mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-22 12:33:29 +00:00
Attempts fully to capture 68000 state.
Albeit that it can't be put back yet.
This commit is contained in:
parent
6f16928215
commit
a3d4c7599b
@ -210,7 +210,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
if(bus_interrupt_level_ > interrupt_level_) {
|
||||
pending_interrupt_level_ = bus_interrupt_level_;
|
||||
program_counter_.full += 4; // Don't return to this stop.
|
||||
execution_state_ = ExecutionState::BeginInterrupt;
|
||||
execution_state_ = ExecutionState::WillBeginInterrupt;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -244,7 +244,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
bus_handler_.perform_bus_operation(stop_cycle_, is_supervisor_);
|
||||
continue;
|
||||
|
||||
case ExecutionState::BeginInterrupt:
|
||||
case ExecutionState::WillBeginInterrupt:
|
||||
#ifdef LOG_TRACE
|
||||
// should_log = true;
|
||||
#endif
|
||||
@ -269,7 +269,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
// no instruction was ongoing. Either way, do a standard instruction operation.
|
||||
|
||||
if(pending_interrupt_level_) {
|
||||
execution_state_ = ExecutionState::BeginInterrupt;
|
||||
execution_state_ = ExecutionState::WillBeginInterrupt;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -302,7 +302,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
#ifndef NDEBUG
|
||||
/* Debugging feature: reset the effective addresses and data latches, so that it's
|
||||
more obvious if some of the instructions aren't properly feeding them. */
|
||||
effective_address_[0].full = effective_address_[1].full = source_bus_data_[0].full = destination_bus_data_[0].full = 0x12344321;
|
||||
effective_address_[0].full = effective_address_[1].full = source_bus_data_.full = destination_bus_data_.full = 0x12344321;
|
||||
#endif
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
@ -829,7 +829,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
|
||||
// JMP: copies the source bus data to the program counter.
|
||||
case Operation::RTS:
|
||||
program_counter_ = source_bus_data_[0];
|
||||
program_counter_ = source_bus_data_;
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -879,7 +879,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
break;
|
||||
|
||||
case Operation::PEA:
|
||||
destination_bus_data_[0] = effective_address_[0];
|
||||
destination_bus_data_ = effective_address_[0];
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -1119,30 +1119,30 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
|
||||
case Operation::MOVEPtoMw:
|
||||
// Write pattern is nW+ nw, which should write the low word of the source in big-endian form.
|
||||
destination_bus_data_[0].halves.high.full = source()->halves.low.halves.high;
|
||||
destination_bus_data_[0].halves.low.full = source()->halves.low.halves.low;
|
||||
destination_bus_data_.halves.high.full = source()->halves.low.halves.high;
|
||||
destination_bus_data_.halves.low.full = source()->halves.low.halves.low;
|
||||
break;
|
||||
|
||||
case Operation::MOVEPtoMl:
|
||||
// Write pattern is nW+ nWr+ nw+ nwr, which should write the source in big-endian form.
|
||||
destination_bus_data_[0].halves.high.full = source()->halves.high.halves.high;
|
||||
source_bus_data_[0].halves.high.full = source()->halves.high.halves.low;
|
||||
destination_bus_data_[0].halves.low.full = source()->halves.low.halves.high;
|
||||
source_bus_data_[0].halves.low.full = source()->halves.low.halves.low;
|
||||
destination_bus_data_.halves.high.full = source()->halves.high.halves.high;
|
||||
source_bus_data_.halves.high.full = source()->halves.high.halves.low;
|
||||
destination_bus_data_.halves.low.full = source()->halves.low.halves.high;
|
||||
source_bus_data_.halves.low.full = source()->halves.low.halves.low;
|
||||
break;
|
||||
|
||||
case Operation::MOVEPtoRw:
|
||||
// Read pattern is nRd+ nrd.
|
||||
source()->halves.low.halves.high = destination_bus_data_[0].halves.high.halves.low;
|
||||
source()->halves.low.halves.low = destination_bus_data_[0].halves.low.halves.low;
|
||||
source()->halves.low.halves.high = destination_bus_data_.halves.high.halves.low;
|
||||
source()->halves.low.halves.low = destination_bus_data_.halves.low.halves.low;
|
||||
break;
|
||||
|
||||
case Operation::MOVEPtoRl:
|
||||
// Read pattern is nRd+ nR+ nrd+ nr.
|
||||
source()->halves.high.halves.high = destination_bus_data_[0].halves.high.halves.low;
|
||||
source()->halves.high.halves.low = source_bus_data_[0].halves.high.halves.low;
|
||||
source()->halves.low.halves.high = destination_bus_data_[0].halves.low.halves.low;
|
||||
source()->halves.low.halves.low = source_bus_data_[0].halves.low.halves.low;
|
||||
source()->halves.high.halves.high = destination_bus_data_.halves.high.halves.low;
|
||||
source()->halves.high.halves.low = source_bus_data_.halves.high.halves.low;
|
||||
source()->halves.low.halves.high = destination_bus_data_.halves.low.halves.low;
|
||||
source()->halves.low.halves.low = source_bus_data_.halves.low.halves.low;
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -1448,7 +1448,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
effective_address_[1].full = address_[7].full;
|
||||
|
||||
// The current value of the address register will be pushed.
|
||||
destination_bus_data_[0].full = source()->full;
|
||||
destination_bus_data_.full = source()->full;
|
||||
|
||||
// The address register will then contain the bottom of the stack,
|
||||
// and the stack pointer will be offset.
|
||||
@ -1458,7 +1458,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
|
||||
case Operation::UNLINK:
|
||||
address_[7].full = effective_address_[1].full + 2;
|
||||
destination()->full = destination_bus_data_[0].full;
|
||||
destination()->full = destination_bus_data_.full;
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -1859,10 +1859,10 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
// If this is RTR, patch out the supervisor half of the status register.
|
||||
if(decoded_instruction_.full == 0x4e77) {
|
||||
const auto current_status = status();
|
||||
source_bus_data_[0].halves.low.halves.high =
|
||||
source_bus_data_.halves.low.halves.high =
|
||||
uint8_t(current_status >> 8);
|
||||
}
|
||||
apply_status(source_bus_data_[0].full);
|
||||
apply_status(source_bus_data_.full);
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -1938,9 +1938,9 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
const auto mode = (decoded_instruction_.full >> 3) & 7;
|
||||
// Determine the proper resumption address.
|
||||
switch(mode) {
|
||||
case 2: destination_bus_data_[0].full = program_counter_.full - 2; break; /* (An) */
|
||||
case 2: destination_bus_data_.full = program_counter_.full - 2; break; /* (An) */
|
||||
default:
|
||||
destination_bus_data_[0].full = program_counter_.full; /* Everything other than (An) */
|
||||
destination_bus_data_.full = program_counter_.full; /* Everything other than (An) */
|
||||
break;
|
||||
}
|
||||
address_[7].full -= 4;
|
||||
@ -1948,7 +1948,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
} break;
|
||||
|
||||
case int_type(MicroOp::Action::PrepareBSR):
|
||||
destination_bus_data_[0].full = (decoded_instruction_.full & 0xff) ? program_counter_.full - 2 : program_counter_.full;
|
||||
destination_bus_data_.full = (decoded_instruction_.full & 0xff) ? program_counter_.full - 2 : program_counter_.full;
|
||||
address_[7].full -= 4;
|
||||
effective_address_[1].full = address_[7].full;
|
||||
break;
|
||||
@ -2002,7 +2002,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
}
|
||||
|
||||
// Otherwise, the vector is whatever we were just told it is.
|
||||
effective_address_[0].full = uint32_t(source_bus_data_[0].halves.low.halves.low << 2);
|
||||
effective_address_[0].full = uint32_t(source_bus_data_.halves.low.halves.low << 2);
|
||||
|
||||
// printf("Interrupt vector: %06x\n", effective_address_[0].full);
|
||||
break;
|
||||
@ -2143,19 +2143,19 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
break;
|
||||
|
||||
case int_type(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask:
|
||||
source_bus_data_[0] = prefetch_queue_.halves.low.full;
|
||||
source_bus_data_ = prefetch_queue_.halves.low.full;
|
||||
break;
|
||||
|
||||
case int_type(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::DestinationMask:
|
||||
destination_bus_data_[0] = prefetch_queue_.halves.low.full;
|
||||
destination_bus_data_ = prefetch_queue_.halves.low.full;
|
||||
break;
|
||||
|
||||
case int_type(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask:
|
||||
source_bus_data_[0] = prefetch_queue_.full;
|
||||
source_bus_data_ = prefetch_queue_.full;
|
||||
break;
|
||||
|
||||
case int_type(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::DestinationMask:
|
||||
destination_bus_data_[0] = prefetch_queue_.full;
|
||||
destination_bus_data_ = prefetch_queue_.full;
|
||||
break;
|
||||
|
||||
case int_type(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::SourceMask:
|
||||
|
@ -300,7 +300,7 @@ struct ProcessorStorageConstructor {
|
||||
if(tolower(access_pattern[1]) == 's') {
|
||||
step.microcycle.operation = Microcycle::NewAddress;
|
||||
step.microcycle.address = &storage_.effective_address_[1].full;
|
||||
step.microcycle.value = isupper(access_pattern[1]) ? &storage_.destination_bus_data_[0].halves.high : &storage_.destination_bus_data_[0].halves.low;
|
||||
step.microcycle.value = isupper(access_pattern[1]) ? &storage_.destination_bus_data_.halves.high : &storage_.destination_bus_data_.halves.low;
|
||||
steps.push_back(step);
|
||||
|
||||
step.microcycle.operation = Microcycle::SameAddress | Microcycle::SelectWord;
|
||||
@ -312,7 +312,7 @@ struct ProcessorStorageConstructor {
|
||||
|
||||
// A stack read.
|
||||
if(tolower(access_pattern[1]) == 'u') {
|
||||
RegisterPair32 *const scratch_data = &storage_.source_bus_data_[0];
|
||||
RegisterPair32 *const scratch_data = &storage_.source_bus_data_;
|
||||
|
||||
step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read;
|
||||
step.microcycle.address = &storage_.effective_address_[0].full;
|
||||
@ -350,7 +350,7 @@ struct ProcessorStorageConstructor {
|
||||
) {
|
||||
const bool is_read = tolower(access_pattern[1]) == 'r';
|
||||
const bool use_source_storage = tolower(end_of_pattern[-1]) == 'r';
|
||||
RegisterPair32 *const scratch_data = use_source_storage ? &storage_.source_bus_data_[0] : &storage_.destination_bus_data_[0];
|
||||
RegisterPair32 *const scratch_data = use_source_storage ? &storage_.source_bus_data_ : &storage_.destination_bus_data_;
|
||||
|
||||
assert(address_iterator != addresses.end());
|
||||
|
||||
@ -377,7 +377,7 @@ struct ProcessorStorageConstructor {
|
||||
if(token_length == 3) {
|
||||
// The completing part of a TAS.
|
||||
if(access_pattern[0] == 't' && access_pattern[1] == 'a' && access_pattern[2] == 's') {
|
||||
RegisterPair32 *const scratch_data = &storage_.destination_bus_data_[0];
|
||||
RegisterPair32 *const scratch_data = &storage_.destination_bus_data_;
|
||||
|
||||
assert(address_iterator != addresses.end());
|
||||
|
||||
@ -399,7 +399,7 @@ struct ProcessorStorageConstructor {
|
||||
if(access_pattern[0] == 'i' && access_pattern[1] == 'n' && access_pattern[2] == 't') {
|
||||
step.microcycle.operation = Microcycle::InterruptAcknowledge | Microcycle::NewAddress;
|
||||
step.microcycle.address = &storage_.effective_address_[0].full; // The selected interrupt should be in bits 1–3; but 0 should be set.
|
||||
step.microcycle.value = &storage_.source_bus_data_[0].halves.low;
|
||||
step.microcycle.value = &storage_.source_bus_data_.halves.low;
|
||||
steps.push_back(step);
|
||||
|
||||
step.microcycle.operation = Microcycle::InterruptAcknowledge | Microcycle::SameAddress | Microcycle::SelectByte;
|
||||
@ -3250,20 +3250,20 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
||||
//
|
||||
// Order of output is: PC.l, SR, PC.h.
|
||||
trap_steps_ = &all_bus_steps_[trap_offset];
|
||||
constructor.replace_write_values(trap_steps_, { &program_counter_.halves.low, &destination_bus_data_[0].halves.low, &program_counter_.halves.high });
|
||||
constructor.replace_write_values(trap_steps_, { &program_counter_.halves.low, &destination_bus_data_.halves.low, &program_counter_.halves.high });
|
||||
|
||||
// Fill in the same order of writes for the interrupt micro-ops, though it divides the work differently.
|
||||
constructor.replace_write_values(interrupt_micro_ops_, { &program_counter_.halves.low, &destination_bus_data_[0].halves.low, &program_counter_.halves.high });
|
||||
constructor.replace_write_values(interrupt_micro_ops_, { &program_counter_.halves.low, &destination_bus_data_.halves.low, &program_counter_.halves.high });
|
||||
|
||||
// Link the bus error exception steps and fill in the proper sources.
|
||||
bus_error_steps_ = &all_bus_steps_[bus_error_offset];
|
||||
constructor.replace_write_values(bus_error_steps_, {
|
||||
&program_counter_.halves.low,
|
||||
&destination_bus_data_[0].halves.low,
|
||||
&destination_bus_data_.halves.low,
|
||||
&program_counter_.halves.high,
|
||||
&decoded_instruction_,
|
||||
&effective_address_[1].halves.low,
|
||||
&destination_bus_data_[0].halves.high,
|
||||
&destination_bus_data_.halves.high,
|
||||
&effective_address_[1].halves.high
|
||||
});
|
||||
|
||||
|
@ -38,7 +38,7 @@ class ProcessorStorage {
|
||||
Halted,
|
||||
|
||||
/// Signals a transition from some other straight directly to cueing up an interrupt.
|
||||
BeginInterrupt,
|
||||
WillBeginInterrupt,
|
||||
} execution_state_ = ExecutionState::Executing;
|
||||
Microcycle dtack_cycle_;
|
||||
Microcycle stop_cycle_;
|
||||
@ -75,8 +75,8 @@ class ProcessorStorage {
|
||||
// Generic sources and targets for memory operations;
|
||||
// by convention: [0] = source, [1] = destination.
|
||||
RegisterPair32 effective_address_[2];
|
||||
RegisterPair32 source_bus_data_[1];
|
||||
RegisterPair32 destination_bus_data_[1];
|
||||
RegisterPair32 source_bus_data_;
|
||||
RegisterPair32 destination_bus_data_;
|
||||
|
||||
HalfCycles half_cycles_left_to_run_;
|
||||
HalfCycles e_clock_phase_;
|
||||
@ -394,18 +394,18 @@ class ProcessorStorage {
|
||||
void set_source(ProcessorStorage &storage, int mode, int reg) {
|
||||
set_source_address(storage, reg);
|
||||
switch(mode) {
|
||||
case 0: set_source(storage, &storage.data_[reg]); break;
|
||||
case 1: set_source(storage, &storage.address_[reg]); break;
|
||||
default: set_source(storage, &storage.source_bus_data_[0]); break;
|
||||
case 0: set_source(storage, &storage.data_[reg]); break;
|
||||
case 1: set_source(storage, &storage.address_[reg]); break;
|
||||
default: set_source(storage, &storage.source_bus_data_); break;
|
||||
}
|
||||
}
|
||||
|
||||
void set_destination(ProcessorStorage &storage, int mode, int reg) {
|
||||
set_destination_address(storage, reg);
|
||||
switch(mode) {
|
||||
case 0: set_destination(storage, &storage.data_[reg]); break;
|
||||
case 1: set_destination(storage, &storage.address_[reg]); break;
|
||||
default: set_destination(storage, &storage.destination_bus_data_[0]); break;
|
||||
case 0: set_destination(storage, &storage.data_[reg]); break;
|
||||
case 1: set_destination(storage, &storage.address_[reg]); break;
|
||||
default: set_destination(storage, &storage.destination_bus_data_); break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -438,13 +438,15 @@ class ProcessorStorage {
|
||||
BusStep *movem_read_steps_;
|
||||
BusStep *movem_write_steps_;
|
||||
|
||||
// These two are dynamically modified depending on the particular
|
||||
// TRAP and bus error.
|
||||
BusStep *trap_steps_;
|
||||
BusStep *bus_error_steps_;
|
||||
|
||||
// Current bus step pointer, and outer program pointer.
|
||||
Program *active_program_ = nullptr;
|
||||
MicroOp *active_micro_op_ = nullptr;
|
||||
BusStep *active_step_ = nullptr;
|
||||
const Program *active_program_ = nullptr;
|
||||
const MicroOp *active_micro_op_ = nullptr;
|
||||
const BusStep *active_step_ = nullptr;
|
||||
RegisterPair16 decoded_instruction_ = 0;
|
||||
uint16_t next_word_ = 0;
|
||||
|
||||
@ -455,9 +457,9 @@ class ProcessorStorage {
|
||||
void set_is_supervisor(bool);
|
||||
|
||||
// Transient storage for MOVEM, TRAP and others.
|
||||
uint32_t precomputed_addresses_[65];
|
||||
RegisterPair16 throwaway_value_;
|
||||
uint32_t movem_final_address_;
|
||||
uint32_t precomputed_addresses_[65]; // This is a big chunk of rarely-used storage. It's placed last deliberately.
|
||||
|
||||
/*!
|
||||
Evaluates the conditional described by @c code and returns @c true or @c false to
|
||||
@ -496,7 +498,7 @@ class ProcessorStorage {
|
||||
*/
|
||||
forceinline void populate_trap_steps(uint32_t vector, uint16_t status) {
|
||||
// Fill in the status word value.
|
||||
destination_bus_data_[0].full = status;
|
||||
destination_bus_data_.full = status;
|
||||
|
||||
// Switch to supervisor mode, disable the trace bit.
|
||||
set_is_supervisor(true);
|
||||
@ -507,7 +509,7 @@ class ProcessorStorage {
|
||||
|
||||
// Schedule the proper stack activity.
|
||||
precomputed_addresses_[0] = address_[7].full - 2; // PC.l
|
||||
precomputed_addresses_[1] = address_[7].full - 6; // status word (in destination_bus_data_[0])
|
||||
precomputed_addresses_[1] = address_[7].full - 6; // status word (in destination_bus_data_)
|
||||
precomputed_addresses_[2] = address_[7].full - 4; // PC.h
|
||||
address_[7].full -= 6;
|
||||
|
||||
@ -517,8 +519,8 @@ class ProcessorStorage {
|
||||
|
||||
forceinline void populate_bus_error_steps(uint32_t vector, uint16_t status, uint16_t bus_status, RegisterPair32 faulting_address) {
|
||||
// Fill in the status word value.
|
||||
destination_bus_data_[0].halves.low.full = status;
|
||||
destination_bus_data_[0].halves.high.full = bus_status;
|
||||
destination_bus_data_.halves.low.full = status;
|
||||
destination_bus_data_.halves.high.full = bus_status;
|
||||
effective_address_[1] = faulting_address;
|
||||
|
||||
// Switch to supervisor mode, disable the trace bit.
|
||||
|
@ -33,22 +33,133 @@ State::State(const ProcessorBase &src): State() {
|
||||
inputs.bus_grant = false; // TODO (within the 68000).
|
||||
inputs.halt = src.halt_;
|
||||
|
||||
// TODO:
|
||||
// execution_state_
|
||||
// active_[program_/micro_op_/step_]
|
||||
|
||||
// Execution state.
|
||||
execution_state.e_clock_phase = src.e_clock_phase_.as<uint8_t>();
|
||||
execution_state.effective_address[0] = src.effective_address_[0].full;
|
||||
execution_state.effective_address[1] = src.effective_address_[1].full;
|
||||
execution_state.source_data = src.source_bus_data_[0].full;
|
||||
execution_state.destination_data = src.destination_bus_data_[0].full;
|
||||
execution_state.source_data = src.source_bus_data_.full;
|
||||
execution_state.destination_data = src.destination_bus_data_.full;
|
||||
execution_state.last_trace_flag = src.last_trace_flag_;
|
||||
execution_state.next_word = src.next_word_;
|
||||
execution_state.dbcc_false_address = src.dbcc_false_address_;
|
||||
execution_state.is_starting_interrupt = src.is_starting_interrupt_;
|
||||
execution_state.pending_interrupt_level = uint8_t(src.pending_interrupt_level_);
|
||||
execution_state.accepted_interrupt_level = uint8_t(src.accepted_interrupt_level_);
|
||||
execution_state.movem_final_address = src.movem_final_address_;
|
||||
|
||||
static_assert(sizeof(execution_state.source_addresses) == sizeof(src.precomputed_addresses_));
|
||||
memcpy(&execution_state.source_addresses, &src.precomputed_addresses_, sizeof(src.precomputed_addresses_));
|
||||
|
||||
// This is collapsed to a Boolean; if there is an active program then it's the
|
||||
// one implied by the current instruction.
|
||||
execution_state.active_program = src.active_program_;
|
||||
|
||||
// Slightly dodgy assumption here: the Phase enum will always exactly track
|
||||
// the 68000's ExecutionState enum.
|
||||
execution_state.phase = ExecutionState::Phase(src.execution_state_);
|
||||
|
||||
auto contained_by = [](const auto *source, const auto *reference) -> bool {
|
||||
while(true) {
|
||||
if(source == reference) return true;
|
||||
if(source->is_terminal()) return false;
|
||||
++source;
|
||||
}
|
||||
};
|
||||
|
||||
// Store enough information to relocate the MicroOp.
|
||||
const ProcessorBase::MicroOp *micro_op_base = nullptr;
|
||||
if(src.active_program_) {
|
||||
micro_op_base = &src.all_micro_ops_[src.instructions[src.decoded_instruction_.full].micro_operations];
|
||||
assert(contained_by(micro_op_base, src.active_micro_op_));
|
||||
execution_state.micro_op_source = ExecutionState::MicroOpSource::ActiveProgram;
|
||||
} else {
|
||||
if(contained_by(src.long_exception_micro_ops_, src.active_micro_op_)) {
|
||||
execution_state.micro_op_source = ExecutionState::MicroOpSource::LongException;
|
||||
micro_op_base = src.long_exception_micro_ops_;
|
||||
} else if(contained_by(src.short_exception_micro_ops_, src.active_micro_op_)) {
|
||||
execution_state.micro_op_source = ExecutionState::MicroOpSource::ShortException;
|
||||
micro_op_base = src.short_exception_micro_ops_;
|
||||
} else if(contained_by(src.interrupt_micro_ops_, src.active_micro_op_)) {
|
||||
execution_state.micro_op_source = ExecutionState::MicroOpSource::Interrupt;
|
||||
micro_op_base = src.interrupt_micro_ops_;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
execution_state.micro_op = uint8_t(src.active_micro_op_ - micro_op_base);
|
||||
|
||||
// Encode the BusStep.
|
||||
struct BusStepOption {
|
||||
const ProcessorBase::BusStep *const base;
|
||||
const ExecutionState::BusStepSource source;
|
||||
};
|
||||
BusStepOption bus_step_options[] = {
|
||||
{
|
||||
src.reset_bus_steps_,
|
||||
ExecutionState::BusStepSource::Reset
|
||||
},
|
||||
{
|
||||
src.branch_taken_bus_steps_,
|
||||
ExecutionState::BusStepSource::BranchTaken
|
||||
},
|
||||
{
|
||||
src.branch_byte_not_taken_bus_steps_,
|
||||
ExecutionState::BusStepSource::BranchByteNotTaken
|
||||
},
|
||||
{
|
||||
src.branch_word_not_taken_bus_steps_,
|
||||
ExecutionState::BusStepSource::BranchWordNotTaken
|
||||
},
|
||||
{
|
||||
src.bsr_bus_steps_,
|
||||
ExecutionState::BusStepSource::BSR
|
||||
},
|
||||
{
|
||||
src.dbcc_condition_true_steps_,
|
||||
ExecutionState::BusStepSource::DBccConditionTrue
|
||||
},
|
||||
{
|
||||
src.dbcc_condition_false_no_branch_steps_,
|
||||
ExecutionState::BusStepSource::DBccConditionFalseNoBranch
|
||||
},
|
||||
{
|
||||
src.dbcc_condition_false_branch_steps_,
|
||||
ExecutionState::BusStepSource::DBccConditionFalseBranch
|
||||
},
|
||||
{
|
||||
src.movem_read_steps_,
|
||||
ExecutionState::BusStepSource::MovemRead
|
||||
},
|
||||
{
|
||||
src.movem_write_steps_,
|
||||
ExecutionState::BusStepSource::MovemWrite
|
||||
},
|
||||
{
|
||||
src.trap_steps_,
|
||||
ExecutionState::BusStepSource::Trap
|
||||
},
|
||||
{
|
||||
src.bus_error_steps_,
|
||||
ExecutionState::BusStepSource::BusError
|
||||
},
|
||||
{
|
||||
&src.all_bus_steps_[src.active_micro_op_->bus_program],
|
||||
ExecutionState::BusStepSource::FollowMicroOp
|
||||
},
|
||||
{nullptr}
|
||||
};
|
||||
const BusStepOption *bus_step_option = bus_step_options;
|
||||
const ProcessorBase::BusStep *bus_step_base = nullptr;
|
||||
while(bus_step_option->base) {
|
||||
if(contained_by(bus_step_option->base, src.active_step_)) {
|
||||
bus_step_base = bus_step_option->base;
|
||||
execution_state.bus_step_source = bus_step_option->source;
|
||||
break;
|
||||
}
|
||||
++bus_step_option;
|
||||
}
|
||||
assert(bus_step_base);
|
||||
execution_state.bus_step = uint8_t(src.active_step_ - bus_step_base);
|
||||
}
|
||||
|
||||
void State::apply(ProcessorBase &target) {
|
||||
@ -100,5 +211,19 @@ State::ExecutionState::ExecutionState() {
|
||||
DeclareField(is_starting_interrupt);
|
||||
DeclareField(pending_interrupt_level);
|
||||
DeclareField(accepted_interrupt_level);
|
||||
DeclareField(active_program);
|
||||
DeclareField(movem_final_address);
|
||||
DeclareField(source_addresses);
|
||||
|
||||
AnnounceEnum(Phase);
|
||||
DeclareField(phase);
|
||||
|
||||
AnnounceEnum(MicroOpSource);
|
||||
DeclareField(micro_op_source);
|
||||
DeclareField(micro_op);
|
||||
|
||||
AnnounceEnum(BusStepSource);
|
||||
DeclareField(bus_step_source);
|
||||
DeclareField(bus_step);
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,49 @@ struct State: public Reflection::StructImpl<State> {
|
||||
uint8_t pending_interrupt_level;
|
||||
uint8_t accepted_interrupt_level;
|
||||
|
||||
// This is a reflective do-over of the ExecutionState enum within
|
||||
// MC68000Storage; I've yet to decide how happy I am with that
|
||||
// as an approach.
|
||||
ReflectableEnum(Phase,
|
||||
Executing,
|
||||
WaitingForDTack,
|
||||
Stopped,
|
||||
Halted,
|
||||
WillBeginInterrupt
|
||||
);
|
||||
Phase phase;
|
||||
|
||||
bool active_program;
|
||||
uint32_t movem_final_address;
|
||||
uint32_t source_addresses[65];
|
||||
|
||||
ReflectableEnum(MicroOpSource,
|
||||
ActiveProgram,
|
||||
LongException,
|
||||
ShortException,
|
||||
Interrupt
|
||||
);
|
||||
MicroOpSource micro_op_source;
|
||||
uint8_t micro_op;
|
||||
|
||||
ReflectableEnum(BusStepSource,
|
||||
FollowMicroOp,
|
||||
BusError,
|
||||
Trap,
|
||||
Reset,
|
||||
BranchTaken,
|
||||
BranchByteNotTaken,
|
||||
BranchWordNotTaken,
|
||||
BSR,
|
||||
DBccConditionTrue,
|
||||
DBccConditionFalseNoBranch,
|
||||
DBccConditionFalseBranch,
|
||||
MovemRead,
|
||||
MovemWrite,
|
||||
);
|
||||
BusStepSource bus_step_source;
|
||||
uint8_t bus_step;
|
||||
|
||||
ExecutionState();
|
||||
} execution_state;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user