From 0d7bbdad54c348ecf2b2b75152a8079a153c8a66 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 17 Mar 2019 21:57:00 -0400 Subject: [PATCH] Begins a basic get/set state API, allowing some actual unit tests, implying an ABCD fix. --- .../Mac/Clock SignalTests/68000Tests.mm | 30 ++++++++++++++++--- Processors/68000/68000.hpp | 16 ++++++++++ .../Implementation/68000Implementation.hpp | 27 +++++++++++++++-- .../68000/Implementation/68000Storage.cpp | 15 +++++++++- .../68000/Implementation/68000Storage.hpp | 6 ++++ 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm index f0c031f15..ba8d1da61 100644 --- a/OSBindings/Mac/Clock SignalTests/68000Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -64,6 +64,14 @@ class RAM68000: public CPU::MC68000::BusHandler { return HalfCycles(0); } + CPU::MC68000::Processor::State get_processor_state() { + return m68000_.get_state(); + } + + void set_processor_state(const CPU::MC68000::Processor::State &state) { + m68000_.set_state(state); + } + private: CPU::MC68000::Processor m68000_; std::vector ram_; @@ -85,10 +93,24 @@ class RAM68000: public CPU::MC68000::BusHandler { } - (void)testABCD { - _machine->set_program({ - 0xc100 // ABCD D0, D0 - }); - _machine->run_for(HalfCycles(400)); + for(int d = 0; d < 100; ++d) { + _machine.reset(new RAM68000()); + _machine->set_program({ + 0xc100 // ABCD D0, D0 + }); + + auto state = _machine->get_processor_state(); + const uint8_t bcd_d = ((d / 10) * 16) + (d % 10); + state.data[0] = bcd_d; + _machine->set_processor_state(state); + + _machine->run_for(Cycles(40 + 6)); + + state = _machine->get_processor_state(); + const uint8_t double_d = (d * 2) % 100; + const uint8_t bcd_double_d = ((double_d / 10) * 16) + (double_d % 10); + XCTAssert(state.data[0] == bcd_double_d, "%02x + %02x = %02x; should equal %02x", bcd_d, bcd_d, state.data[0], bcd_double_d); + } } - (void)testSBCD { diff --git a/Processors/68000/68000.hpp b/Processors/68000/68000.hpp index bfe4e6e15..a179e247c 100644 --- a/Processors/68000/68000.hpp +++ b/Processors/68000/68000.hpp @@ -157,12 +157,28 @@ class BusHandler { class ProcessorBase: public ProcessorStorage { }; +struct ProcessorState { + uint32_t data[8]; + uint32_t address[7]; + uint32_t user_stack_pointer, supervisor_stack_pointer; + uint32_t program_counter; + uint16_t status; + + // TODO: More state needed to indicate current instruction, the processor's + // progress through it, and anything it has fetched so far. +// uint16_t current_instruction; +}; + template class Processor: public ProcessorBase { public: Processor(T &bus_handler) : ProcessorBase(), bus_handler_(bus_handler) {} void run_for(HalfCycles duration); + using State = ProcessorState; + State get_state(); + void set_state(const State &); + private: T &bus_handler_; }; diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index ba31eea5f..f033d5c37 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -93,7 +93,7 @@ template void Processor: int result = (destination & 0xf) + (source & 0xf) + (extend_flag_ ? 1 : 0); if(result > 0x9) result += 0x06; result += (destination & 0xf0) + (source & 0xf0); - if(result > 0x90) result += 0x60; + if((result&0xff0) > 0x90) result += 0x60; // Set all flags essentially as if this were normal addition. zero_flag_ |= result & 0xff; @@ -114,7 +114,7 @@ template void Processor: int result = (destination & 0xf) - (source & 0xf) - (extend_flag_ ? 1 : 0); if(result > 0x9) result -= 0x06; result += (destination & 0xf0) - (source & 0xf0); - if(result > 0x90) result -= 0x60; + if((result&0xff0) > 0x90) result -= 0x60; // Set all flags essentially as if this were normal subtraction. zero_flag_ |= result & 0xff; @@ -176,3 +176,26 @@ template void Processor: } } } + +template ProcessorState Processor::get_state() { + write_back_stack_pointer(); + + State state; + memcpy(state.data, data_, sizeof(state.data)); + memcpy(state.address, address_, sizeof(state.address)); + state.user_stack_pointer = stack_pointers_[0].full; + state.supervisor_stack_pointer = stack_pointers_[1].full; + + // TODO: status word. + + return state; +} + +template void Processor::set_state(const ProcessorState &state) { + memcpy(data_, state.data, sizeof(state.data)); + memcpy(address_, state.address, sizeof(state.address)); + stack_pointers_[0].full = state.user_stack_pointer; + stack_pointers_[1].full = state.supervisor_stack_pointer; + + // TODO: update address[7], once there's a status word to discern the mode this processor should now be in. +} diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index 98fec40f4..cc3e1e978 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -388,7 +388,7 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() { ProcessorStorageConstructor constructor(*this); // Create the exception programs. - const size_t reset_offset = constructor.assemble_program("n- n- n- n- n- nn nF nf nV nv np np"); + const size_t reset_offset = constructor.assemble_program("n n n n n nn nF nf nV nv np np"); // Install operations. constructor.install_instructions(); @@ -401,3 +401,16 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() { effective_address_ = 0; is_supervisor_ = 1; } + +void CPU::MC68000::ProcessorStorage::write_back_stack_pointer() { + stack_pointers_[is_supervisor_] = address_[7]; +} + +void CPU::MC68000::ProcessorStorage::set_is_supervisor(bool is_supervisor) { + const int new_is_supervisor = is_supervisor ? 1 : 0; + if(new_is_supervisor != is_supervisor_) { + stack_pointers_[is_supervisor_] = address_[7]; + is_supervisor_ = new_is_supervisor; + address_[7] = stack_pointers_[is_supervisor_]; + } +} diff --git a/Processors/68000/Implementation/68000Storage.hpp b/Processors/68000/Implementation/68000Storage.hpp index 602bc13d4..37819b368 100644 --- a/Processors/68000/Implementation/68000Storage.hpp +++ b/Processors/68000/Implementation/68000Storage.hpp @@ -141,6 +141,12 @@ class ProcessorStorage { MicroOp *active_micro_op_ = nullptr; BusStep *active_step_ = nullptr; + /// Copies address_[7] to the proper stack pointer based on current mode. + void write_back_stack_pointer(); + + /// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated. + void set_is_supervisor(bool); + private: friend class ProcessorStorageConstructor; };