From c6e4cd1702689962a9a3b60100a814ee6565ab9e Mon Sep 17 00:00:00 2001 From: Anonymus Raccoon Date: Thu, 14 May 2020 15:51:48 +0200 Subject: [PATCH 1/4] Fixing a segfault with the bus & cpu's debugger together --- sources/CPU/CPU.cpp | 2 -- sources/CPU/CPU.hpp | 2 +- sources/Debugger/CPU/CPUDebug.cpp | 19 ++++++++++++++----- sources/Debugger/CPU/CPUDebug.hpp | 10 ++++++++-- ui/ui_cpu.h | 2 +- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index 8116408..cd9ddca 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -6,9 +6,7 @@ #include #include -#include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/InvalidAddress.hpp" -#include "../Exceptions/InvalidOpcode.hpp" namespace ComSquare::CPU { diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 26dde23..f127d41 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -713,7 +713,7 @@ namespace ComSquare::CPU virtual bool isDebugger(); //! @brief Change the memory bus used by the CPU. - void setMemoryBus(std::shared_ptr bus); + virtual void setMemoryBus(std::shared_ptr bus); }; } diff --git a/sources/Debugger/CPU/CPUDebug.cpp b/sources/Debugger/CPU/CPUDebug.cpp index 5be3734..6bcb800 100644 --- a/sources/Debugger/CPU/CPUDebug.cpp +++ b/sources/Debugger/CPU/CPUDebug.cpp @@ -5,11 +5,9 @@ #include "CPUDebug.hpp" #include "../../Utility/Utility.hpp" #include "../../Exceptions/InvalidOpcode.hpp" -#include "../../CPU/CPU.hpp" #include #include #include -#include using namespace ComSquare::CPU; @@ -21,7 +19,7 @@ namespace ComSquare::Debugger _ui(), _model(*this), _painter(*this), - _stackModel(*this->_bus, *this), + _stackModel(this->_bus, *this), _snes(snes) { this->_window->setContextMenuPolicy(Qt::NoContextMenu); @@ -70,6 +68,12 @@ namespace ComSquare::Debugger this->_snes.disableCPUDebugging(); } + void CPUDebug::setMemoryBus(std::shared_ptr bus) + { + this->_stackModel.setMemoryBus(bus); + CPU::setMemoryBus(bus); + } + unsigned CPUDebug::update() { try { @@ -379,7 +383,12 @@ QSize RowPainter::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) co return QSize(); } -StackModel::StackModel(ComSquare::Memory::MemoryBus &bus, ComSquare::Debugger::CPUDebug &cpu) : _bus(bus), _cpu(cpu) { } +StackModel::StackModel(std::shared_ptr bus, ComSquare::Debugger::CPUDebug &cpu) : _bus(bus), _cpu(cpu) { } + +void StackModel::setMemoryBus(std::shared_ptr bus) +{ + this->_bus = std::move(bus); +} int StackModel::rowCount(const QModelIndex &) const { @@ -405,7 +414,7 @@ QVariant StackModel::data(const QModelIndex &index, int role) const return QVariant(); uint16_t addr = index.row() * 2 + index.column(); try { - uint8_t value = this->_bus.read(addr); + uint8_t value = this->_bus->read(addr); return (ComSquare::Utility::to_hex(value, ComSquare::Utility::NoPrefix).c_str()); } catch (std::exception &) { return "??"; diff --git a/sources/Debugger/CPU/CPUDebug.hpp b/sources/Debugger/CPU/CPUDebug.hpp index ab596d0..db00d37 100644 --- a/sources/Debugger/CPU/CPUDebug.hpp +++ b/sources/Debugger/CPU/CPUDebug.hpp @@ -34,10 +34,10 @@ class StackModel : public QAbstractTableModel { Q_OBJECT private: - ComSquare::Memory::MemoryBus &_bus; + std::shared_ptr _bus; ComSquare::Debugger::CPUDebug &_cpu; public: - explicit StackModel(ComSquare::Memory::MemoryBus &bus, ComSquare::Debugger::CPUDebug &cpu); + explicit StackModel(std::shared_ptr bus, ComSquare::Debugger::CPUDebug &cpu); StackModel(const StackModel &) = delete; const StackModel &operator=(const StackModel &) = delete; ~StackModel() override = default; @@ -50,6 +50,9 @@ public: QVariant data(const QModelIndex &index, int role) const override; //! @brief Override the headers to use hex values. QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + //! @brief Change the memory bus used by the view. + void setMemoryBus(std::shared_ptr bus); }; //! @brief The qt model that show the history. @@ -285,6 +288,9 @@ namespace ComSquare::Debugger //! @brief Override the basic cpu's update to allow pausing of the CPU only. unsigned update() override; + + //! @brief Change the memory bus used by the CPU. + void setMemoryBus(std::shared_ptr bus) override; }; } diff --git a/ui/ui_cpu.h b/ui/ui_cpu.h index 97769dd..b7aafd0 100644 --- a/ui/ui_cpu.h +++ b/ui/ui_cpu.h @@ -1,7 +1,7 @@ /******************************************************************************** ** Form generated from reading UI file 'cpu.ui' ** -** Created by: Qt User Interface Compiler version 5.14.1 +** Created by: Qt User Interface Compiler version 5.14.2 ** ** WARNING! All changes made in this file will be lost when recompiling UI file! ********************************************************************************/ From 5f0ed5f5614f1f36b7552a4317ad19a41ae98253 Mon Sep 17 00:00:00 2001 From: Anonymus Raccoon Date: Thu, 14 May 2020 17:37:06 +0200 Subject: [PATCH 2/4] Adding the WAI and handling NMI & IRQ interrupts --- sources/CPU/CPU.cpp | 35 ++++++++++++++++++++--- sources/CPU/CPU.hpp | 24 ++++++++++++++-- sources/CPU/Instructions/Interrupts.cpp | 38 ++++++++++++------------- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index 4f2a727..88ce592 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -205,13 +205,40 @@ namespace ComSquare::CPU { unsigned cycles = 0; - if (this->_isStopped) - return 0xFF; - for (int i = 0; i < 0xFF; i++) - cycles += this->_executeInstruction(this->readPC()); + for (int i = 0; i < 0xFF; i++) { + if (this->_isStopped) { + cycles += 1; + continue; + } + + this->_checkInterrupts(); + + if (!this->_isWaitingForInterrupt) + cycles += this->_executeInstruction(this->readPC()); + } return cycles; } + void CPU::_checkInterrupts() + { + if (!this->IsNMIRequested && !this->IsIRQRequested && !this->IsAbortRequested) + return; + this->_isWaitingForInterrupt = false; + + if (this->IsNMIRequested) { + this->_runInterrupt( + this->_cartridgeHeader.nativeInterrupts.nmi, + this->_cartridgeHeader.emulationInterrupts.nmi); + return; + } + if (this->IsIRQRequested && !this->_registers.p.i) { + this->_runInterrupt( + this->_cartridgeHeader.nativeInterrupts.irq, + this->_cartridgeHeader.emulationInterrupts.irq); + return; + } + } + uint24_t CPU::_getValueAddr(Instruction &instruction) { switch (instruction.addressingMode) { diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 2b95861..808796b 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -186,12 +186,16 @@ namespace ComSquare::CPU protected: //! @brief All the registers of the CPU Registers _registers{}; + //! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F). + InternalRegisters _internalRegisters{}; + //! @brief Is the CPU running in emulation mode (in 8bits) bool _isEmulationMode = true; //! @brief If the processor is stopped (using an STP instruction), the clock is stopped and no instruction will be run until a manual reset. bool _isStopped = false; - //! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F). - InternalRegisters _internalRegisters{}; + //! @brief Is the processor waiting for an interrupt (if true, instructions are not run until an interrupt is requested). + bool _isWaitingForInterrupt = false; + //! @brief The memory bus to use for read/write. std::shared_ptr _bus; //! @brief The cartridge header (stored for interrupt vectors.. @@ -258,6 +262,11 @@ namespace ComSquare::CPU //! @brief Return the data at the program bank concatenated with the program counter. It also increment the program counter (the program bank is not incremented on overflows). uint8_t readPC(); + //! @brief Check if an interrupt is requested and handle it. + void _checkInterrupts(); + //! @brief Run an interrupt (save state of the processor and jump to the interrupt handler) + void _runInterrupt(uint24_t nativeHandler, uint24_t emulationHandler); + //! @brief Execute a single instruction. //! @return The number of CPU cycles that the instruction took. virtual unsigned _executeInstruction(uint8_t opcode); @@ -443,6 +452,8 @@ namespace ComSquare::CPU int PEA(uint24_t, AddressingMode); //! @brief Stop the processor int STP(uint24_t, AddressingMode); + //! @brief Wait for Interrupt + int WAI(uint24_t, AddressingMode); //! @brief WDM Reserved for Future Expansion (used as a code breakpoint) int WDM(uint24_t, AddressingMode); //! @brief Block Move Next. This instruction is special: it takes parameter in the registers @@ -662,7 +673,7 @@ namespace ComSquare::CPU {&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8 {&CPU::CMP, 2, "cmp", AddressingMode::ImmediateForA, 2}, // C9 {&CPU::DEX, 2, "dex", AddressingMode::Implied, 1}, // CA - {&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB + {&CPU::WAI, 3, "wai", AddressingMode::Implied, 1}, // CB {&CPU::CPY, 4, "cpy", AddressingMode::Absolute, 3}, // CC {&CPU::CMP, 4, "cmp", AddressingMode::Absolute, 3}, // CD {&CPU::DEC, 6, "dec", AddressingMode::Absolute, 3}, // CE @@ -744,6 +755,13 @@ namespace ComSquare::CPU //! @brief Reset interrupt - Called on boot and when the reset button is pressed. virtual int RESB(); + //! @brief Is an NMI (non-maskable interrupt) requested. + bool IsNMIRequested = false; + //! @brief Is an interrupt (maskable) requested. + bool IsIRQRequested = false; + //! @brief Is an abort requested + bool IsAbortRequested = false; + //! @brief Return true if the CPU is overloaded with debugging features. virtual bool isDebugger(); diff --git a/sources/CPU/Instructions/Interrupts.cpp b/sources/CPU/Instructions/Interrupts.cpp index 8f8d515..f084ce0 100644 --- a/sources/CPU/Instructions/Interrupts.cpp +++ b/sources/CPU/Instructions/Interrupts.cpp @@ -22,7 +22,7 @@ namespace ComSquare::CPU return 0; } - int CPU::BRK(uint24_t, AddressingMode) + void CPU::_runInterrupt(uint24_t nativeHandler, uint24_t emulationHandler) { if (this->_isEmulationMode) { this->_push(this->_registers.pc); @@ -30,7 +30,7 @@ namespace ComSquare::CPU this->_registers.p.i = true; this->_registers.p.d = false; this->_registers.pbr = 0x0; - this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.brk; + this->_registers.pc = emulationHandler; } else { this->_push(this->_registers.pbr); this->_push(this->_registers.pc); @@ -38,29 +38,23 @@ namespace ComSquare::CPU this->_registers.p.i = true; this->_registers.p.d = false; this->_registers.pbr = 0x0; - this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk; + this->_registers.pc = nativeHandler; } + } + + int CPU::BRK(uint24_t, AddressingMode) + { + this->_runInterrupt( + this->_cartridgeHeader.nativeInterrupts.brk, + this->_cartridgeHeader.emulationInterrupts.brk); return !this->_isEmulationMode; } int CPU::COP(uint24_t, AddressingMode) { - if (this->_isEmulationMode) { - this->_push(this->_registers.pc); - this->_push(this->_registers.p.flags); - this->_registers.p.i = true; - this->_registers.p.d = false; - this->_registers.pbr = 0x0; - this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.cop; - } else { - this->_push(this->_registers.pbr); - this->_push(this->_registers.pc); - this->_push(this->_registers.p.flags); - this->_registers.p.i = true; - this->_registers.p.d = false; - this->_registers.pbr = 0x0; - this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.cop; - } + this->_runInterrupt( + this->_cartridgeHeader.nativeInterrupts.cop, + this->_cartridgeHeader.emulationInterrupts.cop); return !this->_isEmulationMode; } @@ -73,4 +67,10 @@ namespace ComSquare::CPU this->_registers.pbr = this->_pop16(); return !this->_isEmulationMode; } + + int CPU::WAI(uint24_t, AddressingMode) + { + this->_isWaitingForInterrupt = true; + return 0; + } } \ No newline at end of file From efbf009f218b1366d29733d35b00fbca3fc177dd Mon Sep 17 00:00:00 2001 From: Anonymus Raccoon Date: Thu, 14 May 2020 17:58:47 +0200 Subject: [PATCH 3/4] Oups --- sources/CPU/CPU.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index 3c4c248..88ce592 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -7,6 +7,7 @@ #include #include #include "../Exceptions/InvalidAddress.hpp" +#include "../Exceptions/InvalidOpcode.hpp" namespace ComSquare::CPU { From 24bcafeea3896022704904815d263f69f22e5096 Mon Sep 17 00:00:00 2001 From: Anonymus Raccoon Date: Thu, 14 May 2020 18:12:29 +0200 Subject: [PATCH 4/4] Removing unintended logs to the bus's debugger --- sources/Debugger/CPU/CPUDebug.cpp | 2 +- sources/Debugger/CPU/Disassembly.cpp | 10 +++++----- sources/Debugger/MemoryBusDebug.cpp | 2 +- sources/SNES.cpp | 1 - 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/sources/Debugger/CPU/CPUDebug.cpp b/sources/Debugger/CPU/CPUDebug.cpp index 6bcb800..d677158 100644 --- a/sources/Debugger/CPU/CPUDebug.cpp +++ b/sources/Debugger/CPU/CPUDebug.cpp @@ -414,7 +414,7 @@ QVariant StackModel::data(const QModelIndex &index, int role) const return QVariant(); uint16_t addr = index.row() * 2 + index.column(); try { - uint8_t value = this->_bus->read(addr); + uint8_t value = this->_bus->read(addr, true); return (ComSquare::Utility::to_hex(value, ComSquare::Utility::NoPrefix).c_str()); } catch (std::exception &) { return "??"; diff --git a/sources/Debugger/CPU/Disassembly.cpp b/sources/Debugger/CPU/Disassembly.cpp index 7541dd7..75aefd2 100644 --- a/sources/Debugger/CPU/Disassembly.cpp +++ b/sources/Debugger/CPU/Disassembly.cpp @@ -42,13 +42,13 @@ namespace ComSquare::Debugger ctx.mFlag = true; ctx.xFlag = true; } else { - uint8_t m = this->_bus->read(pc - 1); + uint8_t m = this->_bus->read(pc - 1, true); ctx.mFlag &= ~m & 0b00100000u; ctx.xFlag &= ~m & 0b00010000u; } } if (instruction.opcode == 0xE2) { // SEP - uint8_t m = this->_bus->read(pc - 1); + uint8_t m = this->_bus->read(pc - 1, true); ctx.mFlag |= m & 0b00100000u; ctx.xFlag |= m & 0b00010000u; } @@ -150,7 +150,7 @@ namespace ComSquare::Debugger std::string CPUDebug::_getAbsoluteValue(uint24_t pc) { - uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u); + uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u); return Utility::to_hex(value, Utility::HexString::AsmPrefix); } @@ -193,13 +193,13 @@ namespace ComSquare::Debugger std::string CPUDebug::_getAbsoluteIndexByXValue(uint24_t pc) { - uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u); + uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u); return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x"; } std::string CPUDebug::_getAbsoluteIndexByYValue(uint24_t pc) { - uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u); + uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u); return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", y"; } diff --git a/sources/Debugger/MemoryBusDebug.cpp b/sources/Debugger/MemoryBusDebug.cpp index 670f484..51bbc4c 100644 --- a/sources/Debugger/MemoryBusDebug.cpp +++ b/sources/Debugger/MemoryBusDebug.cpp @@ -150,7 +150,7 @@ namespace ComSquare::Debugger uint8_t MemoryBusDebug::read(uint24_t addr, bool silence) { - if (!silence && !forceSilence) { + if (!silence && !this->forceSilence) { auto accessor = this->getAccessor(addr); if (!accessor) { this->_model.log(BusLog(true, addr, accessor, this->_openBus, this->_openBus)); diff --git a/sources/SNES.cpp b/sources/SNES.cpp index a57cd5a..bb6d7aa 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -3,7 +3,6 @@ // #include -#include #include "SNES.hpp" #ifdef DEBUGGER_ENABLED #include "Debugger/CPU/CPUDebug.hpp"