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:
parent
e430f2658f
commit
31bb770fdd
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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_;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user