From bb07206c5549b46931e5cbe829dcf7c31dfede0b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 1 May 2019 21:59:06 -0400 Subject: [PATCH] Corrects internet response to work as currently implemented. Also makes corrections to the bus error and address error exceptions. --- .../Mac/Clock SignalTests/68000Tests.mm | 49 +++++++++------ Processors/68000/68000.hpp | 27 +++------ .../Implementation/68000Implementation.hpp | 59 ++++++++++--------- .../68000/Implementation/68000Storage.cpp | 7 ++- 4 files changed, 76 insertions(+), 66 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm index 7edc65a47..2c09d106d 100644 --- a/OSBindings/Mac/Clock SignalTests/68000Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -21,7 +21,7 @@ class RAM68000: public CPU::MC68000::BusHandler { public: RAM68000() : m68000_(*this) { - ram_.resize(32768); + ram_.resize(256*1024); // Setup the /RESET vector. ram_[0] = 0; @@ -58,22 +58,26 @@ class RAM68000: public CPU::MC68000::BusHandler { using Microcycle = CPU::MC68000::Microcycle; if(cycle.data_select_active()) { - switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { - default: break; + if(cycle.operation & Microcycle::InterruptAcknowledge) { + cycle.value->halves.low = 10; + } else { + switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { + default: break; - case Microcycle::SelectWord | Microcycle::Read: - cycle.value->full = ram_[word_address]; - break; - case Microcycle::SelectByte | Microcycle::Read: - cycle.value->halves.low = ram_[word_address] >> cycle.byte_shift(); - break; - case Microcycle::SelectWord: - printf("w %08x of %02x\n", *cycle.address, cycle.value->full); - ram_[word_address] = cycle.value->full; - break; - case Microcycle::SelectByte: - ram_[word_address] = (cycle.value->full & cycle.byte_mask()) | (ram_[word_address] & (0xffff ^ cycle.byte_mask())); - break; + case Microcycle::SelectWord | Microcycle::Read: + cycle.value->full = ram_[word_address]; + break; + case Microcycle::SelectByte | Microcycle::Read: + cycle.value->halves.low = ram_[word_address] >> cycle.byte_shift(); + break; + case Microcycle::SelectWord: + printf("w %08x of %02x\n", *cycle.address, cycle.value->full); + ram_[word_address] = cycle.value->full; + break; + case Microcycle::SelectByte: + ram_[word_address] = (cycle.value->full & cycle.byte_mask()) | (ram_[word_address] & (0xffff ^ cycle.byte_mask())); + break; + } } } @@ -88,7 +92,7 @@ class RAM68000: public CPU::MC68000::BusHandler { m68000_.set_state(state); } - const CPU::MC68000::Processor &processor() { + CPU::MC68000::Processor &processor() { return m68000_; } @@ -286,6 +290,17 @@ class CPU::MC68000::ProcessorStorageTests { 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 { // Perform an audit of implemented instructions. CPU::MC68000::ProcessorStorageTests storage_tests( diff --git a/Processors/68000/68000.hpp b/Processors/68000/68000.hpp index c3b8e3875..8238ad8c3 100644 --- a/Processors/68000/68000.hpp +++ b/Processors/68000/68000.hpp @@ -45,29 +45,16 @@ namespace MC68000 { avoid the runtime cost of actual DTack emulation. But such as the bus allows.) */ 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; /// 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 /// 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. - static const int Reset = 3; - - /// 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; + static const int Reset = 1 << 2; /// Indicates that the address and both data select strobes are active. static const int SelectWord = 1 << 3; @@ -79,12 +66,16 @@ struct Microcycle { /// If set, indicates a read. Otherwise, a write. 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; - /// 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; + /// 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; HalfCycles length = HalfCycles(4); diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 61f99d121..bf8a22667 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -76,10 +76,11 @@ template void Proces // Check for bus error. if(bus_error_ && !is_starting_interrupt_) { + const auto offending_address = *active_step_->microcycle.address; 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); + populate_bus_error_steps(2, get_status(), get_bus_code(), offending_address); } } @@ -89,16 +90,42 @@ template void Proces (active_step_[0].microcycle.operation & Microcycle::NewAddress) && (active_step_[1].microcycle.operation & Microcycle::SelectWord) && *active_step_->microcycle.address & 1) { + const auto offending_address = *active_step_->microcycle.address; 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); + populate_bus_error_steps(3, get_status(), get_bus_code(), offending_address); } // Perform the microcycle. cycles_run_for += active_step_->microcycle.length + 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; case ExecutionState::Stopped: @@ -144,11 +171,11 @@ template void Proces active_program_ = nullptr; active_micro_op_ = interrupt_micro_ops_; execution_state_ = ExecutionState::Executing; + active_step_ = active_micro_op_->bus_program; is_starting_interrupt_ = true; break; } - #ifdef LOG_TRACE if(!(active_step_->microcycle.operation & Microcycle::IsProgram)) { switch(active_step_->microcycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { @@ -170,30 +197,6 @@ template void Proces } #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. */ @@ -1800,8 +1803,8 @@ template void Proces break; case int(MicroOp::Action::PrepareINT): - accepted_interrupt_level_ = bus_interrupt_level_; populate_trap_steps(0, get_status()); + accepted_interrupt_level_ = interrupt_level_ = bus_interrupt_level_; break; case int(MicroOp::Action::PrepareINTVector): diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index b1a1718d0..3d1781178 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -340,12 +340,12 @@ struct ProcessorStorageConstructor { // Interrupt acknowledge. 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.value = &storage_.source_bus_data_[0].halves.low; 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); continue; @@ -3314,6 +3314,7 @@ struct ProcessorStorageConstructor { // Throw in the interrupt program. 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::PrepareINTVector); // The standard trap steps will be appended here, and PrepareINT will set them up according to the vector received. op(); @@ -3509,7 +3510,7 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() { long_exception_micro_ops_->bus_program = bus_error_steps_; // 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. active_step_ = reset_bus_steps_;