From 0418f51ef2b725c3245211230126752e531a482b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 8 Oct 2020 17:52:13 -0400 Subject: [PATCH] Takes a shot at emulation-mode 'exceptions'. It's just RTI and correct decimal SBC left of the official 6502s now, I think. --- .../Bridges/TestMachine6502.mm | 1 - .../Clock SignalTests/KlausDormannTests.swift | 4 +- Processors/6502/AllRAM/6502AllRAM.cpp | 15 +++++- .../Implementation/65816Implementation.hpp | 46 +++++++++++++++++-- .../65816/Implementation/65816Storage.cpp | 24 ++++++++-- .../65816/Implementation/65816Storage.hpp | 4 -- 6 files changed, 80 insertions(+), 14 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm index a941f4d82..f25bbbe8c 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm @@ -9,7 +9,6 @@ #import "TestMachine6502.h" #include #include "../../../../Processors/6502/AllRAM/6502AllRAM.hpp" -//#include "../../../../Processors/65816/AllRAM/65816AllRAM.hpp" #import "TestMachine+ForSubclassEyesOnly.h" const uint8_t CSTestMachine6502JamOpcode = CPU::MOS6502::JamOpcode; diff --git a/OSBindings/Mac/Clock SignalTests/KlausDormannTests.swift b/OSBindings/Mac/Clock SignalTests/KlausDormannTests.swift index 4dcfdf51c..bf22e17eb 100644 --- a/OSBindings/Mac/Clock SignalTests/KlausDormannTests.swift +++ b/OSBindings/Mac/Clock SignalTests/KlausDormannTests.swift @@ -55,7 +55,9 @@ class KlausDormannTests: XCTestCase { case 0x36ac, 0x36f6: return "Improper JSR return address on stack" case 0x36c6: return "Unexpected RESET" case 0x36d1: return "BRK: unexpected BRK or IRQ" - case 0x36e5: return "BRK flag not set on stack" + case 0x36e5: return "BRK flag not set on stack following BRK" + case 0x36ea: return "BRK did not set the I flag" + case 0x36fd: return "Wrong address put on stack by BRK" case 0: return "Didn't find tests" diff --git a/Processors/6502/AllRAM/6502AllRAM.cpp b/Processors/6502/AllRAM/6502AllRAM.cpp index 793fb5eff..f59b68272 100644 --- a/Processors/6502/AllRAM/6502AllRAM.cpp +++ b/Processors/6502/AllRAM/6502AllRAM.cpp @@ -11,6 +11,8 @@ #include #include +#define BE_NOISY + using namespace CPU::MOS6502; namespace { @@ -28,20 +30,31 @@ template class ConcreteAllRAMProcessor: public AllRAMProcessor, publ timestamp_ += Cycles(1); if(operation == BusOperation::ReadOpcode) { - // TEMPORARY LOGGING. TODO: remove. +#ifdef BE_NOISY printf("[%04x] %02x a:%04x x:%04x y:%04x p:%02x s:%02x\n", address, memory_[address], mos6502_.get_value_of_register(Register::A), mos6502_.get_value_of_register(Register::X), mos6502_.get_value_of_register(Register::Y), mos6502_.get_value_of_register(Register::Flags) & 0xff, mos6502_.get_value_of_register(Register::StackPointer) & 0xff); +#endif check_address_for_trap(address); } if(isReadOperation(operation)) { *value = memory_[address]; +#ifdef BE_NOISY + if((address&0xff00) == 0x100) { + printf("%04x -> %02x\n", address, *value); + } +#endif } else { memory_[address] = *value; +#ifdef BE_NOISY + if((address&0xff00) == 0x100) { + printf("%04x <- %02x\n", address, *value); + } +#endif } return Cycles(1); diff --git a/Processors/65816/Implementation/65816Implementation.hpp b/Processors/65816/Implementation/65816Implementation.hpp index 5028e97ac..6aa9543b8 100644 --- a/Processors/65816/Implementation/65816Implementation.hpp +++ b/Processors/65816/Implementation/65816Implementation.hpp @@ -296,6 +296,49 @@ template void Processor::run_for(const Cycles data_address_ = data_bank_ + (instruction_buffer_.value + y()) & 0xffff; continue; + case OperationPrepareException: { + // Put the proper exception vector into the data address, put the flags and PC + // into the data buffer (possibly also PBR), and skip an instruction if in + // emulation mode. + + bool is_brk = false; + + if(pending_exceptions_ & (Reset | PowerOn)) { + // TODO: set emulation mode, etc. + pending_exceptions_ &= ~(Reset | PowerOn); + data_address_ = 0xfffc; + } else if(pending_exceptions_ & NMI) { + pending_exceptions_ &= ~NMI; + data_address_ = 0xfffa; + } else if(pending_exceptions_ & IRQ) { + pending_exceptions_ &= ~IRQ; + data_address_ = 0xfffe; + } else { + is_brk = active_instruction_ == instructions; + if(is_brk) { + data_address_ = emulation_flag_ ? 0xfffe : 0xfff6; + } else { + // Implicitly: COP. + data_address_ = 0xfff4; + } + } + + data_buffer_.value = (pc_ << 8) | flags_.get(); + if(emulation_flag_) { + if(is_brk) data_buffer_.value |= Flag::Break; + data_buffer_.size = 3; + ++next_op_; + } else { + data_buffer_.value |= program_bank_ << 24; + data_buffer_.size = 4; + program_bank_ = 0; + + assert(false); // TODO: proper flags, still. + } + + flags_.inverse_interrupt = 0; + } continue; + // // Performance. // @@ -687,7 +730,6 @@ template void Processor::run_for(const Cycles // XCE, XBA, // STP, WAI, // RTI, RTL, - // BRK, // TCD, TCS, TDC, TSC default: @@ -695,8 +737,6 @@ template void Processor::run_for(const Cycles } continue; - // TODO: OperationPrepareException - default: assert(false); } diff --git a/Processors/65816/Implementation/65816Storage.cpp b/Processors/65816/Implementation/65816Storage.cpp index cb83334bc..7ef6e22eb 100644 --- a/Processors/65816/Implementation/65816Storage.cpp +++ b/Processors/65816/Implementation/65816Storage.cpp @@ -111,7 +111,7 @@ struct CPU::WDC65816::ProcessorStorageConstructor { const auto map_entry = installed_patterns.find(key); storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[0] = storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[1] = uint16_t(map_entry->second.first); - storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].operation = BRK; + storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].operation = JMPind; } void install_fetch_decode_execute() { @@ -579,6 +579,7 @@ struct CPU::WDC65816::ProcessorStorageConstructor { target(CyclePush); // PCL target(CyclePush); // P + // TODO: I think I need a seperate vector fetch here, to signal vector pull? target(CycleFetchIncrementData); // AAVL target(CycleFetchData); // AAVH @@ -677,8 +678,23 @@ struct CPU::WDC65816::ProcessorStorageConstructor { } // 22j. Stack; s, BRK/COP. + static void brk_cop(AccessType, bool, const std::function &target) { + target(CycleFetchIncrementPC); // Signature. - // Covered by stack_exception. + target(OperationPrepareException); // Populates the data buffer; this skips a micro-op if + // in emulation mode. + + target(CyclePush); // PBR [skipped in emulation mode] + target(CyclePush); // PCH + target(CyclePush); // PCL + target(CyclePush); // P + + // TODO: I think I need a seperate vector fetch here, to signal vector pull? + target(CycleFetchIncrementData); // AAVL + target(CycleFetchData); // AAVH + + target(OperationPerform); // Jumps to the vector address. + } // 23. Stack Relative; d, s. static void stack_relative(AccessType type, bool is8bit, const std::function &target) { @@ -710,9 +726,9 @@ ProcessorStorage::ProcessorStorage() { // Install the instructions. #define op(x, y) constructor.install(&ProcessorStorageConstructor::x, y) - /* 0x00 BRK s */ op(stack_exception, BRK); + /* 0x00 BRK s */ op(brk_cop, JMPind); /* 0x01 ORA (d, x) */ op(direct_indexed_indirect, ORA); - /* 0x02 COP s */ op(stack_exception, BRK); + /* 0x02 COP s */ op(brk_cop, JMPind); /* 0x03 ORA d, s */ op(stack_relative, ORA); /* 0x04 TSB d */ op(direct_rmw, TSB); /* 0x05 ORA d */ op(direct, ORA); diff --git a/Processors/65816/Implementation/65816Storage.hpp b/Processors/65816/Implementation/65816Storage.hpp index 168cf2455..1e6fb03da 100644 --- a/Processors/65816/Implementation/65816Storage.hpp +++ b/Processors/65816/Implementation/65816Storage.hpp @@ -193,10 +193,6 @@ enum Operation: uint8_t { /// Loads the PC with the contents of the data buffer + 1. RTS, - - /// i.e. jump to vector. TODO: is this really distinct from JMP? I'm assuming so for now, - /// as I assume the PBR is implicitly modified. But then is it just JML? We'll see. - BRK, }; class ProcessorStorageConstructor;