diff --git a/CMakeLists.txt b/CMakeLists.txt index e12549a..bdf401a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,11 @@ add_executable(unit_tests sources/APU/Instructions/Stack.cpp sources/APU/Instructions/Subroutine.cpp sources/APU/Instructions/ProgramFlow.cpp - tests/CPU/Math/testSBC.cpp sources/CPU/Instructions/TransferRegisters.cpp tests/CPU/TransferRegisters.cpp) + tests/CPU/Math/testSBC.cpp + sources/CPU/Instructions/TransferRegisters.cpp + tests/CPU/TransferRegisters.cpp + sources/CPU/AddressingModes.cpp +) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) @@ -95,7 +99,7 @@ set(CMAKE_AUTOUIC ON) # make app add_executable(ComSquare - main.cpp + sources/main.cpp sources/SNES.cpp sources/SNES.hpp sources/Memory/MemoryBus.cpp @@ -166,7 +170,12 @@ add_executable(ComSquare sources/APU/Instructions/Stack.cpp sources/APU/Instructions/Subroutine.cpp sources/APU/Instructions/ProgramFlow.cpp - sources/CPU/Instructions/TransferRegisters.cpp) + sources/CPU/Instructions/TransferRegisters.cpp + sources/CPU/AddressingModes.cpp + sources/Debugger/MemoryBusDebug.cpp + sources/Debugger/MemoryBusDebug.hpp + sources/Debugger/ClosableWindow.hpp +) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/CPU/AddressingModes.cpp b/sources/CPU/AddressingModes.cpp new file mode 100644 index 0000000..cbe52ff --- /dev/null +++ b/sources/CPU/AddressingModes.cpp @@ -0,0 +1,184 @@ +// +// Created by anonymus-raccoon on 3/20/20. +// + +#include "../Models/Int24.hpp"$ +#include "CPU.hpp" + +namespace ComSquare::CPU +{ + uint24_t CPU::_getImmediateAddrForA() + { + uint24_t effective = this->_registers.pac++; + if (!this->_registers.p.m) + this->_registers.pac++; + return effective; + } + + uint24_t CPU::_getImmediateAddrForX() + { + uint24_t effective = this->_registers.pac++; + if (!this->_registers.p.x_b) + this->_registers.pac++; + return effective; + } + + uint24_t CPU::_getDirectAddr() + { + uint8_t addr = this->_bus->read(this->_registers.pac++); + return this->_registers.d + addr; + } + + uint24_t CPU::_getAbsoluteAddr() + { + uint24_t addr = this->_registers.dbr << 16u; + addr += this->_bus->read(this->_registers.pac++); + addr += this->_bus->read(this->_registers.pac++) << 8u; + return addr; + } + + uint24_t CPU::_getAbsoluteLongAddr() + { + uint24_t addr = this->_bus->read(this->_registers.pac++); + addr += this->_bus->read(this->_registers.pac++) << 8u; + addr += this->_bus->read(this->_registers.pac++) << 16u; + return addr; + } + + uint24_t CPU::_getDirectIndirectIndexedYAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + uint24_t base = this->_bus->read(dp); + base += this->_bus->read(dp + 1) << 8u; + base += this->_registers.dbr << 16u; + if ((base & 0x80000000u) == (((base + this->_registers.y) & 0x80000000u))) + this->_hasIndexCrossedPageBoundary = true; + return base + this->_registers.y; + } + + uint24_t CPU::_getDirectIndirectIndexedYLongAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + uint24_t base = this->_bus->read(dp); + base += this->_bus->read(dp + 1) << 8u; + base += this->_bus->read(dp + 2) << 16u; + return base; + } + + uint24_t CPU::_getDirectIndirectIndexedXAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + dp += this->_registers.x; + uint24_t base = this->_bus->read(dp); + base += this->_bus->read(dp + 1) << 8u; + base += this->_registers.dbr << 16u; + return base; + } + + uint24_t CPU::_getDirectIndexedByXAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + dp += this->_registers.x; + return dp; + } + + uint24_t CPU::_getDirectIndexedByYAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + dp += this->_registers.y; + return dp; + } + + uint24_t CPU::_getAbsoluteIndexedByXAddr() + { + uint16_t abs = this->_bus->read(this->_registers.pac++); + abs += this->_bus->read(this->_registers.pac++) << 8u; + uint24_t effective = abs + (this->_registers.dbr << 16u); + if ((effective & 0x80000000u) == (((effective + this->_registers.x) & 0x80000000u))) + this->_hasIndexCrossedPageBoundary = true; + return effective + this->_registers.x; + } + + uint24_t CPU::_getAbsoluteIndexedByYAddr() + { + uint16_t abs = this->_bus->read(this->_registers.pac++); + abs += this->_bus->read(this->_registers.pac++) << 8u; + uint24_t effective = abs + (this->_registers.dbr << 16u); + if ((effective & 0x80000000u) == (((effective + this->_registers.y) & 0x80000000u))) + this->_hasIndexCrossedPageBoundary = true; + return effective + this->_registers.y; + } + + uint24_t CPU::_getAbsoluteIndexedByXLongAddr() + { + uint24_t lng = this->_bus->read(this->_registers.pac++); + lng += this->_bus->read(this->_registers.pac++) << 8u; + lng += this->_bus->read(this->_registers.pac++) << 16u; + return lng + this->_registers.x; + } + + uint24_t CPU::_getProgramCounterRelativeAddr() + { + uint24_t pc = this->_registers.pac; + int8_t mod = this->_bus->read(this->_registers.pac++); + return pc + mod; + } + + uint24_t CPU::_getProgramCounterRelativeLongAddr() + { + uint24_t pc = this->_registers.pac; + uint8_t val1 = this->_bus->read(this->_registers.pac++); + uint8_t val2 = this->_bus->read(this->_registers.pac++); + int16_t mod = val2 > 0x7F ? (static_cast(val2) * 256 - val1) : (val1 | val2 << 8u); + return pc + mod; + } + + uint24_t CPU::_getAbsoluteIndirectAddr() + { + uint16_t abs = this->_bus->read(this->_registers.pac++); + abs += this->_bus->read(this->_registers.pac++) << 8u; + uint24_t effective = this->_bus->read(abs); + effective += this->_bus->read(abs + 1) << 8u; + return effective; + } + + uint24_t CPU::_getAbsoluteIndirectIndexedByXAddr() + { + uint24_t abs = this->_bus->read(this->_registers.pac++); + abs += this->_bus->read(this->_registers.pac++) << 8u; + abs += this->_registers.x; + uint24_t effective = this->_bus->read(abs); + effective += this->_bus->read(abs + 1) << 8u; + return effective; + } + + uint24_t CPU::_getDirectIndirectAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + uint24_t effective = this->_bus->read(dp); + effective += this->_bus->read(dp + 1) << 8u; + effective += this->_registers.dbr << 16u; + return effective; + } + + uint24_t CPU::_getDirectIndirectLongAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + uint24_t effective = this->_bus->read(dp); + effective += this->_bus->read(++dp) << 8u; + effective += this->_bus->read(++dp) << 16u; + return effective; + } + + uint24_t CPU::_getStackRelativeAddr() + { + return this->_bus->read(this->_registers.pac++) + this->_registers.s; + } + + uint24_t CPU::_getStackRelativeIndirectIndexedYAddr() + { + uint24_t base = this->_bus->read(this->_registers.pac++) + this->_registers.s; + base += this->_registers.dbr << 16u; + return base + this->_registers.y; + } +} \ No newline at end of file diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index ffc2647..5a81b0f 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -18,6 +18,11 @@ namespace ComSquare::CPU this->RESB(); } + void CPU::setMemoryBus(std::shared_ptr bus) + { + this->_bus = std::move(bus); + } + //! @bref The CPU's internal registers starts at $4200 and finish at $421F. uint8_t CPU::read(uint24_t addr) { @@ -204,9 +209,9 @@ namespace ComSquare::CPU case Instructions::COP: this->COP(); return 7 + !this->_isEmulationMode; - case Instructions::RTI: this->RTI(); return 6 + !this->_isEmulationMode; + case Instructions::RTI: this->RTI(); return 6 + !this->_isEmulationMode; - case Instructions::ADC_IM: this->ADC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; + case Instructions::ADC_IM: this->ADC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; case Instructions::ADC_ABS: this->ADC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; case Instructions::ADC_ABSl: this->ADC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; case Instructions::ADC_DP: this->ADC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; @@ -250,7 +255,7 @@ namespace ComSquare::CPU case Instructions::STZ_ABSX: this->STX(this->_getAbsoluteIndexedByXAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; case Instructions::STZ_DPX: this->STX(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDA_IM: this->LDA(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; + case Instructions::LDA_IM: this->LDA(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; case Instructions::LDA_ABS: this->LDA(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; case Instructions::LDA_ABSl: this->LDA(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; case Instructions::LDA_DP: this->LDA(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; @@ -266,13 +271,13 @@ namespace ComSquare::CPU case Instructions::LDA_SR: this->LDA(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; case Instructions::LDA_SRYi: this->LDA(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; - case Instructions::LDX_IM: this->LDX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; + case Instructions::LDX_IM: this->LDX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; case Instructions::LDX_ABS: this->LDX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; case Instructions::LDX_DP: this->LDX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; case Instructions::LDX_ABSY: this->LDX(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; case Instructions::LDX_DPY: this->LDX(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDY_IM: this->LDY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; + case Instructions::LDY_IM: this->LDY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; case Instructions::LDY_ABS: this->LDY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; case Instructions::LDY_DP: this->LDY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; case Instructions::LDY_ABSY: this->LDY(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; @@ -311,7 +316,7 @@ namespace ComSquare::CPU case Instructions::SED: this->SED(); return 2; case Instructions::SEI: this->SEI(); return 2; - case Instructions::AND_IM: this->AND(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; + case Instructions::AND_IM: this->AND(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; case Instructions::AND_ABS: this->AND(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; case Instructions::AND_ABSl: this->AND(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; case Instructions::AND_DP: this->AND(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; @@ -352,13 +357,13 @@ namespace ComSquare::CPU case Instructions::INX: this->INX(); return 2; case Instructions::INY: this->INY(); return 2; - case Instructions::CPX_IM: this->CPX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; - case Instructions::CPX_ABS: this->CPX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::CPX_DP: this->CPX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; + case Instructions::CPX_IM: this->CPX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; + case Instructions::CPX_ABS: this->CPX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; + case Instructions::CPX_DP: this->CPX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::CPY_IM: this->CPY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; - case Instructions::CPY_ABS: this->CPY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::CPY_DP: this->CPY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; + case Instructions::CPY_IM: this->CPY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; + case Instructions::CPY_ABS: this->CPY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; + case Instructions::CPY_DP: this->CPY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; case Instructions::BCC: return this->BCC(this->_registers.pc++) + 2 + this->_isEmulationMode; case Instructions::BCS: return this->BCS(this->_registers.pc++) + 2 + this->_isEmulationMode; @@ -403,183 +408,4 @@ namespace ComSquare::CPU { return this->_bus->read(++this->_registers.s) + (this->_bus->read(++this->_registers.s) << 8u); } - - //////////////////////////////////////////////////////////////////// - /// Addressing modes - //////////////////////////////////////////////////////////////////// - - uint24_t CPU::_getImmediateAddrForA() - { - uint24_t effective = this->_registers.pac++; - if (!this->_registers.p.m) - this->_registers.pac++; - return effective; - } - - uint24_t CPU::_getImmediateAddrForX() - { - uint24_t effective = this->_registers.pac++; - if (!this->_registers.p.x_b) - this->_registers.pac++; - return effective; - } - - uint24_t CPU::_getDirectAddr() - { - uint8_t addr = this->_bus->read(this->_registers.pac++); - return this->_registers.d + addr; - } - - uint24_t CPU::_getAbsoluteAddr() - { - uint24_t addr = this->_registers.dbr << 16u; - addr += this->_bus->read(this->_registers.pac++); - addr += this->_bus->read(this->_registers.pac++) << 8u; - return addr; - } - - uint24_t CPU::_getAbsoluteLongAddr() - { - uint24_t addr = this->_bus->read(this->_registers.pac++); - addr += this->_bus->read(this->_registers.pac++) << 8u; - addr += this->_bus->read(this->_registers.pac++) << 16u; - return addr; - } - - uint24_t CPU::_getDirectIndirectIndexedYAddr() - { - uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; - uint24_t base = this->_bus->read(dp); - base += this->_bus->read(dp + 1) << 8u; - base += this->_registers.dbr << 16u; - if ((base & 0x80000000u) == (((base + this->_registers.y) & 0x80000000u))) - this->_hasIndexCrossedPageBoundary = true; - return base + this->_registers.y; - } - - uint24_t CPU::_getDirectIndirectIndexedYLongAddr() - { - uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; - uint24_t base = this->_bus->read(dp); - base += this->_bus->read(dp + 1) << 8u; - base += this->_bus->read(dp + 2) << 16u; - return base; - } - - uint24_t CPU::_getDirectIndirectIndexedXAddr() - { - uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; - dp += this->_registers.x; - uint24_t base = this->_bus->read(dp); - base += this->_bus->read(dp + 1) << 8u; - base += this->_registers.dbr << 16u; - return base; - } - - uint24_t CPU::_getDirectIndexedByXAddr() - { - uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; - dp += this->_registers.x; - return dp; - } - - uint24_t CPU::_getDirectIndexedByYAddr() - { - uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; - dp += this->_registers.y; - return dp; - } - - uint24_t CPU::_getAbsoluteIndexedByXAddr() - { - uint16_t abs = this->_bus->read(this->_registers.pac++); - abs += this->_bus->read(this->_registers.pac++) << 8u; - uint24_t effective = abs + (this->_registers.dbr << 16u); - if ((effective & 0x80000000u) == (((effective + this->_registers.x) & 0x80000000u))) - this->_hasIndexCrossedPageBoundary = true; - return effective + this->_registers.x; - } - - uint24_t CPU::_getAbsoluteIndexedByYAddr() - { - uint16_t abs = this->_bus->read(this->_registers.pac++); - abs += this->_bus->read(this->_registers.pac++) << 8u; - uint24_t effective = abs + (this->_registers.dbr << 16u); - if ((effective & 0x80000000u) == (((effective + this->_registers.y) & 0x80000000u))) - this->_hasIndexCrossedPageBoundary = true; - return effective + this->_registers.y; - } - - uint24_t CPU::_getAbsoluteIndexedByXLongAddr() - { - uint24_t lng = this->_bus->read(this->_registers.pac++); - lng += this->_bus->read(this->_registers.pac++) << 8u; - lng += this->_bus->read(this->_registers.pac++) << 16u; - return lng + this->_registers.x; - } - - uint24_t CPU::_getProgramCounterRelativeAddr() - { - uint24_t pc = this->_registers.pac; - int8_t mod = this->_bus->read(this->_registers.pac++); - return pc + mod; - } - - uint24_t CPU::_getProgramCounterRelativeLongAddr() - { - uint24_t pc = this->_registers.pac; - uint8_t val1 = this->_bus->read(this->_registers.pac++); - uint8_t val2 = this->_bus->read(this->_registers.pac++); - int16_t mod = val2 > 0x7F ? (static_cast(val2) * 256 - val1) : (val1 | val2 << 8u); - return pc + mod; - } - - uint24_t CPU::_getAbsoluteIndirectAddr() - { - uint16_t abs = this->_bus->read(this->_registers.pac++); - abs += this->_bus->read(this->_registers.pac++) << 8u; - uint24_t effective = this->_bus->read(abs); - effective += this->_bus->read(abs + 1) << 8u; - return effective; - } - - uint24_t CPU::_getAbsoluteIndirectIndexedByXAddr() - { - uint24_t abs = this->_bus->read(this->_registers.pac++); - abs += this->_bus->read(this->_registers.pac++) << 8u; - abs += this->_registers.x; - uint24_t effective = this->_bus->read(abs); - effective += this->_bus->read(abs + 1) << 8u; - return effective; - } - - uint24_t CPU::_getDirectIndirectAddr() - { - uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; - uint24_t effective = this->_bus->read(dp); - effective += this->_bus->read(dp + 1) << 8u; - effective += this->_registers.dbr << 16u; - return effective; - } - - uint24_t CPU::_getDirectIndirectLongAddr() - { - uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; - uint24_t effective = this->_bus->read(dp); - effective += this->_bus->read(++dp) << 8u; - effective += this->_bus->read(++dp) << 16u; - return effective; - } - - uint24_t CPU::_getStackRelativeAddr() - { - return this->_bus->read(this->_registers.pac++) + this->_registers.s; - } - - uint24_t CPU::_getStackRelativeIndirectIndexedYAddr() - { - uint24_t base = this->_bus->read(this->_registers.pac++) + this->_registers.s; - base += this->_registers.dbr << 16u; - return base + this->_registers.y; - } } \ No newline at end of file diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index b3cc6cf..a856962 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -555,7 +555,7 @@ namespace ComSquare::CPU explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader); CPU(const CPU &) = default; CPU &operator=(const CPU &) = delete; - ~CPU() = default; + ~CPU() override = default; //! @brief This function continue to execute the Cartridge code. //! @return The number of CPU cycles that elapsed virtual unsigned update(); @@ -572,6 +572,9 @@ namespace ComSquare::CPU //! @brief Reset interrupt - Called on boot and when the reset button is pressed. virtual void RESB(); + + //! @brief Change the memory bus used by the CPU. + void setMemoryBus(std::shared_ptr bus); }; } diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp index bb80fe6..77ab9f1 100644 --- a/sources/Debugger/CPUDebug.cpp +++ b/sources/Debugger/CPUDebug.cpp @@ -5,33 +5,41 @@ #include "CPUDebug.hpp" #include "../Utility/Utility.hpp" #include "../Exceptions/InvalidOpcode.hpp" +#include +#include using namespace ComSquare::CPU; namespace ComSquare::Debugger { CPUDebug::CPUDebug(CPU &basicCPU, SNES &snes) - : CPU(basicCPU), QMainWindow(), _ui(), _snes(snes) + : CPU(basicCPU), _window(new ClosableWindow(this, &CPUDebug::disableDebugger)), _ui(), _snes(snes) { - this->setContextMenuPolicy(Qt::NoContextMenu); - this->setAttribute(Qt::WA_QuitOnClose, false); + this->_window->setContextMenuPolicy(Qt::NoContextMenu); + this->_window->setAttribute(Qt::WA_QuitOnClose, false); + this->_window->setAttribute(Qt::WA_DeleteOnClose); - this->_ui.setupUi(this); + this->_ui.setupUi(this->_window); QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause); QMainWindow::connect(this->_ui.actionStep, &QAction::triggered, this, &CPUDebug::step); QMainWindow::connect(this->_ui.clear, &QPushButton::released, this, &CPUDebug::clearHistory); - this->show(); + this->_window->show(); this->_updateRegistersPanel(); } + void CPUDebug::disableDebugger() + { + this->_snes.disableCPUDebugging(); + } + + CPUDebug::~CPUDebug() + { + std::cout << "Destructor" << std::endl; + } + unsigned CPUDebug::update() { try { - if (!this->isVisible()) { - this->_snes.disableCPUDebugging(); - return 0; - } - if (this->_isPaused) return 0xFF; return CPU::update(); diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp index e40f361..a7219a8 100644 --- a/sources/Debugger/CPUDebug.hpp +++ b/sources/Debugger/CPUDebug.hpp @@ -9,12 +9,14 @@ #include "../Renderer/SFRenderer.hpp" #include "../SNES.hpp" #include "../../ui/ui_cpu.h" +#include "ClosableWindow.hpp" namespace ComSquare::Debugger { //! @brief A custom CPU with a window that show it's registers and the disassembly. - class CPUDebug : public CPU::CPU, public QMainWindow { + class CPUDebug : public CPU::CPU, public QObject { private: + ClosableWindow *_window; //! @brief A widget that contain the whole UI. Ui::CPUView _ui; //! @brief If this is set to true, the execution of the CPU will be paused. @@ -56,6 +58,8 @@ namespace ComSquare::Debugger void step(); //! @brief Clear the history panel. void clearHistory(); + //! @brief Called when the window is closed. Turn off the debugger and revert to a basic CPU. + void disableDebugger(); public: //! @brief Update the UI when reseting the CPU. void RESB() override; @@ -63,7 +67,7 @@ namespace ComSquare::Debugger explicit CPUDebug(ComSquare::CPU::CPU &cpu, SNES &snes); CPUDebug(const CPUDebug &) = delete; CPUDebug &operator=(const CPUDebug &) = delete; - ~CPUDebug() override = default; + ~CPUDebug() override; //! @brief Override the basic cpu's update to allow pausing of the CPU only. unsigned update() override; diff --git a/sources/Debugger/ClosableWindow.hpp b/sources/Debugger/ClosableWindow.hpp new file mode 100644 index 0000000..f87df08 --- /dev/null +++ b/sources/Debugger/ClosableWindow.hpp @@ -0,0 +1,34 @@ +// +// Created by anonymus-raccoon on 3/20/20. +// + +#ifndef COMSQUARE_CLOSABLEWINDOW_HPP +#define COMSQUARE_CLOSABLEWINDOW_HPP + +#include + +namespace ComSquare::Debugger +{ + template + class ClosableWindow : public QMainWindow { + protected: + void closeEvent(QCloseEvent *) override + { + (this->_obj->*this->_onClose)(); + } + + private: + T *_obj; + void (T::*_onClose)(); + + public: + explicit ClosableWindow(T *obj, void (T::*onClose)()) + : _obj(obj), _onClose(onClose) + { } + ClosableWindow(const ClosableWindow &) = delete; + ClosableWindow &operator=(const ClosableWindow &) = delete; + ~ClosableWindow() override = default; + }; +} + +#endif //COMSQUARE_CLOSABLEWINDOW_HPP diff --git a/sources/Debugger/MemoryBusDebug.cpp b/sources/Debugger/MemoryBusDebug.cpp new file mode 100644 index 0000000..37168ad --- /dev/null +++ b/sources/Debugger/MemoryBusDebug.cpp @@ -0,0 +1,19 @@ +// +// Created by anonymus-raccoon on 3/20/20. +// + +#include "MemoryBusDebug.hpp" + +namespace ComSquare::Debugger +{ + MemoryBusDebug::MemoryBusDebug(const ComSquare::Memory::MemoryBus &bus) + : MemoryBus(bus), QMainWindow(), _ui() + { + this->setContextMenuPolicy(Qt::NoContextMenu); + this->setAttribute(Qt::WA_QuitOnClose, false); + + this->_ui.setupUi(this); +// QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause); + this->show(); + } +} \ No newline at end of file diff --git a/sources/Debugger/MemoryBusDebug.hpp b/sources/Debugger/MemoryBusDebug.hpp new file mode 100644 index 0000000..e93c6e0 --- /dev/null +++ b/sources/Debugger/MemoryBusDebug.hpp @@ -0,0 +1,27 @@ +// +// Created by anonymus-raccoon on 3/20/20. +// + +#ifndef COMSQUARE_MEMORYBUSDEBUG_HPP +#define COMSQUARE_MEMORYBUSDEBUG_HPP + +#include +#include "../Memory/MemoryBus.hpp" +#include "../../ui/ui_busView.h" + +namespace ComSquare::Debugger +{ + //! @brief window that allow the user to view all data going through the memory bus. + class MemoryBusDebug : public Memory::MemoryBus, public QMainWindow { + private: + //! @brief A widget that contain the whole UI. + Ui::BusView _ui; + public: + explicit MemoryBusDebug(const Memory::MemoryBus &bus); + MemoryBusDebug(const MemoryBusDebug &) = delete; + MemoryBusDebug &operator=(const MemoryBusDebug &) = delete; + ~MemoryBusDebug() override = default; + }; +} + +#endif //COMSQUARE_MEMORYBUSDEBUG_HPP diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index d029ca0..92d40a6 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -10,6 +10,15 @@ namespace ComSquare::PPU { + PPU::PPU(Renderer::IRenderer &renderer): + _renderer(renderer), + _vram(65536), + _oamram(544), + _cgram(512) + { + this->_isLowByte = true; + } + uint8_t PPU::read(uint24_t addr) { switch (addr) { @@ -235,14 +244,4 @@ namespace ComSquare::PPU } this->_renderer.drawScreen(); } - - PPU::PPU(const std::shared_ptr &bus, Renderer::IRenderer &renderer): - _renderer(renderer), - _bus(std::move(bus)), - _vram(65536), - _oamram(544), - _cgram(512) - { - this->_isLowByte = true; - } } \ No newline at end of file diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 0836011..85ed2aa 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -545,12 +545,11 @@ namespace ComSquare::PPU uint32_t mpy; } mpy; Renderer::IRenderer &_renderer; - std::shared_ptr _bus; Ram::ExtendedRam _vram; Ram::ExtendedRam _oamram; Ram::ExtendedRam _cgram; public: - PPU(const std::shared_ptr &bus, Renderer::IRenderer &renderer); + PPU(Renderer::IRenderer &renderer); PPU(const PPU &) = default; PPU &operator=(const PPU &) = delete; ~PPU() = default; diff --git a/sources/Renderer/QtRenderer/QtSFML.cpp b/sources/Renderer/QtRenderer/QtSFML.cpp index a2abe00..9020d62 100644 --- a/sources/Renderer/QtRenderer/QtSFML.cpp +++ b/sources/Renderer/QtRenderer/QtSFML.cpp @@ -55,6 +55,10 @@ namespace ComSquare::Renderer apuDebugger->setShortcut(Qt::Key_F4); QMainWindow::connect(apuDebugger, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableDebugAPU); debugger->addAction(apuDebugger); + QAction *busDebugger = new QAction("Memory bus Viewer", &this->_window); + busDebugger->setShortcut(Qt::Key_F5); + QMainWindow::connect(busDebugger, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableDebugBus); + debugger->addAction(busDebugger); this->_window.show(); } @@ -110,4 +114,9 @@ namespace ComSquare::Renderer { this->_snes.enableAPUDebugging(); } + + void QtFullSFML::enableDebugBus() + { + this->_snes.enableMemoryBusDebugging(); + } } \ No newline at end of file diff --git a/sources/Renderer/QtRenderer/QtSFML.hpp b/sources/Renderer/QtRenderer/QtSFML.hpp index 66096b6..b971b82 100644 --- a/sources/Renderer/QtRenderer/QtSFML.hpp +++ b/sources/Renderer/QtRenderer/QtSFML.hpp @@ -31,6 +31,8 @@ namespace ComSquare::Renderer void enableHeaderViewer(); //! @brief Action called when clicking on the enable APU debugger button. void enableDebugAPU(); + //! @brief Action called when clicking on the enable Memory Bus debugger button. + void enableDebugBus(); //! @brief Action called when clicking on the reset button. void reset(); QtFullSFML(SNES &snes, QWidget* parent, const QPoint& position, const QSize& size, int frameRate = 0); diff --git a/sources/SNES.cpp b/sources/SNES.cpp index 73d4450..aa5824c 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -8,21 +8,23 @@ #ifdef DEBUGGER_ENABLED #include "Debugger/CPUDebug.hpp" #include "Debugger/APUDebug.hpp" +#include "Debugger/MemoryBusDebug.hpp" + #endif namespace ComSquare { - SNES::SNES(const std::shared_ptr &bus, const std::string &romPath, Renderer::IRenderer &renderer) : - _bus(bus), + SNES::SNES(const std::string &romPath, Renderer::IRenderer &renderer) : + _bus(std::make_shared()), cartridge(new Cartridge::Cartridge(romPath)), wram(new Ram::Ram(16384)), sram(new Ram::Ram(this->cartridge->header.sramSize)), apuRam(new APU::MemoryMap()), - cpu(new CPU::CPU(bus, cartridge->header)), - ppu(new PPU::PPU(bus, renderer)), + cpu(new CPU::CPU(this->_bus, cartridge->header)), + ppu(new PPU::PPU(renderer)), apu(new APU::APU(this->apuRam)) { - bus->mapComponents(*this); + this->_bus->mapComponents(*this); } void SNES::enableCPUDebugging() @@ -43,7 +45,7 @@ namespace ComSquare void SNES::enableRamViewer() { #ifdef DEBUGGER_ENABLED - this->_ramViewer = std::make_shared(*this, *this->_bus); + this->_ramViewer = std::make_unique(*this, *this->_bus); #endif } @@ -64,7 +66,7 @@ namespace ComSquare void SNES::enableHeaderViewer() { #ifdef DEBUGGER_ENABLED - this->_headerViewer = std::make_shared(*this->cartridge); + this->_headerViewer = std::make_unique(*this->cartridge); #endif } @@ -78,9 +80,9 @@ namespace ComSquare void SNES::enableAPUDebugging() { #ifdef DEBUGGER_ENABLED - this->apu = std::make_shared(*this->apu, *this); + this->apu = std::make_shared(*this->apu, *this); #else - std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; + std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; #endif } @@ -88,4 +90,24 @@ namespace ComSquare { this->apu = std::make_shared(*this->apu); } + + void SNES::disableMemoryBusDebugging() + { + #ifdef DEBUGGER_ENABLED + this->_bus = std::make_shared(*this->_bus); + this->cpu->setMemoryBus(this->_bus); + #else + std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; + #endif + } + + void SNES::enableMemoryBusDebugging() + { + #ifdef DEBUGGER_ENABLED + this->_bus = std::make_shared(*this->_bus); + this->cpu->setMemoryBus(this->_bus); + #else + std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; + #endif + } } diff --git a/sources/SNES.hpp b/sources/SNES.hpp index 5fc5846..b9a2025 100644 --- a/sources/SNES.hpp +++ b/sources/SNES.hpp @@ -25,10 +25,12 @@ namespace ComSquare private: #ifdef DEBUGGER_ENABLED //! @brief The window that allow the user to view a memory. - std::shared_ptr _ramViewer; + std::unique_ptr _ramViewer; //! @brief The window that allow the user to view the cartridge's header. - std::shared_ptr _headerViewer; + std::unique_ptr _headerViewer; +// std::unique_ptr _bus; public: //! @brief Cartridge containing instructions (ROM). @@ -65,11 +67,15 @@ namespace ComSquare void disableAPUDebugging(); //! @brief Enable the APU's debugging window. void enableAPUDebugging(); + //! @brief Disable the Memory Bus's debugging window. + void disableMemoryBusDebugging(); + //! @brief Enable the Memory Bus's debugging window. + void enableMemoryBusDebugging(); //! @brief Create all the components using a common memory bus for all of them. - SNES(const std::shared_ptr &bus, const std::string &ramPath, Renderer::IRenderer &renderer); + SNES(const std::string &ramPath, Renderer::IRenderer &renderer); SNES(const SNES &) = default; - SNES &operator=(const SNES &) = default; + SNES &operator=(const SNES &) = delete; ~SNES() = default; }; } diff --git a/main.cpp b/sources/main.cpp similarity index 52% rename from main.cpp rename to sources/main.cpp index a2bb748..ed678cd 100644 --- a/main.cpp +++ b/sources/main.cpp @@ -5,15 +5,21 @@ #include #include #include -#include "sources/SNES.hpp" -#include "sources/Renderer/SFRenderer.hpp" -#include "sources/Renderer/QtRenderer/QtSFML.hpp" +#include "SNES.hpp" +#include "Renderer/SFRenderer.hpp" +#include "Renderer/QtRenderer/QtSFML.hpp" using namespace ComSquare; void usage(char *bin) { - std::cout << "ComSquare:" << std::endl << "\tUsage: " << bin << " rom_path" << std::endl; + std::cout << "ComSquare:" << std::endl + << "\tUsage: " << bin << " rom_path [options]" << std::endl + << "Options:" << std::endl + << "\t-c, --cpu: \tEnable the debugger of the CPU." << std::endl + << "\t-m, --memory: \tEnable the memory viewer panel." << std::endl + << "\t-h, --header: \tShow the header of the cartridge." << std::endl + << "\t-b, --bus: \tShow the memory bus's log." << std::endl; } void parseArguments(int argc, char **argv, SNES &snes) @@ -21,13 +27,14 @@ void parseArguments(int argc, char **argv, SNES &snes) while (true) { int option_index = 0; static struct option long_options[] = { - {"cpu", no_argument, 0, 'c' }, - {"memory", no_argument, 0, 'm' }, - {"header", no_argument, 0, 'h' }, - {0, 0, 0, 0 } + {"cpu", no_argument, 0, 'c'}, + {"memory", no_argument, 0, 'm'}, + {"header", no_argument, 0, 'h'}, + {"bus", no_argument, 0, 'b'}, + {0, 0, 0, 0} }; - char c = getopt_long(argc, argv, "cmh", long_options, &option_index); + int c = getopt_long(argc, argv, "cmh", long_options, &option_index); if (c == -1) break; switch (c) { @@ -43,6 +50,9 @@ void parseArguments(int argc, char **argv, SNES &snes) case 'h': snes.enableHeaderViewer(); break; + case 'b': + snes.enableMemoryBusDebugging(); + break; default: break; } @@ -58,7 +68,7 @@ int main(int argc, char **argv) QApplication app(argc, argv); QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); Renderer::QtSFML renderer(600, 800); - SNES snes(std::make_shared(), argv[1], renderer); + SNES snes(argv[1], renderer); renderer.createWindow(snes, 60); parseArguments(argc, argv, snes); return QApplication::exec(); diff --git a/tests/tests.cpp b/tests/tests.cpp index c9a3bd7..5864663 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -13,14 +13,12 @@ using namespace ComSquare; std::pair, SNES> Init() { - std::shared_ptr bus = std::make_shared(); Renderer::NoRenderer norenderer(0, 0, 0); - SNES snes(bus, "../tests/my_cartridge", norenderer); + SNES snes("../tests/my_cartridge", norenderer); snes.cartridge->_size = 100; snes.cartridge->_data = new uint8_t[snes.cartridge->_size]; snes.cartridge->header.mappingMode = Cartridge::LoRom; snes.sram->_size = 100; snes.sram->_data = new uint8_t[snes.cartridge->_size]; -// bus->mapComponents(snes); - return std::make_pair(bus, snes); + return std::make_pair(snes._bus, snes); } \ No newline at end of file diff --git a/ui/busView.ui b/ui/busView.ui index cddaee3..2b700d8 100644 --- a/ui/busView.ui +++ b/ui/busView.ui @@ -1,7 +1,7 @@ - MainWindow - + BusView + 0