mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-23 21:29:11 +00:00
Corrects internet response to work as currently implemented.
Also makes corrections to the bus error and address error exceptions.
This commit is contained in:
parent
2e5c0811e7
commit
bb07206c55
@ -21,7 +21,7 @@
|
|||||||
class RAM68000: public CPU::MC68000::BusHandler {
|
class RAM68000: public CPU::MC68000::BusHandler {
|
||||||
public:
|
public:
|
||||||
RAM68000() : m68000_(*this) {
|
RAM68000() : m68000_(*this) {
|
||||||
ram_.resize(32768);
|
ram_.resize(256*1024);
|
||||||
|
|
||||||
// Setup the /RESET vector.
|
// Setup the /RESET vector.
|
||||||
ram_[0] = 0;
|
ram_[0] = 0;
|
||||||
@ -58,6 +58,9 @@ class RAM68000: public CPU::MC68000::BusHandler {
|
|||||||
|
|
||||||
using Microcycle = CPU::MC68000::Microcycle;
|
using Microcycle = CPU::MC68000::Microcycle;
|
||||||
if(cycle.data_select_active()) {
|
if(cycle.data_select_active()) {
|
||||||
|
if(cycle.operation & Microcycle::InterruptAcknowledge) {
|
||||||
|
cycle.value->halves.low = 10;
|
||||||
|
} else {
|
||||||
switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
@ -76,6 +79,7 @@ class RAM68000: public CPU::MC68000::BusHandler {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return HalfCycles(0);
|
return HalfCycles(0);
|
||||||
}
|
}
|
||||||
@ -88,7 +92,7 @@ class RAM68000: public CPU::MC68000::BusHandler {
|
|||||||
m68000_.set_state(state);
|
m68000_.set_state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CPU::MC68000::Processor<RAM68000, true, true> &processor() {
|
CPU::MC68000::Processor<RAM68000, true, true> &processor() {
|
||||||
return m68000_;
|
return m68000_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,6 +290,17 @@ class CPU::MC68000::ProcessorStorageTests {
|
|||||||
XCTAssert(state.data[2] == 0x303cfb2e, "D2 was %08x instead of 0x303cfb2e", state.data[2]);
|
XCTAssert(state.data[2] == 0x303cfb2e, "D2 was %08x instead of 0x303cfb2e", state.data[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)testVectoredInterrupt {
|
||||||
|
_machine->set_program({
|
||||||
|
0x46f8, 0x2000, // MOVE $2000, SR
|
||||||
|
0x4e71, // NOP
|
||||||
|
0x4e71, // NOP
|
||||||
|
});
|
||||||
|
_machine->run_for_instructions(1);
|
||||||
|
_machine->processor().set_interrupt_level(1);
|
||||||
|
_machine->run_for_instructions(1);
|
||||||
|
}
|
||||||
|
|
||||||
- (void)testOpcodeCoverage {
|
- (void)testOpcodeCoverage {
|
||||||
// Perform an audit of implemented instructions.
|
// Perform an audit of implemented instructions.
|
||||||
CPU::MC68000::ProcessorStorageTests storage_tests(
|
CPU::MC68000::ProcessorStorageTests storage_tests(
|
||||||
|
@ -45,29 +45,16 @@ namespace MC68000 {
|
|||||||
avoid the runtime cost of actual DTack emulation. But such as the bus allows.)
|
avoid the runtime cost of actual DTack emulation. But such as the bus allows.)
|
||||||
*/
|
*/
|
||||||
struct Microcycle {
|
struct Microcycle {
|
||||||
/*
|
|
||||||
The operation code is composed of several parts; a compound low part
|
|
||||||
that can be masked off with TypeMask identifies the type of the cycle;
|
|
||||||
some of the other status lines are also present in the top parts of the int.
|
|
||||||
*/
|
|
||||||
static const int TypeMask = 3;
|
|
||||||
|
|
||||||
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;
|
||||||
/// this correlates to states 0 to 5 of a standard read/write cycle.
|
/// this correlates to states 0 to 5 of a standard read/write cycle.
|
||||||
static const int NewAddress = 1;
|
static const int NewAddress = 1 << 0;
|
||||||
|
|
||||||
/// A SameAddress cycle is one in which the address strobe is continuously asserted, but neither
|
/// A SameAddress cycle is one in which the address strobe is continuously asserted, but neither
|
||||||
/// of the data strobes are.
|
/// of the data strobes are.
|
||||||
static const int SameAddress = 2;
|
static const int SameAddress = 1 << 1;
|
||||||
|
|
||||||
/// A Reset cycle is one in which the RESET output is asserted.
|
/// A Reset cycle is one in which the RESET output is asserted.
|
||||||
static const int Reset = 3;
|
static const int Reset = 1 << 2;
|
||||||
|
|
||||||
/// The interrupt acknowledge cycle is that during which the 68000 seeks to obtain the vector for
|
|
||||||
/// an interrupt it plans to observe. Noted on a real 68000 by all FCs being set to 1.
|
|
||||||
static const int InterruptAcknowledge = 4;
|
|
||||||
|
|
||||||
/// Indicates that the address and both data select strobes are active.
|
/// Indicates that the address and both data select strobes are active.
|
||||||
static const int SelectWord = 1 << 3;
|
static const int SelectWord = 1 << 3;
|
||||||
@ -79,12 +66,16 @@ struct Microcycle {
|
|||||||
/// If set, indicates a read. Otherwise, a write.
|
/// If set, indicates a read. Otherwise, a write.
|
||||||
static const int Read = 1 << 5;
|
static const int Read = 1 << 5;
|
||||||
|
|
||||||
/// Contains the value of line FC0.
|
/// Contains the value of line FC0 if it is not implicit via InterruptAcknowledge.
|
||||||
static const int IsData = 1 << 6;
|
static const int IsData = 1 << 6;
|
||||||
|
|
||||||
/// Contains the value of line FC1.
|
/// Contains the value of line FC1 if it is not implicit via InterruptAcknowledge.
|
||||||
static const int IsProgram = 1 << 7;
|
static const int IsProgram = 1 << 7;
|
||||||
|
|
||||||
|
/// The interrupt acknowledge cycle is that during which the 68000 seeks to obtain the vector for
|
||||||
|
/// an interrupt it plans to observe. Noted on a real 68000 by all FCs being set to 1.
|
||||||
|
static const int InterruptAcknowledge = 1 << 8;
|
||||||
|
|
||||||
int operation = 0;
|
int operation = 0;
|
||||||
HalfCycles length = HalfCycles(4);
|
HalfCycles length = HalfCycles(4);
|
||||||
|
|
||||||
|
@ -76,10 +76,11 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
|
|
||||||
// Check for bus error.
|
// Check for bus error.
|
||||||
if(bus_error_ && !is_starting_interrupt_) {
|
if(bus_error_ && !is_starting_interrupt_) {
|
||||||
|
const auto offending_address = *active_step_->microcycle.address;
|
||||||
active_program_ = nullptr;
|
active_program_ = nullptr;
|
||||||
active_micro_op_ = long_exception_micro_ops_;
|
active_micro_op_ = long_exception_micro_ops_;
|
||||||
active_step_ = active_micro_op_->bus_program;
|
active_step_ = active_micro_op_->bus_program;
|
||||||
populate_bus_error_steps(2, get_status(), get_bus_code(), *active_step_->microcycle.address);
|
populate_bus_error_steps(2, get_status(), get_bus_code(), offending_address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,16 +90,42 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
(active_step_[0].microcycle.operation & Microcycle::NewAddress) &&
|
(active_step_[0].microcycle.operation & Microcycle::NewAddress) &&
|
||||||
(active_step_[1].microcycle.operation & Microcycle::SelectWord) &&
|
(active_step_[1].microcycle.operation & Microcycle::SelectWord) &&
|
||||||
*active_step_->microcycle.address & 1) {
|
*active_step_->microcycle.address & 1) {
|
||||||
|
const auto offending_address = *active_step_->microcycle.address;
|
||||||
active_program_ = nullptr;
|
active_program_ = nullptr;
|
||||||
active_micro_op_ = long_exception_micro_ops_;
|
active_micro_op_ = long_exception_micro_ops_;
|
||||||
active_step_ = active_micro_op_->bus_program;
|
active_step_ = active_micro_op_->bus_program;
|
||||||
populate_bus_error_steps(3, get_status(), get_bus_code(), *active_step_->microcycle.address);
|
populate_bus_error_steps(3, get_status(), get_bus_code(), offending_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the microcycle.
|
// Perform the microcycle.
|
||||||
cycles_run_for +=
|
cycles_run_for +=
|
||||||
active_step_->microcycle.length +
|
active_step_->microcycle.length +
|
||||||
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
|
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
|
||||||
|
|
||||||
|
/*
|
||||||
|
PERFORM THE BUS STEP'S ACTION.
|
||||||
|
*/
|
||||||
|
switch(active_step_->action) {
|
||||||
|
default:
|
||||||
|
std::cerr << "Unimplemented 68000 bus step action: " << int(active_step_->action) << std::endl;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BusStep::Action::None: break;
|
||||||
|
|
||||||
|
case BusStep::Action::IncrementEffectiveAddress0: effective_address_[0].full += 2; break;
|
||||||
|
case BusStep::Action::IncrementEffectiveAddress1: effective_address_[1].full += 2; break;
|
||||||
|
case BusStep::Action::DecrementEffectiveAddress0: effective_address_[0].full -= 2; break;
|
||||||
|
case BusStep::Action::DecrementEffectiveAddress1: effective_address_[1].full -= 2; break;
|
||||||
|
case BusStep::Action::IncrementProgramCounter: program_counter_.full += 2; break;
|
||||||
|
|
||||||
|
case BusStep::Action::AdvancePrefetch:
|
||||||
|
prefetch_queue_.halves.high = prefetch_queue_.halves.low;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next bus step.
|
||||||
|
++ active_step_;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ExecutionState::Stopped:
|
case ExecutionState::Stopped:
|
||||||
@ -144,11 +171,11 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
active_program_ = nullptr;
|
active_program_ = nullptr;
|
||||||
active_micro_op_ = interrupt_micro_ops_;
|
active_micro_op_ = interrupt_micro_ops_;
|
||||||
execution_state_ = ExecutionState::Executing;
|
execution_state_ = ExecutionState::Executing;
|
||||||
|
active_step_ = active_micro_op_->bus_program;
|
||||||
is_starting_interrupt_ = true;
|
is_starting_interrupt_ = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef LOG_TRACE
|
#ifdef LOG_TRACE
|
||||||
if(!(active_step_->microcycle.operation & Microcycle::IsProgram)) {
|
if(!(active_step_->microcycle.operation & Microcycle::IsProgram)) {
|
||||||
switch(active_step_->microcycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
switch(active_step_->microcycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
||||||
@ -170,30 +197,6 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
PERFORM THE BUS STEP'S ACTION.
|
|
||||||
*/
|
|
||||||
switch(active_step_->action) {
|
|
||||||
default:
|
|
||||||
std::cerr << "Unimplemented 68000 bus step action: " << int(active_step_->action) << std::endl;
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BusStep::Action::None: break;
|
|
||||||
|
|
||||||
case BusStep::Action::IncrementEffectiveAddress0: effective_address_[0].full += 2; break;
|
|
||||||
case BusStep::Action::IncrementEffectiveAddress1: effective_address_[1].full += 2; break;
|
|
||||||
case BusStep::Action::DecrementEffectiveAddress0: effective_address_[0].full -= 2; break;
|
|
||||||
case BusStep::Action::DecrementEffectiveAddress1: effective_address_[1].full -= 2; break;
|
|
||||||
case BusStep::Action::IncrementProgramCounter: program_counter_.full += 2; break;
|
|
||||||
|
|
||||||
case BusStep::Action::AdvancePrefetch:
|
|
||||||
prefetch_queue_.halves.high = prefetch_queue_.halves.low;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to the next bus step.
|
|
||||||
++ active_step_;
|
|
||||||
/*
|
/*
|
||||||
FIND THE NEXT MICRO-OP IF UNKNOWN.
|
FIND THE NEXT MICRO-OP IF UNKNOWN.
|
||||||
*/
|
*/
|
||||||
@ -1800,8 +1803,8 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case int(MicroOp::Action::PrepareINT):
|
case int(MicroOp::Action::PrepareINT):
|
||||||
accepted_interrupt_level_ = bus_interrupt_level_;
|
|
||||||
populate_trap_steps(0, get_status());
|
populate_trap_steps(0, get_status());
|
||||||
|
accepted_interrupt_level_ = interrupt_level_ = bus_interrupt_level_;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case int(MicroOp::Action::PrepareINTVector):
|
case int(MicroOp::Action::PrepareINTVector):
|
||||||
|
@ -340,12 +340,12 @@ struct ProcessorStorageConstructor {
|
|||||||
|
|
||||||
// Interrupt acknowledge.
|
// Interrupt acknowledge.
|
||||||
if(token == "int") {
|
if(token == "int") {
|
||||||
step.microcycle.operation = Microcycle::InterruptAcknowledge | Microcycle::IsData | Microcycle::IsProgram | Microcycle::NewAddress;
|
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.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_[0].halves.low;
|
||||||
steps.push_back(step);
|
steps.push_back(step);
|
||||||
|
|
||||||
step.microcycle.operation = Microcycle::InterruptAcknowledge | Microcycle::IsData | Microcycle::IsProgram | Microcycle::SameAddress | Microcycle::SelectByte;
|
step.microcycle.operation = Microcycle::InterruptAcknowledge | Microcycle::SameAddress | Microcycle::SelectByte;
|
||||||
steps.push_back(step);
|
steps.push_back(step);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -3314,6 +3314,7 @@ struct ProcessorStorageConstructor {
|
|||||||
|
|
||||||
// Throw in the interrupt program.
|
// Throw in the interrupt program.
|
||||||
const auto interrupt_pointer = storage_.all_micro_ops_.size();
|
const auto interrupt_pointer = storage_.all_micro_ops_.size();
|
||||||
|
op(Action::None, seq("")); // WORKAROUND FOR THE BE68000 MAIN LOOP. Hopefully temporary.
|
||||||
op(Action::PrepareINT, seq("int")); // Perform a cycle that will obtain an interrupt vector, or else dictate an autovector or a spurious interrupt.
|
op(Action::PrepareINT, seq("int")); // Perform a cycle that will obtain an interrupt vector, or else dictate an autovector or a spurious interrupt.
|
||||||
op(Action::PrepareINTVector); // The standard trap steps will be appended here, and PrepareINT will set them up according to the vector received.
|
op(Action::PrepareINTVector); // The standard trap steps will be appended here, and PrepareINT will set them up according to the vector received.
|
||||||
op();
|
op();
|
||||||
@ -3509,7 +3510,7 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
|||||||
long_exception_micro_ops_->bus_program = bus_error_steps_;
|
long_exception_micro_ops_->bus_program = bus_error_steps_;
|
||||||
|
|
||||||
// Apply the TRAP steps to the interrupt routine.
|
// Apply the TRAP steps to the interrupt routine.
|
||||||
interrupt_micro_ops_[1].bus_program = trap_steps_;
|
interrupt_micro_ops_[2].bus_program = trap_steps_;
|
||||||
|
|
||||||
// Set initial state.
|
// Set initial state.
|
||||||
active_step_ = reset_bus_steps_;
|
active_step_ = reset_bus_steps_;
|
||||||
|
Loading…
Reference in New Issue
Block a user