mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-18 16:30:29 +00:00
Takes a run at TRAP.
This commit is contained in:
parent
b8a0f4e831
commit
e49b257e94
@ -548,7 +548,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
|||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
auto step = bus_program; \
|
auto step = bus_program; \
|
||||||
uint32_t *address_storage = movem_addresses_; \
|
uint32_t *address_storage = precomputed_addresses_; \
|
||||||
mask = next_word_; \
|
mask = next_word_; \
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
@ -596,7 +596,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Operation::MOVEMtoRl: {
|
case Operation::MOVEMtoRl: {
|
||||||
setup_movem(2, movem_reads_steps_);
|
setup_movem(2, movem_read_steps_);
|
||||||
|
|
||||||
// Everything for move to registers is based on an incrementing
|
// Everything for move to registers is based on an incrementing
|
||||||
// address; per M68000PRM:
|
// address; per M68000PRM:
|
||||||
@ -613,23 +613,23 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
|||||||
// MOVEM to R always reads one word too many.
|
// MOVEM to R always reads one word too many.
|
||||||
address_storage[0] = start_address;
|
address_storage[0] = start_address;
|
||||||
step[0].microcycle.address = step[1].microcycle.address = address_storage;
|
step[0].microcycle.address = step[1].microcycle.address = address_storage;
|
||||||
step[0].microcycle.value = step[1].microcycle.value = &movem_spare_value_;
|
step[0].microcycle.value = step[1].microcycle.value = &throwaway_value_;
|
||||||
movem_final_address_ = start_address;
|
movem_final_address_ = start_address;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Operation::MOVEMtoRw: {
|
case Operation::MOVEMtoRw: {
|
||||||
setup_movem(1, movem_reads_steps_);
|
setup_movem(1, movem_read_steps_);
|
||||||
write_address_sequence_word(inc_action);
|
write_address_sequence_word(inc_action);
|
||||||
|
|
||||||
// MOVEM to R always reads one word too many.
|
// MOVEM to R always reads one word too many.
|
||||||
address_storage[0] = start_address;
|
address_storage[0] = start_address;
|
||||||
step[0].microcycle.address = step[1].microcycle.address = address_storage;
|
step[0].microcycle.address = step[1].microcycle.address = address_storage;
|
||||||
step[0].microcycle.value = step[1].microcycle.value = &movem_spare_value_;
|
step[0].microcycle.value = step[1].microcycle.value = &throwaway_value_;
|
||||||
movem_final_address_ = start_address;
|
movem_final_address_ = start_address;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Operation::MOVEMtoMl: {
|
case Operation::MOVEMtoMl: {
|
||||||
setup_movem(2, movem_writes_steps_);
|
setup_movem(2, movem_write_steps_);
|
||||||
|
|
||||||
// MOVEM to M counts downwards and enumerates the registers in reverse order
|
// MOVEM to M counts downwards and enumerates the registers in reverse order
|
||||||
// if subject to the predecrementing mode; otherwise it counts upwards and
|
// if subject to the predecrementing mode; otherwise it counts upwards and
|
||||||
@ -652,7 +652,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Operation::MOVEMtoMw: {
|
case Operation::MOVEMtoMw: {
|
||||||
setup_movem(1, movem_writes_steps_);
|
setup_movem(1, movem_write_steps_);
|
||||||
|
|
||||||
if(mode == 4) {
|
if(mode == 4) {
|
||||||
offset = 15;
|
offset = 15;
|
||||||
@ -669,6 +669,27 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
|||||||
#undef inc_action
|
#undef inc_action
|
||||||
#undef dec_action
|
#undef dec_action
|
||||||
|
|
||||||
|
// TRAP, which is a nicer form of ILLEGAL.
|
||||||
|
case Operation::TRAP: {
|
||||||
|
// Select the trap steps as next.
|
||||||
|
bus_program = trap_steps_;
|
||||||
|
|
||||||
|
// Fill in the status word value.
|
||||||
|
destination_bus_data_[0].full = get_status();
|
||||||
|
|
||||||
|
// Switch to supervisor mode.
|
||||||
|
set_is_supervisor(true);
|
||||||
|
|
||||||
|
// Pick a vector.
|
||||||
|
effective_address_[0].full = ((decoded_instruction_ & 15) + 32) << 2;
|
||||||
|
|
||||||
|
// Schedule the proper stack activity.
|
||||||
|
precomputed_addresses_[0] = address_[7].full - 2;
|
||||||
|
precomputed_addresses_[1] = address_[7].full - 6;
|
||||||
|
precomputed_addresses_[2] = address_[7].full - 4;
|
||||||
|
address_[7].full -= 6;
|
||||||
|
} break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NEGs: negatives the destination, setting the zero,
|
NEGs: negatives the destination, setting the zero,
|
||||||
negative, overflow and carry flags appropriate, and extend.
|
negative, overflow and carry flags appropriate, and extend.
|
||||||
|
@ -377,6 +377,8 @@ struct ProcessorStorageConstructor {
|
|||||||
RTS, // Maps to an RST.
|
RTS, // Maps to an RST.
|
||||||
|
|
||||||
MOVEUSP, // Maps a direction and register to a MOVE [to/from] USP.
|
MOVEUSP, // Maps a direction and register to a MOVE [to/from] USP.
|
||||||
|
|
||||||
|
TRAP, // Maps to a TRAP.
|
||||||
};
|
};
|
||||||
|
|
||||||
using Operation = ProcessorStorage::Operation;
|
using Operation = ProcessorStorage::Operation;
|
||||||
@ -557,6 +559,7 @@ struct ProcessorStorageConstructor {
|
|||||||
|
|
||||||
{0xfff0, 0x4e60, Operation::MOVEAl, Decoder::MOVEUSP}, // 6-21 (p475)
|
{0xfff0, 0x4e60, Operation::MOVEAl, Decoder::MOVEUSP}, // 6-21 (p475)
|
||||||
|
|
||||||
|
{0xfff0, 0x4e40, Operation::TRAP, Decoder::TRAP}, // 4-188 (p292)
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@ -2424,24 +2427,6 @@ struct ProcessorStorageConstructor {
|
|||||||
// n np nr n np nw np
|
// n np nr n np nw np
|
||||||
// continue;
|
// continue;
|
||||||
|
|
||||||
// case 0x1005: // MOVE (xxx).W, (d16, An)
|
|
||||||
// np nr np nw np
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
// case 0x1006: // MOVE (xxx).W, (d8, An, Xn)
|
|
||||||
// np nr n np nw np
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
case bw2(Imm, d16An): // MOVE.bw #, (d16, An)
|
|
||||||
case bw2(Imm, d8AnXn): // MOVE.bw #, (d8, An, Xn)
|
|
||||||
case bw2(Imm, d16PC): // MOVE.bw #, (d16, PC)
|
|
||||||
case bw2(Imm, d8PCXn): // MOVE.bw #, (d8, PC, Xn)
|
|
||||||
storage_.instructions[instruction].source = &storage_.destination_bus_data_[0];
|
|
||||||
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::DestinationMask, seq("np"));
|
|
||||||
op(calc_action_for_mode(combined_destination_mode) | MicroOp::DestinationMask, seq(pseq("np nw np", combined_destination_mode), { ea(1) }, !is_byte_access ));
|
|
||||||
op(is_byte_access ? Action::SetMoveFlagsb : Action::SetMoveFlagsl);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case bw2(XXXl, d16An): // MOVE.bw (xxx).l, (d16, An)
|
case bw2(XXXl, d16An): // MOVE.bw (xxx).l, (d16, An)
|
||||||
case bw2(XXXl, d8AnXn): // MOVE.bw (xxx).l, (d8, An, Xn)
|
case bw2(XXXl, d8AnXn): // MOVE.bw (xxx).l, (d8, An, Xn)
|
||||||
case bw2(XXXl, d16PC): // MOVE.bw (xxx).l, (d16, PC)
|
case bw2(XXXl, d16PC): // MOVE.bw (xxx).l, (d16, PC)
|
||||||
@ -2470,6 +2455,25 @@ struct ProcessorStorageConstructor {
|
|||||||
op(Action::PerformOperation, seq(pseq("np nW+ nw np", combined_destination_mode), { ea(1), ea(1) }));
|
op(Action::PerformOperation, seq(pseq("np nW+ nw np", combined_destination_mode), { ea(1), ea(1) }));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case bw2(Imm, d16An): // MOVE.bw #, (d16, An)
|
||||||
|
case bw2(Imm, d16PC): // MOVE.bw #, (d16, PC)
|
||||||
|
case bw2(Imm, d8PCXn): // MOVE.bw #, (d8, PC, Xn)
|
||||||
|
case bw2(Imm, d8AnXn): // MOVE.bw #, (d8, An, Xn)
|
||||||
|
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
|
||||||
|
op(calc_action_for_mode(combined_destination_mode) | MicroOp::DestinationMask, seq(pseq("np", combined_destination_mode)));
|
||||||
|
op(Action::PerformOperation, seq("nw np", { ea(1) }, !is_byte_access));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case l2(Imm, d16An): // MOVE.l #, (d16, An)
|
||||||
|
case l2(Imm, d16PC): // MOVE.l #, (d16, PC)
|
||||||
|
case l2(Imm, d8PCXn): // MOVE.l #, (d8, PC, Xn)
|
||||||
|
case l2(Imm, d8AnXn): // MOVE.l #, (d8, An, Xn)
|
||||||
|
op(Action::None, seq("np"));
|
||||||
|
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
|
||||||
|
op(calc_action_for_mode(combined_destination_mode) | MicroOp::DestinationMask, seq(pseq("np", combined_destination_mode)));
|
||||||
|
op(Action::PerformOperation, seq("nW+ nw np", { ea(1), ea(1) }));
|
||||||
|
break;
|
||||||
|
|
||||||
//
|
//
|
||||||
// MOVE <ea>, (xxx).W
|
// MOVE <ea>, (xxx).W
|
||||||
// MOVE <ea>, (xxx).L
|
// MOVE <ea>, (xxx).L
|
||||||
@ -2697,6 +2701,14 @@ struct ProcessorStorageConstructor {
|
|||||||
op(Action::None, seq("nn _ np"));
|
op(Action::None, seq("nn _ np"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Decoder::TRAP: {
|
||||||
|
// TRAP involves some oddly-sequenced stack writes, so is calculated
|
||||||
|
// at runtime; also the same sequence is used for illegal instructions.
|
||||||
|
// So the entirety is scheduled at runtime.
|
||||||
|
op(Action::PerformOperation);
|
||||||
|
op();
|
||||||
|
} break;
|
||||||
|
|
||||||
case Decoder::TST: {
|
case Decoder::TST: {
|
||||||
storage_.instructions[instruction].set_source(storage_, ea_mode, ea_register);
|
storage_.instructions[instruction].set_source(storage_, ea_mode, ea_register);
|
||||||
|
|
||||||
@ -2864,8 +2876,11 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
|||||||
}
|
}
|
||||||
movem_reads_pattern += "nr";
|
movem_reads_pattern += "nr";
|
||||||
addresses.push_back(nullptr);
|
addresses.push_back(nullptr);
|
||||||
const size_t movem_reads_offset = constructor.assemble_program(movem_reads_pattern, addresses);
|
const size_t movem_read_offset = constructor.assemble_program(movem_reads_pattern, addresses);
|
||||||
const size_t movem_writes_offset = constructor.assemble_program(movem_writes_pattern, addresses);
|
const size_t movem_write_offset = constructor.assemble_program(movem_writes_pattern, addresses);
|
||||||
|
|
||||||
|
// Target addresses and values will be filled in by TRAP/illegal too.
|
||||||
|
const size_t trap_offset = constructor.assemble_program("nn nw nw nW nV nv np np", { &precomputed_addresses_[0], &precomputed_addresses_[1], &precomputed_addresses_[2] });
|
||||||
|
|
||||||
// Install operations.
|
// Install operations.
|
||||||
constructor.install_instructions();
|
constructor.install_instructions();
|
||||||
@ -2882,8 +2897,17 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
|||||||
dbcc_condition_false_no_branch_steps_ = &all_bus_steps_[dbcc_condition_false_no_branch_offset];
|
dbcc_condition_false_no_branch_steps_ = &all_bus_steps_[dbcc_condition_false_no_branch_offset];
|
||||||
dbcc_condition_false_branch_steps_ = &all_bus_steps_[dbcc_condition_false_branch_offset];
|
dbcc_condition_false_branch_steps_ = &all_bus_steps_[dbcc_condition_false_branch_offset];
|
||||||
|
|
||||||
movem_reads_steps_ = &all_bus_steps_[movem_reads_offset];
|
movem_read_steps_ = &all_bus_steps_[movem_read_offset];
|
||||||
movem_writes_steps_ = &all_bus_steps_[movem_writes_offset];
|
movem_write_steps_ = &all_bus_steps_[movem_write_offset];
|
||||||
|
|
||||||
|
// Link the trap steps but also fill in the program counter as the source
|
||||||
|
// for its parts, and use the computed addresses.
|
||||||
|
//
|
||||||
|
// Order of output is: PC.l, SR, PC.h.
|
||||||
|
trap_steps_ = &all_bus_steps_[trap_offset];
|
||||||
|
trap_steps_[1].microcycle.value = trap_steps_[2].microcycle.value = &program_counter_.halves.low;
|
||||||
|
trap_steps_[3].microcycle.value = trap_steps_[4].microcycle.value = &destination_bus_data_[0].halves.low;
|
||||||
|
trap_steps_[5].microcycle.value = trap_steps_[6].microcycle.value = &program_counter_.halves.high;
|
||||||
|
|
||||||
// Set initial state. Largely TODO.
|
// Set initial state. Largely TODO.
|
||||||
active_step_ = reset_bus_steps_;
|
active_step_ = reset_bus_steps_;
|
||||||
|
@ -92,6 +92,8 @@ class ProcessorStorage {
|
|||||||
ORb, ORw, ORl,
|
ORb, ORw, ORl,
|
||||||
|
|
||||||
MULU, MULS,
|
MULU, MULS,
|
||||||
|
|
||||||
|
TRAP,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -313,8 +315,10 @@ class ProcessorStorage {
|
|||||||
BusStep *dbcc_condition_false_no_branch_steps_;
|
BusStep *dbcc_condition_false_no_branch_steps_;
|
||||||
BusStep *dbcc_condition_false_branch_steps_;
|
BusStep *dbcc_condition_false_branch_steps_;
|
||||||
|
|
||||||
BusStep *movem_reads_steps_;
|
BusStep *movem_read_steps_;
|
||||||
BusStep *movem_writes_steps_;
|
BusStep *movem_write_steps_;
|
||||||
|
|
||||||
|
BusStep *trap_steps_;
|
||||||
|
|
||||||
// Current bus step pointer, and outer program pointer.
|
// Current bus step pointer, and outer program pointer.
|
||||||
Program *active_program_ = nullptr;
|
Program *active_program_ = nullptr;
|
||||||
@ -329,9 +333,9 @@ class ProcessorStorage {
|
|||||||
/// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated.
|
/// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated.
|
||||||
void set_is_supervisor(bool);
|
void set_is_supervisor(bool);
|
||||||
|
|
||||||
// Transient storage for MOVEM.
|
// Transient storage for MOVEM, TRAP and others.
|
||||||
uint32_t movem_addresses_[65];
|
uint32_t precomputed_addresses_[65];
|
||||||
RegisterPair16 movem_spare_value_;
|
RegisterPair16 throwaway_value_;
|
||||||
uint32_t movem_final_address_;
|
uint32_t movem_final_address_;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user