mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +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; \
|
||||
uint32_t *address_storage = movem_addresses_; \
|
||||
uint32_t *address_storage = precomputed_addresses_; \
|
||||
mask = next_word_; \
|
||||
int offset = 0;
|
||||
|
||||
@ -596,7 +596,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
}
|
||||
|
||||
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
|
||||
// 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.
|
||||
address_storage[0] = start_address;
|
||||
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;
|
||||
} break;
|
||||
|
||||
case Operation::MOVEMtoRw: {
|
||||
setup_movem(1, movem_reads_steps_);
|
||||
setup_movem(1, movem_read_steps_);
|
||||
write_address_sequence_word(inc_action);
|
||||
|
||||
// MOVEM to R always reads one word too many.
|
||||
address_storage[0] = start_address;
|
||||
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;
|
||||
} break;
|
||||
|
||||
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
|
||||
// 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;
|
||||
|
||||
case Operation::MOVEMtoMw: {
|
||||
setup_movem(1, movem_writes_steps_);
|
||||
setup_movem(1, movem_write_steps_);
|
||||
|
||||
if(mode == 4) {
|
||||
offset = 15;
|
||||
@ -669,6 +669,27 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
#undef inc_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,
|
||||
negative, overflow and carry flags appropriate, and extend.
|
||||
|
@ -377,6 +377,8 @@ struct ProcessorStorageConstructor {
|
||||
RTS, // Maps to an RST.
|
||||
|
||||
MOVEUSP, // Maps a direction and register to a MOVE [to/from] USP.
|
||||
|
||||
TRAP, // Maps to a TRAP.
|
||||
};
|
||||
|
||||
using Operation = ProcessorStorage::Operation;
|
||||
@ -557,6 +559,7 @@ struct ProcessorStorageConstructor {
|
||||
|
||||
{0xfff0, 0x4e60, Operation::MOVEAl, Decoder::MOVEUSP}, // 6-21 (p475)
|
||||
|
||||
{0xfff0, 0x4e40, Operation::TRAP, Decoder::TRAP}, // 4-188 (p292)
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
@ -2424,24 +2427,6 @@ struct ProcessorStorageConstructor {
|
||||
// n np nr n np nw np
|
||||
// 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, d8AnXn): // MOVE.bw (xxx).l, (d8, An, Xn)
|
||||
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) }));
|
||||
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).L
|
||||
@ -2697,6 +2701,14 @@ struct ProcessorStorageConstructor {
|
||||
op(Action::None, seq("nn _ np"));
|
||||
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: {
|
||||
storage_.instructions[instruction].set_source(storage_, ea_mode, ea_register);
|
||||
|
||||
@ -2864,8 +2876,11 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
||||
}
|
||||
movem_reads_pattern += "nr";
|
||||
addresses.push_back(nullptr);
|
||||
const size_t movem_reads_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_read_offset = constructor.assemble_program(movem_reads_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.
|
||||
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_branch_steps_ = &all_bus_steps_[dbcc_condition_false_branch_offset];
|
||||
|
||||
movem_reads_steps_ = &all_bus_steps_[movem_reads_offset];
|
||||
movem_writes_steps_ = &all_bus_steps_[movem_writes_offset];
|
||||
movem_read_steps_ = &all_bus_steps_[movem_read_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.
|
||||
active_step_ = reset_bus_steps_;
|
||||
|
@ -92,6 +92,8 @@ class ProcessorStorage {
|
||||
ORb, ORw, ORl,
|
||||
|
||||
MULU, MULS,
|
||||
|
||||
TRAP,
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -313,8 +315,10 @@ class ProcessorStorage {
|
||||
BusStep *dbcc_condition_false_no_branch_steps_;
|
||||
BusStep *dbcc_condition_false_branch_steps_;
|
||||
|
||||
BusStep *movem_reads_steps_;
|
||||
BusStep *movem_writes_steps_;
|
||||
BusStep *movem_read_steps_;
|
||||
BusStep *movem_write_steps_;
|
||||
|
||||
BusStep *trap_steps_;
|
||||
|
||||
// Current bus step pointer, and outer program pointer.
|
||||
Program *active_program_ = nullptr;
|
||||
@ -329,9 +333,9 @@ class ProcessorStorage {
|
||||
/// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated.
|
||||
void set_is_supervisor(bool);
|
||||
|
||||
// Transient storage for MOVEM.
|
||||
uint32_t movem_addresses_[65];
|
||||
RegisterPair16 movem_spare_value_;
|
||||
// Transient storage for MOVEM, TRAP and others.
|
||||
uint32_t precomputed_addresses_[65];
|
||||
RegisterPair16 throwaway_value_;
|
||||
uint32_t movem_final_address_;
|
||||
|
||||
/*!
|
||||
|
Loading…
Reference in New Issue
Block a user