1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-24 12:30:17 +00:00

Implement STOPpages, waits for DTack, and bus and address error exceptions.

This commit is contained in:
Thomas Harte 2019-04-30 19:24:22 -04:00
parent e430f2658f
commit 31bb770fdd
4 changed files with 174 additions and 57 deletions

View File

@ -52,8 +52,6 @@ struct Microcycle {
*/ */
static const int TypeMask = 3; 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; static const int Idle = 0;
/// A NewAddress cycle is one in which the address strobe is initially low but becomes high; /// A NewAddress cycle is one in which the address strobe is initially low but becomes high;

View File

@ -36,29 +36,79 @@
trace_flag_ = (x) & 0x8000; \ trace_flag_ = (x) & 0x8000; \
set_is_supervisor(!!(((x) >> 13) & 1)); 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) { 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_; HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
while(remaining_duration > HalfCycles(0)) { while(remaining_duration > HalfCycles(0)) {
/* /*
PERFORM THE CURRENT BUS STEP'S MICROCYCLE. PERFORM THE CURRENT BUS STEP'S MICROCYCLE.
*/ */
// Check for DTack if this isn't being treated implicitly. switch(execution_state_) {
if(active_step_->microcycle.data_select_active()) { default:
if(!dtack_is_implicit) { break;
if(active_step_->microcycle.data_select_active() && !dtack_) {
// TODO: perform wait state.
continue;
}
}
// TODO: synchronous bus. case ExecutionState::Stopped:
} else { // If an interrupt (TODO: or reset) has finally arrived that will be serviced,
// TODO: check for bus error (but here, or when checking for DTACK?) // exit the STOP.
// if(active_step_->microcycle.operation & MicroCycle::NewAddress) { 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. // Perform the microcycle.
remaining_duration -= remaining_duration -=
@ -127,7 +177,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
if(trace_flag_) { if(trace_flag_) {
// The user has set the trace bit in the status register. // The user has set the trace bit in the status register.
active_program_ = nullptr; active_program_ = nullptr;
active_micro_op_ = exception_micro_ops_; active_micro_op_ = short_exception_micro_ops_;
populate_trap_steps(9, get_status()); populate_trap_steps(9, get_status());
} else { } else {
#ifdef LOG_TRACE #ifdef LOG_TRACE
@ -144,34 +194,34 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
std::cout << '\n'; std::cout << '\n';
#endif #endif
decoded_instruction_ = prefetch_queue_.halves.high.full; decoded_instruction_.full = prefetch_queue_.halves.high.full;
#ifdef LOG_TRACE #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 #endif
if(signal_will_perform) { 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_.full].micro_operations) {
if(instructions[decoded_instruction_].requires_supervisor && !is_supervisor_) { if(instructions[decoded_instruction_.full].requires_supervisor && !is_supervisor_) {
// A privilege violation has been detected. // A privilege violation has been detected.
active_program_ = nullptr; active_program_ = nullptr;
active_micro_op_ = exception_micro_ops_; active_micro_op_ = short_exception_micro_ops_;
populate_trap_steps(8, get_status()); populate_trap_steps(8, get_status());
} else { } else {
// Standard instruction dispatch. // Standard instruction dispatch.
active_program_ = &instructions[decoded_instruction_]; active_program_ = &instructions[decoded_instruction_.full];
active_micro_op_ = active_program_->micro_operations; active_micro_op_ = active_program_->micro_operations;
} }
} else { } else {
// The opcode fetched isn't valid. // The opcode fetched isn't valid.
active_program_ = nullptr; 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, // The vector used depends on whether this is a vanilla unrecognised instruction,
// or one on the A or F lines. // 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; default: populate_trap_steps(4, get_status()); break;
case 0xa: populate_trap_steps(10, get_status()); break; case 0xa: populate_trap_steps(10, get_status()); break;
case 0xf: populate_trap_steps(11, 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; auto bus_program = active_micro_op_->bus_program;
switch(active_micro_op_->action) { switch(active_micro_op_->action) {
default: 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; break;
case int(MicroOp::Action::None): 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 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 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: { case Operation::ADDb: {
no_extend( 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); const int8_t byte_offset = int8_t(prefetch_queue_.halves.high.halves.low);
// Check whether this is secretly BSR. // 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. // 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. // Schedule something appropriate, by rewriting the program for this instruction temporarily.
if(should_branch) { if(should_branch) {
@ -533,7 +583,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
case Operation::DBcc: { case Operation::DBcc: {
// Decide what sort of DBcc this is. // 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; -- active_program_->source->halves.low.full;
const auto target_program_counter = program_counter_.full + int16_t(prefetch_queue_.halves.low.full) - 2; 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: { case Operation::Scc: {
active_program_->destination->halves.low.halves.low = active_program_->destination->halves.low.halves.low =
evaluate_condition(decoded_instruction_ >> 8) ? 0xff : 0x00; evaluate_condition(decoded_instruction_.full >> 8) ? 0xff : 0x00;
} break; } 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) { if(!active_program_->source->halves.low.full) {
// Schedule a divide-by-zero exception. // Schedule a divide-by-zero exception.
active_program_ = nullptr; active_program_ = nullptr;
active_micro_op_ = exception_micro_ops_; active_micro_op_ = short_exception_micro_ops_;
bus_program = active_micro_op_->bus_program; bus_program = active_micro_op_->bus_program;
populate_trap_steps(5, get_status()); populate_trap_steps(5, get_status());
program_counter_.full -= 2; 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) { if(!active_program_->source->halves.low.full) {
// Schedule a divide-by-zero exception. // Schedule a divide-by-zero exception.
active_program_ = nullptr; active_program_ = nullptr;
active_micro_op_ = exception_micro_ops_; active_micro_op_ = short_exception_micro_ops_;
bus_program = active_micro_op_->bus_program; bus_program = active_micro_op_->bus_program;
populate_trap_steps(5, get_status()); populate_trap_steps(5, get_status());
program_counter_.full -= 2; 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; \ bus_program = base + (64 - total_to_move*words_per_reg)*2; \
\ \
/* Fill in the proper addresses and targets. */ \ /* 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; \ uint32_t start_address; \
if(mode <= 4) { \ if(mode <= 4) { \
start_address = active_program_->destination_address->full; \ 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: { case Operation::TRAP: {
// Select the trap steps as next; the initial microcycle should be 4 cycles long. // Select the trap steps as next; the initial microcycle should be 4 cycles long.
bus_program = trap_steps_; 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); bus_program->microcycle.length = HalfCycles(8);
// The program counter to push is actually one slot ago. // 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); overflow_flag_ = (value ^ zero_result_) & (m);
#define decode_shift_count() \ #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); active_step_->microcycle.length = HalfCycles(4 * shift_count);
#define set_flags_b(t) set_flags(active_program_->destination->halves.low.halves.low, 0x80, t) #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: case Operation::RTE_RTR:
// If this is RTR, patch out the is_supervisor bit. // 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 =
(source_bus_data_[0].full & ~(1 << 13)) | (source_bus_data_[0].full & ~(1 << 13)) |
(is_supervisor_ << 13); (is_supervisor_ << 13);
@ -1636,7 +1686,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
case Operation::STOP: case Operation::STOP:
set_status(prefetch_queue_.halves.low.full); set_status(prefetch_queue_.halves.low.full);
is_stopped_ = true; execution_state_ = ExecutionState::Stopped;
break; 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. // 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) { if(mode == 3) {
const auto reg = decoded_instruction_ & 7; const auto reg = decoded_instruction_.full & 7;
address_[reg] = movem_final_address_; address_[reg] = movem_final_address_;
} }
} break; } break;
case int(MicroOp::Action::MOVEMtoMComplete): { case int(MicroOp::Action::MOVEMtoMComplete): {
const auto mode = (decoded_instruction_ >> 3) & 7; const auto mode = (decoded_instruction_.full >> 3) & 7;
if(mode == 4) { if(mode == 4) {
const auto reg = decoded_instruction_ & 7; const auto reg = decoded_instruction_.full & 7;
address_[reg] = movem_final_address_; address_[reg] = movem_final_address_;
} }
} break; } break;
case int(MicroOp::Action::PrepareJSR): { 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. // Determine the proper resumption address.
switch(mode) { switch(mode) {
case 2: destination_bus_data_[0].full = program_counter_.full - 2; break; /* (An) */ 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; } break;
case int(MicroOp::Action::PrepareBSR): 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; address_[7].full -= 4;
effective_address_[1].full = address_[7].full; effective_address_[1].full = address_[7].full;
break; break;
@ -1828,7 +1878,6 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
#undef CalculateD8AnXn #undef CalculateD8AnXn
case int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask: 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); effective_address_[0] = int16_t(prefetch_queue_.halves.low.full);
break; break;
@ -1845,7 +1894,6 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
break; break;
case int(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask: 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; source_bus_data_[0] = prefetch_queue_.halves.low.full;
break; break;

View File

@ -3407,9 +3407,26 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
// Target addresses and values will be filled in by TRAP/illegal too. // 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 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. // 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(ProcessorBase::MicroOp::Action::None);
all_micro_ops_.emplace_back(); 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_[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; 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. // 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). // 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; 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. // Complete linkage of the exception micro program.
exception_micro_ops_ = &all_micro_ops_[exception_offset]; short_exception_micro_ops_ = &all_micro_ops_[short_exception_offset];
exception_micro_ops_->bus_program = trap_steps_; 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. // Set initial state.
active_step_ = reset_bus_steps_; active_step_ = reset_bus_steps_;

View File

@ -23,7 +23,13 @@ class ProcessorStorage {
RegisterPair32 prefetch_queue_; // Each word will go into the low part of the word, then proceed upward. 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. // Various status bits.
int is_supervisor_; int is_supervisor_;
@ -241,7 +247,7 @@ class ProcessorStorage {
/// Sets the high three bytes according to the MSB of the low byte. /// Sets the high three bytes according to the MSB of the low byte.
SignExtendByte, 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]. /// both of effective_address_[0] and effective_address_[1].
AssembleWordAddressFromPrefetch, AssembleWordAddressFromPrefetch,
@ -339,7 +345,9 @@ class ProcessorStorage {
// Special steps and programs for exception handlers. // Special steps and programs for exception handlers.
BusStep *reset_bus_steps_; 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. // Special micro-op sequences and storage for conditionals.
BusStep *branch_taken_bus_steps_; BusStep *branch_taken_bus_steps_;
@ -356,12 +364,13 @@ class ProcessorStorage {
BusStep *movem_write_steps_; BusStep *movem_write_steps_;
BusStep *trap_steps_; BusStep *trap_steps_;
BusStep *bus_error_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;
MicroOp *active_micro_op_ = nullptr; MicroOp *active_micro_op_ = nullptr;
BusStep *active_step_ = nullptr; BusStep *active_step_ = nullptr;
uint16_t decoded_instruction_ = 0; RegisterPair16 decoded_instruction_ = 0;
uint16_t next_word_ = 0; uint16_t next_word_ = 0;
/// Copies address_[7] to the proper stack pointer based on current mode. /// 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) { inline void populate_trap_steps(uint32_t vector, uint16_t status) {
// Fill in the status word value. // Fill in the status word value.
destination_bus_data_[0].full = status; destination_bus_data_[0].full = status;
@ -417,15 +431,39 @@ class ProcessorStorage {
effective_address_[0].full = vector << 2; effective_address_[0].full = vector << 2;
// Schedule the proper stack activity. // Schedule the proper stack activity.
precomputed_addresses_[0] = address_[7].full - 2; precomputed_addresses_[0] = address_[7].full - 2; // PC.l
precomputed_addresses_[1] = address_[7].full - 6; precomputed_addresses_[1] = address_[7].full - 6; // status word (in destination_bus_data_[0])
precomputed_addresses_[2] = address_[7].full - 4; precomputed_addresses_[2] = address_[7].full - 4; // PC.h
address_[7].full -= 6; address_[7].full -= 6;
// Set the default timing. // Set the default timing.
trap_steps_->microcycle.length = HalfCycles(8); 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: private:
friend class ProcessorStorageConstructor; friend class ProcessorStorageConstructor;