From 80ebfa8064d70a403c4f6dcadfc2a162cfdbb63c Mon Sep 17 00:00:00 2001 From: Anonymus Raccoon Date: Thu, 26 Mar 2020 22:19:16 +0100 Subject: [PATCH] Finishing the array of instruction, it now works well --- sources/APU/APU.cpp | 1 + sources/CPU/CPU.cpp | 2 + sources/CPU/CPU.hpp | 6 +- sources/CPU/Instruction.hpp | 5 ++ .../CPU/Instructions/InternalInstruction.cpp | 16 ++--- sources/Debugger/CPUDebug.cpp | 67 +++++++++++++------ sources/Debugger/CPUDebug.hpp | 20 +++++- sources/SNES.cpp | 6 +- tests/CPU/testInternal.cpp | 18 +++-- ui/cpu.ui | 2 +- 10 files changed, 101 insertions(+), 42 deletions(-) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index c2cacd9..550fc21 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -709,6 +709,7 @@ namespace ComSquare::APU cycles -= this->_paddingCycles; while (total < cycles && this->_state == Running) total += this->_executeInstruction(); + std::cout << "Done." << std::endl; if (this->_state == Running) this->_paddingCycles = total - cycles; } diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index 8791036..92f3474 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -303,6 +303,8 @@ namespace ComSquare::CPU case AbsoluteIndirectIndexedByX: valueAddr = this->_getAbsoluteIndirectIndexedByXAddr(); break; + default: + break; } return cycles + (this->*instruction.call)(valueAddr); diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index a14f2c0..8fab4cb 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -532,7 +532,7 @@ namespace ComSquare::CPU {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 97 {&CPU::BRK, 7, "tya #-#", AddressingMode::Implied, 2}, // 98 {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByY, 3}, // 99 - {&CPU::BRK, 7, "txs #-#", AddressingMode::Implied, 2}, // 9A + {&CPU::TXS, 2, "txs", AddressingMode::Implied, 1}, // 9A {&CPU::BRK, 7, "txy #-#", AddressingMode::Implied, 2}, // 9B {&CPU::STZ, 4, "stz", AddressingMode::Absolute, 3}, // 9C {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByX, 3}, // 9D @@ -546,9 +546,9 @@ namespace ComSquare::CPU {&CPU::LDA, 3, "lda", AddressingMode::DirectPage, 2}, // A5 {&CPU::LDX, 3, "ldx", AddressingMode::DirectPage, 2}, // A6 {&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectLong, 2}, // A7 - {&CPU::BRK, 7, "tay #-#", AddressingMode::Implied, 2}, // A8 + {&CPU::TAY, 2, "tay", AddressingMode::Implied, 1}, // A8 {&CPU::LDA, 2, "lda", AddressingMode::ImmediateForA, 2}, // A9 - {&CPU::BRK, 7, "tax #-#", AddressingMode::Implied, 2}, // AA + {&CPU::TAX, 2, "tax", AddressingMode::Implied, 1}, // AA {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // AB {&CPU::LDY, 4, "ldy", AddressingMode::Absolute, 4}, // AC {&CPU::LDA, 4, "lda", AddressingMode::Absolute, 3}, // AD diff --git a/sources/CPU/Instruction.hpp b/sources/CPU/Instruction.hpp index 8efd762..c2057d4 100644 --- a/sources/CPU/Instruction.hpp +++ b/sources/CPU/Instruction.hpp @@ -57,6 +57,11 @@ namespace ComSquare::CPU std::string name; AddressingMode addressingMode; int size; + + Instruction() = default; + Instruction(const Instruction &) = default; + Instruction &operator=(const Instruction &) = default; + ~Instruction() = default; }; } #endif //COMSQUARE_INSTRUCTION_HPP diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp index 921d2a9..c83b690 100644 --- a/sources/CPU/Instructions/InternalInstruction.cpp +++ b/sources/CPU/Instructions/InternalInstruction.cpp @@ -48,15 +48,15 @@ namespace ComSquare::CPU return 0; } - int CPU::SEP(uint24_t value) + int CPU::SEP(uint24_t valueAddr) { - this->_registers.p.flags |= value; + this->_registers.p.flags |= this->_bus->read(valueAddr); return 0; } - int CPU::REP(uint24_t value) + int CPU::REP(uint24_t valueAddr) { - this->_registers.p.flags &= ~value; + this->_registers.p.flags &= ~this->_bus->read(valueAddr); if (this->_isEmulationMode) { this->_registers.p.x_b = true; this->_registers.p.m = true; @@ -64,19 +64,19 @@ namespace ComSquare::CPU return 0; } - int CPU::JSR(uint24_t value) + int CPU::JSR(uint24_t valueAddr) { this->_push(--this->_registers.pc); - this->_registers.pc = value; + this->_registers.pc = valueAddr; return 0; } - int CPU::JSL(uint24_t value) + int CPU::JSL(uint24_t valueAddr) { this->_registers.pac--; this->_push(this->_registers.pbr); this->_push(this->_registers.pc); - this->_registers.pac = value; + this->_registers.pac = valueAddr; return 0; } diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp index 9455189..63424da 100644 --- a/sources/Debugger/CPUDebug.cpp +++ b/sources/Debugger/CPUDebug.cpp @@ -7,6 +7,7 @@ #include "../Exceptions/InvalidOpcode.hpp" #include #include +#include using namespace ComSquare::CPU; @@ -24,12 +25,16 @@ namespace ComSquare::Debugger this->_window->setAttribute(Qt::WA_DeleteOnClose); this->_ui.setupUi(this->_window); -// -// this->_ui.disasembly->setModel(&this->_model); -// this->_ui.disasembly->setShowGrid(false); -// this->_ui.disasembly->verticalHeader()->hide(); -// this->_ui.disasembly->horizontalHeader()->hide(); -// this->_ui.disasembly->horizontalHeader()->setStretchLastSection(true); + + this->_ui.disasembly->setModel(&this->_model); + this->_ui.disasembly->setShowGrid(false); + this->_ui.disasembly->verticalHeader()->hide(); + this->_ui.disasembly->horizontalHeader()->hide(); + this->_ui.disasembly->horizontalHeader()->setStretchLastSection(true); + +// uint24_t pc = 0x80800; // The first byte of the ROM //TODO make this work for other rom mapping. +// while (pc < 0x80800 + this->_cartridgeHeader.romSize) +// this->_disassembledInstructions.insert(pc, this->_parseInstruction(pc)); QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause); QMainWindow::connect(this->_ui.actionStep, &QAction::triggered, this, &CPUDebug::step); @@ -72,7 +77,7 @@ namespace ComSquare::Debugger this->_isStepping = false; this->_isPaused = true; } - this->_ui.logger->append((CPUDebug::_getInstructionString(this->_registers.pac - 1) + " - " + Utility::to_hex(opcode)).c_str()); + this->_ui.logger->append((this->_parseInstruction(this->_registers.pac - 1).toString() + " - " + Utility::to_hex(opcode)).c_str()); unsigned ret = CPU::_executeInstruction(opcode); this->_updateRegistersPanel(); return ret; @@ -162,7 +167,7 @@ namespace ComSquare::Debugger std::string CPUDebug::_getImmediateValue8Bits(uint24_t pc) { std::stringstream ss; - ss << "#$" << std::hex << static_cast(this->_bus->read(pc), true); + ss << "#$" << std::hex << static_cast(this->_bus->read(pc, true)); return ss.str(); } @@ -179,7 +184,7 @@ namespace ComSquare::Debugger std::string CPUDebug::_getDirectValue(uint24_t pc) { std::stringstream ss; - ss << "$" << std::hex << static_cast(this->_bus->read(pc), true); + ss << "$" << std::hex << static_cast(this->_bus->read(pc, true)); return ss.str(); } @@ -210,20 +215,36 @@ namespace ComSquare::Debugger return ss.str(); } - std::string CPUDebug::_getInstructionString(uint24_t pc) + DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc) { - uint8_t opcode = this->_bus->read(pc++, true); - - return this->_instructions[opcode].name + this->_getInstructionParameter(pc); + uint24_t opcode = this->_bus->read(pc++, true); + Instruction instruction = this->_instructions[opcode]; + std::string argument = this->_getInstructionParameter(instruction, pc); + return DisassembledInstruction(instruction, argument, opcode); } - std::string CPUDebug::_getInstructionParameter(uint24_t pc) + std::string CPUDebug::_getInstructionParameter(Instruction &instruction, uint24_t pc) { - Instruction instruction = this->_instructions[opcode]; - switch (instruction.addressingMode) { + case Implied: + return ""; case ImmediateForA: - return this->_getImmediateAddrForA(pc); + return this->_getImmediateValueForA(pc); + case ImmediateForX: + return this->_getImmediateValueForX(pc); + case Immediate8bits: + return this->_getImmediateValue8Bits(pc); + case Absolute: + return this->_getAbsoluteValue(pc); + case AbsoluteLong: + return this->_getAbsoluteLongValue(pc); + case DirectPage: + return this->_getDirectValue(pc); + case DirectPageIndexedByX: + return this->_getDirectIndexedByXValue(pc); + + default: + return "???"; } } @@ -238,6 +259,14 @@ namespace ComSquare::Debugger { this->_window->activateWindow(); } + + DisassembledInstruction::DisassembledInstruction(const CPU::Instruction &instruction, std::string arg, uint8_t op) + : CPU::Instruction(instruction), argument(std::move(arg)), opcode(op) {} + + std::string DisassembledInstruction::toString() + { + return this->name + " " + this->argument; + } } DisassemblyModel::DisassemblyModel(ComSquare::Debugger::CPUDebug &cpu) : QAbstractTableModel(), _cpu(cpu){ } @@ -249,10 +278,10 @@ int DisassemblyModel::columnCount(const QModelIndex &) const int DisassemblyModel::rowCount(const QModelIndex &) const { - return 0xFFFFFF; + return 5; } -QVariant DisassemblyModel::data(const QModelIndex &index, int role) const +QVariant DisassemblyModel::data(const QModelIndex &, int role) const { if (role != Qt::DisplayRole) return QVariant(); diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp index 0e29686..3137fa8 100644 --- a/sources/Debugger/CPUDebug.hpp +++ b/sources/Debugger/CPUDebug.hpp @@ -38,6 +38,18 @@ public: namespace ComSquare::Debugger { + struct DisassembledInstruction : public CPU::Instruction { + std::string argument; + uint8_t opcode; + + DisassembledInstruction(const CPU::Instruction &instruction, std::string argument, uint8_t opcode); + DisassembledInstruction(const DisassembledInstruction &) = default; + DisassembledInstruction &operator=(const DisassembledInstruction &) = default; + ~DisassembledInstruction() = default; + + std::string toString(); + }; + //! @brief A custom CPU with a window that show it's registers and the disassembly. class CPUDebug : public CPU::CPU, public QObject { private: @@ -47,6 +59,8 @@ namespace ComSquare::Debugger Ui::CPUView _ui; //! @brief The disassembly viewer's model. DisassemblyModel _model; + //! @brief The list of disassembled instructions to show on the debugger. + std::map _disassembledInstructions; //! @brief If this is set to true, the execution of the CPU will be paused. bool _isPaused = true; //! @brief If this is set to true, the CPU will execute one instruction and pause itself. @@ -55,10 +69,10 @@ namespace ComSquare::Debugger SNES &_snes; //! @brief Reimplement the basic instruction execution method to log instructions inside the logger view. unsigned _executeInstruction(uint8_t opcode) override; - //! @brief Get a printable string representing an instruction at the program counter given as parameter. - std::string _getInstructionString(uint24_t pc); + //! @brief Parse the instruction at the program counter given to have human readable information. + DisassembledInstruction _parseInstruction(uint24_t pc); //! @brief Get the parameter of the instruction as an hexadecimal string. - std::string _getInstructionParameter(uint24_t pc); + std::string _getInstructionParameter(ComSquare::CPU::Instruction &instruction, uint24_t pc); //! @brief Get a printable string representing the flags. std::string _getFlagsString(); //! @brief Update the register's panel (accumulator, stack pointer...) diff --git a/sources/SNES.cpp b/sources/SNES.cpp index b6188fe..7274243 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -31,7 +31,7 @@ namespace ComSquare { unsigned cycleCount = this->cpu->update(); this->ppu->update(cycleCount); - this->apu->update(cycleCount); +// this->apu->update(cycleCount); } void SNES::enableCPUDebugging(bool pause) @@ -40,11 +40,13 @@ namespace ComSquare if (this->cpu->isDebugger()) { auto cpuDebug = std::static_pointer_cast(this->cpu); cpuDebug->focus(); - cpuDebug->pause(); + if (pause) + cpuDebug->pause(); } else this->cpu = std::make_shared(*this->cpu, *this); #else std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; + (void)pause; #endif } diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp index fca58c3..42a3c40 100644 --- a/tests/CPU/testInternal.cpp +++ b/tests/CPU/testInternal.cpp @@ -15,7 +15,8 @@ using namespace ComSquare; Test(SEP, setall) { Init() - snes.cpu->SEP(0xFF); + snes.wram->_data[0] = 0xFF; + snes.cpu->SEP(0x00); auto data = snes.cpu->_registers.p.flags; cr_assert_eq(data, 0xFF, "The flag should be 0xFF but it was %x", data); } @@ -24,7 +25,8 @@ Test(SEP, setsome) { Init() snes.cpu->_registers.p.flags = 0b01000000; - snes.cpu->SEP(0b10110101); + snes.wram->_data[0] = 0b10110101; + snes.cpu->SEP(0x0); auto data = snes.cpu->_registers.p.flags; cr_assert_eq(data, 0b11110101, "The flag should be 245 but it was %i", data); } @@ -33,7 +35,8 @@ Test(REP, resetall) { Init() snes.cpu->_isEmulationMode = false; - snes.cpu->REP(0xFF); + snes.wram->_data[0] = 0xFF; + snes.cpu->REP(0x00); auto data = snes.cpu->_registers.p.flags; cr_assert_eq(data, 0x00, "The flag should be 0x00 but it was %x", data); } @@ -43,7 +46,8 @@ Test(REP, resetsome) Init() snes.cpu->_isEmulationMode = false; snes.cpu->_registers.p.flags = 0b01000000; - snes.cpu->REP(0b01000000); + snes.wram->_data[0] = 0b01000000; + snes.cpu->REP(0x0); auto data = snes.cpu->_registers.p.flags; cr_assert_eq(data, 0x0, "The flag should be 0 but it was %x", data); } @@ -52,7 +56,8 @@ Test(REP, resetallEmulation) { Init() snes.cpu->_isEmulationMode = true; - snes.cpu->REP(0xFF); + snes.wram->_data[0] = 0xFF; + snes.cpu->REP(0x00); auto data = snes.cpu->_registers.p.flags; cr_assert_eq(data, 0b00110000, "The flag should be 0b00110000 but it was %x", data); } @@ -62,7 +67,8 @@ Test(REP, resetsomeEmulation) Init() snes.cpu->_isEmulationMode = true; snes.cpu->_registers.p.flags = 0b01000101; - snes.cpu->REP(0b01000001); + snes.wram->_data[0] = 0b01000001; + snes.cpu->REP(0x0); auto data = snes.cpu->_registers.p.flags; cr_assert_eq(data, 0b00110100, "The flag should be 0b00110100 but it was %x", data); } diff --git a/ui/cpu.ui b/ui/cpu.ui index 280e858..e3b719f 100644 --- a/ui/cpu.ui +++ b/ui/cpu.ui @@ -141,7 +141,7 @@ Qt::RightToLeft - false + true