mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-23 20:29:42 +00:00
Implement STOPpages, waits for DTack, and bus and address error exceptions.
This commit is contained in:
parent
e430f2658f
commit
31bb770fdd
@ -52,8 +52,6 @@ struct Microcycle {
|
||||
*/
|
||||
static const int TypeMask = 3;
|
||||
|
||||
/// A NewAddress cycle is one in which the address strobe is initially low but becomes high;
|
||||
/// this correlates to states 0 to 5 of a standard read/write cycle.
|
||||
static const int Idle = 0;
|
||||
|
||||
/// A NewAddress cycle is one in which the address strobe is initially low but becomes high;
|
||||
|
@ -36,29 +36,79 @@
|
||||
trace_flag_ = (x) & 0x8000; \
|
||||
set_is_supervisor(!!(((x) >> 13) & 1));
|
||||
|
||||
#define get_bus_code() \
|
||||
((active_step_->microcycle.operation & Microcycle::IsProgram) ? 0x02 : 0x01) | \
|
||||
(is_supervisor_ << 2) | \
|
||||
(active_program_ ? 0x08 : 0) | \
|
||||
((active_step_->microcycle.operation & Microcycle::Read) ? 0x10 : 0)
|
||||
|
||||
template <class T, bool dtack_is_implicit, bool signal_will_perform> void Processor<T, dtack_is_implicit, signal_will_perform>::run_for(HalfCycles duration) {
|
||||
HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
|
||||
while(remaining_duration > HalfCycles(0)) {
|
||||
/*
|
||||
PERFORM THE CURRENT BUS STEP'S MICROCYCLE.
|
||||
*/
|
||||
// Check for DTack if this isn't being treated implicitly.
|
||||
if(active_step_->microcycle.data_select_active()) {
|
||||
if(!dtack_is_implicit) {
|
||||
if(active_step_->microcycle.data_select_active() && !dtack_) {
|
||||
// TODO: perform wait state.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch(execution_state_) {
|
||||
default:
|
||||
break;
|
||||
|
||||
// TODO: synchronous bus.
|
||||
} else {
|
||||
// TODO: check for bus error (but here, or when checking for DTACK?)
|
||||
// if(active_step_->microcycle.operation & MicroCycle::NewAddress) {
|
||||
// }
|
||||
case ExecutionState::Stopped:
|
||||
// If an interrupt (TODO: or reset) has finally arrived that will be serviced,
|
||||
// exit the STOP.
|
||||
if(bus_interrupt_level_ >= interrupt_level_) {
|
||||
execution_state_ = ExecutionState::Executing;
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise continue being stopped.
|
||||
remaining_duration -=
|
||||
stop_cycle_.length +
|
||||
bus_handler_.perform_bus_operation(stop_cycle_, is_supervisor_);
|
||||
continue;
|
||||
|
||||
case ExecutionState::WaitingForDTack:
|
||||
// If DTack or bus error has been signalled, stop waiting.
|
||||
if(dtack_ || bus_error_) {
|
||||
execution_state_ = ExecutionState::Executing;
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, signal another cycle of wait.
|
||||
remaining_duration -=
|
||||
dtack_cycle_.length +
|
||||
bus_handler_.perform_bus_operation(dtack_cycle_, is_supervisor_);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: obey is_stopped_.
|
||||
if(active_step_->microcycle.data_select_active()) {
|
||||
if(!dtack_is_implicit && !dtack_ && !bus_error_) {
|
||||
execution_state_ = ExecutionState::WaitingForDTack;
|
||||
dtack_cycle_ = active_step_->microcycle;
|
||||
dtack_cycle_.length = HalfCycles(2);
|
||||
dtack_cycle_.operation &= ~(Microcycle::SelectByte | Microcycle::SelectWord);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for bus error here.
|
||||
if(bus_error_) {
|
||||
active_program_ = nullptr;
|
||||
active_micro_op_ = long_exception_micro_ops_;
|
||||
active_step_ = active_micro_op_->bus_program;
|
||||
populate_bus_error_steps(2, get_status(), get_bus_code(), *active_step_->microcycle.address);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for an address error. Which I have assumed happens before the microcycle that
|
||||
// would nominate the new address.
|
||||
if(
|
||||
(active_step_[0].microcycle.operation & Microcycle::NewAddress) &&
|
||||
(active_step_[1].microcycle.operation & Microcycle::SelectWord) &&
|
||||
*active_step_->microcycle.address & 1) {
|
||||
active_program_ = nullptr;
|
||||
active_micro_op_ = long_exception_micro_ops_;
|
||||
active_step_ = active_micro_op_->bus_program;
|
||||
populate_bus_error_steps(3, get_status(), get_bus_code(), *active_step_->microcycle.address);
|
||||
}
|
||||
|
||||
// Perform the microcycle.
|
||||
remaining_duration -=
|
||||
@ -127,7 +177,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
if(trace_flag_) {
|
||||
// The user has set the trace bit in the status register.
|
||||
active_program_ = nullptr;
|
||||
active_micro_op_ = exception_micro_ops_;
|
||||
active_micro_op_ = short_exception_micro_ops_;
|
||||
populate_trap_steps(9, get_status());
|
||||
} else {
|
||||
#ifdef LOG_TRACE
|
||||
@ -144,34 +194,34 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
std::cout << '\n';
|
||||
#endif
|
||||
|
||||
decoded_instruction_ = prefetch_queue_.halves.high.full;
|
||||
decoded_instruction_.full = prefetch_queue_.halves.high.full;
|
||||
#ifdef LOG_TRACE
|
||||
std::cout << std::hex << (program_counter_.full - 4) << ": " << std::setw(4) << decoded_instruction_ << '\t';
|
||||
std::cout << std::hex << (program_counter_.full - 4) << ": " << std::setw(4) << decoded_instruction_.full << '\t';
|
||||
#endif
|
||||
|
||||
if(signal_will_perform) {
|
||||
bus_handler_.will_perform(program_counter_.full - 4, decoded_instruction_);
|
||||
bus_handler_.will_perform(program_counter_.full - 4, decoded_instruction_.full);
|
||||
}
|
||||
|
||||
if(instructions[decoded_instruction_].micro_operations) {
|
||||
if(instructions[decoded_instruction_].requires_supervisor && !is_supervisor_) {
|
||||
if(instructions[decoded_instruction_.full].micro_operations) {
|
||||
if(instructions[decoded_instruction_.full].requires_supervisor && !is_supervisor_) {
|
||||
// A privilege violation has been detected.
|
||||
active_program_ = nullptr;
|
||||
active_micro_op_ = exception_micro_ops_;
|
||||
active_micro_op_ = short_exception_micro_ops_;
|
||||
populate_trap_steps(8, get_status());
|
||||
} else {
|
||||
// Standard instruction dispatch.
|
||||
active_program_ = &instructions[decoded_instruction_];
|
||||
active_program_ = &instructions[decoded_instruction_.full];
|
||||
active_micro_op_ = active_program_->micro_operations;
|
||||
}
|
||||
} else {
|
||||
// The opcode fetched isn't valid.
|
||||
active_program_ = nullptr;
|
||||
active_micro_op_ = exception_micro_ops_;
|
||||
active_micro_op_ = short_exception_micro_ops_;
|
||||
|
||||
// The vector used depends on whether this is a vanilla unrecognised instruction,
|
||||
// or one on the A or F lines.
|
||||
switch(decoded_instruction_ >> 12) {
|
||||
switch(decoded_instruction_.full >> 12) {
|
||||
default: populate_trap_steps(4, get_status()); break;
|
||||
case 0xa: populate_trap_steps(10, get_status()); break;
|
||||
case 0xf: populate_trap_steps(11, get_status()); break;
|
||||
@ -183,7 +233,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
auto bus_program = active_micro_op_->bus_program;
|
||||
switch(active_micro_op_->action) {
|
||||
default:
|
||||
std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << " within instruction " << decoded_instruction_ << std::endl;
|
||||
std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << " within instruction " << decoded_instruction_.full << std::endl;
|
||||
break;
|
||||
|
||||
case int(MicroOp::Action::None): break;
|
||||
@ -267,7 +317,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
#define no_extend(op, a, b, c) op(a, b, c, 0, z_set)
|
||||
#define extend(op, a, b, c) op(a, b, c, extend_flag_, z_or)
|
||||
|
||||
#define q() (((decoded_instruction_ >> 9)&7) ? ((decoded_instruction_ >> 9)&7) : 8)
|
||||
#define q() (((decoded_instruction_.full >> 9)&7) ? ((decoded_instruction_.full >> 9)&7) : 8)
|
||||
|
||||
case Operation::ADDb: {
|
||||
no_extend( addb,
|
||||
@ -508,10 +558,10 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
const int8_t byte_offset = int8_t(prefetch_queue_.halves.high.halves.low);
|
||||
|
||||
// Check whether this is secretly BSR.
|
||||
const bool is_bsr = ((decoded_instruction_ >> 8) & 0xf) == 1;
|
||||
const bool is_bsr = ((decoded_instruction_.full >> 8) & 0xf) == 1;
|
||||
|
||||
// Test the conditional, treating 'false' as true.
|
||||
const bool should_branch = is_bsr || evaluate_condition(decoded_instruction_ >> 8);
|
||||
const bool should_branch = is_bsr || evaluate_condition(decoded_instruction_.full >> 8);
|
||||
|
||||
// Schedule something appropriate, by rewriting the program for this instruction temporarily.
|
||||
if(should_branch) {
|
||||
@ -533,7 +583,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
|
||||
case Operation::DBcc: {
|
||||
// Decide what sort of DBcc this is.
|
||||
if(!evaluate_condition(decoded_instruction_ >> 8)) {
|
||||
if(!evaluate_condition(decoded_instruction_.full >> 8)) {
|
||||
-- active_program_->source->halves.low.full;
|
||||
const auto target_program_counter = program_counter_.full + int16_t(prefetch_queue_.halves.low.full) - 2;
|
||||
|
||||
@ -557,7 +607,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
|
||||
case Operation::Scc: {
|
||||
active_program_->destination->halves.low.halves.low =
|
||||
evaluate_condition(decoded_instruction_ >> 8) ? 0xff : 0x00;
|
||||
evaluate_condition(decoded_instruction_.full >> 8) ? 0xff : 0x00;
|
||||
} break;
|
||||
|
||||
/*
|
||||
@ -781,7 +831,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
if(!active_program_->source->halves.low.full) {
|
||||
// Schedule a divide-by-zero exception.
|
||||
active_program_ = nullptr;
|
||||
active_micro_op_ = exception_micro_ops_;
|
||||
active_micro_op_ = short_exception_micro_ops_;
|
||||
bus_program = active_micro_op_->bus_program;
|
||||
populate_trap_steps(5, get_status());
|
||||
program_counter_.full -= 2;
|
||||
@ -844,7 +894,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
if(!active_program_->source->halves.low.full) {
|
||||
// Schedule a divide-by-zero exception.
|
||||
active_program_ = nullptr;
|
||||
active_micro_op_ = exception_micro_ops_;
|
||||
active_micro_op_ = short_exception_micro_ops_;
|
||||
bus_program = active_micro_op_->bus_program;
|
||||
populate_trap_steps(5, get_status());
|
||||
program_counter_.full -= 2;
|
||||
@ -946,7 +996,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
bus_program = base + (64 - total_to_move*words_per_reg)*2; \
|
||||
\
|
||||
/* Fill in the proper addresses and targets. */ \
|
||||
const auto mode = (decoded_instruction_ >> 3) & 7; \
|
||||
const auto mode = (decoded_instruction_.full >> 3) & 7; \
|
||||
uint32_t start_address; \
|
||||
if(mode <= 4) { \
|
||||
start_address = active_program_->destination_address->full; \
|
||||
@ -1081,7 +1131,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
case Operation::TRAP: {
|
||||
// Select the trap steps as next; the initial microcycle should be 4 cycles long.
|
||||
bus_program = trap_steps_;
|
||||
populate_trap_steps((decoded_instruction_ & 15) + 32, get_status());
|
||||
populate_trap_steps((decoded_instruction_.full & 15) + 32, get_status());
|
||||
bus_program->microcycle.length = HalfCycles(8);
|
||||
|
||||
// The program counter to push is actually one slot ago.
|
||||
@ -1365,7 +1415,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
overflow_flag_ = (value ^ zero_result_) & (m);
|
||||
|
||||
#define decode_shift_count() \
|
||||
int shift_count = (decoded_instruction_ & 32) ? data_[(decoded_instruction_ >> 9) & 7].full&63 : ( ((decoded_instruction_ >> 9)&7) ? ((decoded_instruction_ >> 9)&7) : 8) ; \
|
||||
int shift_count = (decoded_instruction_.full & 32) ? data_[(decoded_instruction_.full >> 9) & 7].full&63 : ( ((decoded_instruction_.full >> 9)&7) ? ((decoded_instruction_.full >> 9)&7) : 8) ; \
|
||||
active_step_->microcycle.length = HalfCycles(4 * shift_count);
|
||||
|
||||
#define set_flags_b(t) set_flags(active_program_->destination->halves.low.halves.low, 0x80, t)
|
||||
@ -1604,7 +1654,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
*/
|
||||
case Operation::RTE_RTR:
|
||||
// If this is RTR, patch out the is_supervisor bit.
|
||||
if(decoded_instruction_ == 0x4e77) {
|
||||
if(decoded_instruction_.full == 0x4e77) {
|
||||
source_bus_data_[0].full =
|
||||
(source_bus_data_[0].full & ~(1 << 13)) |
|
||||
(is_supervisor_ << 13);
|
||||
@ -1636,7 +1686,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
|
||||
case Operation::STOP:
|
||||
set_status(prefetch_queue_.halves.low.full);
|
||||
is_stopped_ = true;
|
||||
execution_state_ = ExecutionState::Stopped;
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -1666,23 +1716,23 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
}
|
||||
|
||||
// If the post-increment mode was used, overwrite the source register.
|
||||
const auto mode = (decoded_instruction_ >> 3) & 7;
|
||||
const auto mode = (decoded_instruction_.full >> 3) & 7;
|
||||
if(mode == 3) {
|
||||
const auto reg = decoded_instruction_ & 7;
|
||||
const auto reg = decoded_instruction_.full & 7;
|
||||
address_[reg] = movem_final_address_;
|
||||
}
|
||||
} break;
|
||||
|
||||
case int(MicroOp::Action::MOVEMtoMComplete): {
|
||||
const auto mode = (decoded_instruction_ >> 3) & 7;
|
||||
const auto mode = (decoded_instruction_.full >> 3) & 7;
|
||||
if(mode == 4) {
|
||||
const auto reg = decoded_instruction_ & 7;
|
||||
const auto reg = decoded_instruction_.full & 7;
|
||||
address_[reg] = movem_final_address_;
|
||||
}
|
||||
} break;
|
||||
|
||||
case int(MicroOp::Action::PrepareJSR): {
|
||||
const auto mode = (decoded_instruction_ >> 3) & 7;
|
||||
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) */
|
||||
@ -1695,7 +1745,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
} break;
|
||||
|
||||
case int(MicroOp::Action::PrepareBSR):
|
||||
destination_bus_data_[0].full = (decoded_instruction_ & 0xff) ? program_counter_.full - 2 : program_counter_.full;
|
||||
destination_bus_data_[0].full = (decoded_instruction_.full & 0xff) ? program_counter_.full - 2 : program_counter_.full;
|
||||
address_[7].full -= 4;
|
||||
effective_address_[1].full = address_[7].full;
|
||||
break;
|
||||
@ -1828,7 +1878,6 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
#undef CalculateD8AnXn
|
||||
|
||||
case int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask:
|
||||
// Assumption: this will be assembling right at the start of the instruction.
|
||||
effective_address_[0] = int16_t(prefetch_queue_.halves.low.full);
|
||||
break;
|
||||
|
||||
@ -1845,7 +1894,6 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
||||
break;
|
||||
|
||||
case int(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask:
|
||||
// Assumption: this will be assembling right at the start of the instruction.
|
||||
source_bus_data_[0] = prefetch_queue_.halves.low.full;
|
||||
break;
|
||||
|
||||
|
@ -3407,9 +3407,26 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
||||
|
||||
// Target addresses and values will be filled in by TRAP/illegal too.
|
||||
const size_t trap_offset = constructor.assemble_program("r nw nw nW nV nv np np", { &precomputed_addresses_[0], &precomputed_addresses_[1], &precomputed_addresses_[2] });
|
||||
const size_t bus_error_offset =
|
||||
constructor.assemble_program(
|
||||
"nn nw nw nW nw nw nw nW nV nv np np",
|
||||
{
|
||||
&precomputed_addresses_[0],
|
||||
&precomputed_addresses_[1],
|
||||
&precomputed_addresses_[2],
|
||||
&precomputed_addresses_[3],
|
||||
&precomputed_addresses_[4],
|
||||
&precomputed_addresses_[5],
|
||||
&precomputed_addresses_[6]
|
||||
}
|
||||
);
|
||||
|
||||
// Chuck in the proper micro-ops for handling an exception.
|
||||
const auto exception_offset = all_micro_ops_.size();
|
||||
const auto short_exception_offset = all_micro_ops_.size();
|
||||
all_micro_ops_.emplace_back(ProcessorBase::MicroOp::Action::None);
|
||||
all_micro_ops_.emplace_back();
|
||||
|
||||
const auto long_exception_offset = all_micro_ops_.size();
|
||||
all_micro_ops_.emplace_back(ProcessorBase::MicroOp::Action::None);
|
||||
all_micro_ops_.emplace_back();
|
||||
|
||||
@ -3444,6 +3461,16 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
||||
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;
|
||||
|
||||
// Link the bus error exception steps and fill in the proper sources.
|
||||
bus_error_steps_ = &all_bus_steps_[bus_error_offset];
|
||||
bus_error_steps_[1].microcycle.value = bus_error_steps_[2].microcycle.value = &program_counter_.halves.low;
|
||||
bus_error_steps_[3].microcycle.value = bus_error_steps_[4].microcycle.value = &destination_bus_data_[0].halves.low;
|
||||
bus_error_steps_[5].microcycle.value = bus_error_steps_[6].microcycle.value = &program_counter_.halves.high;
|
||||
bus_error_steps_[7].microcycle.value = bus_error_steps_[8].microcycle.value = &decoded_instruction_;
|
||||
bus_error_steps_[9].microcycle.value = bus_error_steps_[10].microcycle.value = &effective_address_[0].halves.low;
|
||||
bus_error_steps_[11].microcycle.value = bus_error_steps_[12].microcycle.value = &destination_bus_data_[0].halves.high;
|
||||
bus_error_steps_[13].microcycle.value = bus_error_steps_[14].microcycle.value = &effective_address_[0].halves.high;
|
||||
|
||||
// Also relink the RTE and RTR bus steps to collect the program counter.
|
||||
//
|
||||
// Assumed order of input: PC.h, SR, PC.l (i.e. the opposite of TRAP's output).
|
||||
@ -3453,9 +3480,15 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
||||
steps[4].microcycle.value = steps[5].microcycle.value = &program_counter_.halves.low;
|
||||
}
|
||||
|
||||
// Setup the stop cycle.
|
||||
stop_cycle_.length = HalfCycles(2);
|
||||
|
||||
// Complete linkage of the exception micro program.
|
||||
exception_micro_ops_ = &all_micro_ops_[exception_offset];
|
||||
exception_micro_ops_->bus_program = trap_steps_;
|
||||
short_exception_micro_ops_ = &all_micro_ops_[short_exception_offset];
|
||||
short_exception_micro_ops_->bus_program = trap_steps_;
|
||||
|
||||
long_exception_micro_ops_ = &all_micro_ops_[long_exception_offset];
|
||||
long_exception_micro_ops_->bus_program = bus_error_steps_;
|
||||
|
||||
// Set initial state.
|
||||
active_step_ = reset_bus_steps_;
|
||||
|
@ -23,7 +23,13 @@ class ProcessorStorage {
|
||||
|
||||
RegisterPair32 prefetch_queue_; // Each word will go into the low part of the word, then proceed upward.
|
||||
|
||||
bool is_stopped_ = false;
|
||||
enum class ExecutionState {
|
||||
Executing,
|
||||
WaitingForDTack,
|
||||
Stopped
|
||||
} execution_state_ = ExecutionState::Executing;
|
||||
Microcycle dtack_cycle_;
|
||||
Microcycle stop_cycle_;
|
||||
|
||||
// Various status bits.
|
||||
int is_supervisor_;
|
||||
@ -241,7 +247,7 @@ class ProcessorStorage {
|
||||
/// Sets the high three bytes according to the MSB of the low byte.
|
||||
SignExtendByte,
|
||||
|
||||
/// From the next word in the prefetch queue assembles a 0-padded 32-bit long word in either or
|
||||
/// From the next word in the prefetch queue assembles a sign-extended long word in either or
|
||||
/// both of effective_address_[0] and effective_address_[1].
|
||||
AssembleWordAddressFromPrefetch,
|
||||
|
||||
@ -339,7 +345,9 @@ class ProcessorStorage {
|
||||
|
||||
// Special steps and programs for exception handlers.
|
||||
BusStep *reset_bus_steps_;
|
||||
MicroOp *exception_micro_ops_;
|
||||
MicroOp *long_exception_micro_ops_; // i.e. those that leave 14 bytes on the stack — bus error and address error.
|
||||
MicroOp *short_exception_micro_ops_; // i.e. those that leave 6 bytes on the stack — everything else (other than interrupts).
|
||||
MicroOp *interrupt_micro_ops_;
|
||||
|
||||
// Special micro-op sequences and storage for conditionals.
|
||||
BusStep *branch_taken_bus_steps_;
|
||||
@ -356,12 +364,13 @@ class ProcessorStorage {
|
||||
BusStep *movem_write_steps_;
|
||||
|
||||
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;
|
||||
uint16_t decoded_instruction_ = 0;
|
||||
RegisterPair16 decoded_instruction_ = 0;
|
||||
uint16_t next_word_ = 0;
|
||||
|
||||
/// Copies address_[7] to the proper stack pointer based on current mode.
|
||||
@ -405,6 +414,11 @@ class ProcessorStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Fills in the appropriate addresses and values to complete the TRAP steps — those
|
||||
representing a short-form exception — and mutates the status register as if one
|
||||
were beginning.
|
||||
*/
|
||||
inline void populate_trap_steps(uint32_t vector, uint16_t status) {
|
||||
// Fill in the status word value.
|
||||
destination_bus_data_[0].full = status;
|
||||
@ -417,15 +431,39 @@ class ProcessorStorage {
|
||||
effective_address_[0].full = vector << 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;
|
||||
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_[2] = address_[7].full - 4; // PC.h
|
||||
address_[7].full -= 6;
|
||||
|
||||
// Set the default timing.
|
||||
trap_steps_->microcycle.length = HalfCycles(8);
|
||||
}
|
||||
|
||||
inline 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;
|
||||
effective_address_[1] = faulting_address;
|
||||
|
||||
// Switch to supervisor mode, disable the trace bit.
|
||||
set_is_supervisor(true);
|
||||
trace_flag_ = 0;
|
||||
|
||||
// Pick a vector.
|
||||
effective_address_[0].full = vector << 2;
|
||||
|
||||
// Schedule the proper stack activity.
|
||||
precomputed_addresses_[0] = address_[7].full - 2; // PC.l
|
||||
precomputed_addresses_[1] = address_[7].full - 6; // status word
|
||||
precomputed_addresses_[2] = address_[7].full - 4; // PC.h
|
||||
precomputed_addresses_[3] = address_[7].full - 8; // current instruction
|
||||
precomputed_addresses_[4] = address_[7].full - 10; // fault address.l
|
||||
precomputed_addresses_[5] = address_[7].full - 14; // bus cycle status word
|
||||
precomputed_addresses_[6] = address_[7].full - 12; // fault address.h
|
||||
address_[7].full -= 14;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class ProcessorStorageConstructor;
|
||||
|
Loading…
Reference in New Issue
Block a user