diff --git a/CMakeLists.txt b/CMakeLists.txt index b64b32b..36966d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,9 @@ add_executable(unit_tests sources/Models/Components.hpp sources/CPU/Instruction.hpp sources/Exceptions/DebuggableError.hpp + tests/CPU/Math/testOthersMath.cpp + tests/testRectangleMemory.cpp + tests/CPU/Math/testCMP.cpp ) # include criterion & coverage @@ -159,8 +162,8 @@ add_executable(ComSquare sources/CPU/Instructions/InternalInstruction.cpp sources/Ram/ExtendedRam.cpp sources/Ram/ExtendedRam.hpp - sources/Debugger/CPUDebug.cpp - sources/Debugger/CPUDebug.hpp + sources/Debugger/CPU/CPUDebug.cpp + sources/Debugger/CPU/CPUDebug.hpp sources/Renderer/QtRenderer/QtSFML.cpp sources/Renderer/QtRenderer/QtSFML.hpp sources/Renderer/QtRenderer/QtWidgetSFML.cpp @@ -205,10 +208,11 @@ add_executable(ComSquare sources/Models/Components.hpp sources/CPU/Instruction.hpp sources/Exceptions/DebuggableError.hpp + sources/Debugger/CPU/Disassembly.cpp sources/Models/Components.hpp sources/Debugger/CGramDebug.cpp sources/Debugger/CGramDebug.hpp - ) +) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/CPU/AddressingModes.cpp b/sources/CPU/AddressingModes.cpp index 0d39b18..d19a985 100644 --- a/sources/CPU/AddressingModes.cpp +++ b/sources/CPU/AddressingModes.cpp @@ -126,22 +126,6 @@ namespace ComSquare::CPU return lng + this->_registers.x; } - uint24_t CPU::_getProgramCounterRelativeAddr() - { - uint24_t pc = this->_registers.pac; - int8_t mod = this->readPC(); - return pc + mod; - } - - uint24_t CPU::_getProgramCounterRelativeLongAddr() - { - uint24_t pc = this->_registers.pac; - uint8_t val1 = this->readPC(); - uint8_t val2 = this->readPC(); - int16_t mod = val2 > 0x7F ? (static_cast(val2) * 256 - val1) : (val1 | val2 << 8u); - return pc + mod; - } - uint24_t CPU::_getAbsoluteIndirectAddr() { uint16_t abs = this->readPC(); @@ -151,6 +135,16 @@ namespace ComSquare::CPU return effective; } + uint24_t CPU::_getAbsoluteIndirectLongAddr() + { + uint16_t abs = this->readPC(); + abs += this->readPC() << 8u; + uint24_t effective = this->_bus->read(abs); + effective += this->_bus->read(abs + 1) << 8u; + effective += this->_bus->read(abs + 2) << 16u; + return effective; + } + uint24_t CPU::_getAbsoluteIndirectIndexedByXAddr() { uint24_t abs = this->readPC(); diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index a31bf3f..8116408 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -211,96 +211,69 @@ namespace ComSquare::CPU return cycles; } + uint24_t CPU::_getValueAddr(Instruction &instruction) + { + switch (instruction.addressingMode) { + case Implied: + return 0; + case Immediate8bits: + return this->_getImmediateAddr8Bits(); + case ImmediateForA: + return this->_getImmediateAddrForA(); + case ImmediateForX: + return this->_getImmediateAddrForX(); + + case Absolute: + return this->_getAbsoluteAddr(); + case AbsoluteLong: + return this->_getAbsoluteLongAddr(); + case AbsoluteIndirect: + return this->_getAbsoluteIndirectAddr(); + case AbsoluteIndirectLong: + return this->_getAbsoluteIndirectLongAddr(); + + case DirectPage: + return this->_getDirectAddr(); + case DirectPageIndirect: + return this->_getDirectIndirectAddr(); + case DirectPageIndirectLong: + return this->_getDirectIndirectLongAddr(); + + case DirectPageIndexedByX: + return this->_getDirectIndexedByXAddr(); + case DirectPageIndexedByY: + return this->_getDirectIndexedByYAddr(); + case DirectPageIndirectIndexedByX: + return this->_getDirectIndirectIndexedXAddr(); + case DirectPageIndirectIndexedByY: + return this->_getDirectIndirectIndexedYAddr(); + case DirectPageIndirectIndexedByYLong: + return this->_getDirectIndirectIndexedYLongAddr(); + + case AbsoluteIndexedByX: + return this->_getAbsoluteIndexedByXAddr(); + case AbsoluteIndexedByXLong: + return this->_getAbsoluteIndexedByXLongAddr(); + case AbsoluteIndexedByY: + return this->_getAbsoluteIndexedByYAddr(); + + case StackRelative: + return this->_getStackRelativeAddr(); + case StackRelativeIndirectIndexedByY: + return this->_getStackRelativeIndirectIndexedYAddr(); + + case AbsoluteIndirectIndexedByX: + return this->_getAbsoluteIndirectIndexedByXAddr(); + default: + return 0; + } + } + unsigned CPU::_executeInstruction(uint8_t opcode) { Instruction instruction = this->_instructions[opcode]; - uint24_t valueAddr = 0; - this->_hasIndexCrossedPageBoundary = false; - - switch (instruction.addressingMode) { - case Implied: - break; - case Immediate8bits: - valueAddr = this->_getImmediateAddr8Bits(); - break; - case ImmediateForA: - valueAddr = this->_getImmediateAddrForA(); - break; - case ImmediateForX: - valueAddr = this->_getImmediateAddrForX(); - break; - - // TODO implement the relative addressing mode - // TODO implement the relative long addressing mode - - case Absolute: - valueAddr = this->_getAbsoluteAddr(); - break; - case AbsoluteLong: - valueAddr = this->_getAbsoluteLongAddr(); - break; - case AbsoluteIndirect: - valueAddr = this->_getAbsoluteIndirectAddr(); - break; - - //TODO implement absolute indirect long addressing mode - - case DirectPage: - valueAddr = this->_getDirectAddr(); - break; - case DirectPageIndirect: - valueAddr = this->_getDirectIndirectAddr(); - break; - case DirectPageIndirectLong: - valueAddr = this->_getDirectIndirectLongAddr(); - break; - - case DirectPageIndexedByX: - valueAddr = this->_getDirectIndexedByXAddr(); - break; - case DirectPageIndexedByY: - valueAddr = this->_getDirectIndexedByYAddr(); - break; - case DirectPageIndirectIndexedByX: - valueAddr = this->_getDirectIndirectIndexedXAddr(); - break; - case DirectPageIndirectIndexedByY: - valueAddr = this->_getDirectIndirectIndexedYAddr(); - break; - case DirectPageIndirectIndexedByYLong: - valueAddr = this->_getDirectIndirectIndexedYLongAddr(); - break; - - case AbsoluteIndexedByX: - valueAddr = this->_getAbsoluteIndexedByXAddr(); - break; - case AbsoluteIndexedByXLong: - valueAddr = this->_getAbsoluteIndexedByXLongAddr(); - break; - case AbsoluteIndexedByY: - valueAddr = this->_getAbsoluteIndexedByYAddr(); - break; - - case StackRelative: - valueAddr = this->_getStackRelativeAddr(); - break; - case StackRelativeIndirectIndexedByY: - valueAddr = this->_getStackRelativeIndirectIndexedYAddr(); - break; - - case ProgramCounterRelative: - valueAddr = this->_getProgramCounterRelativeAddr(); - break; - case ProgramCounterRelativeLong: - valueAddr = this->_getProgramCounterRelativeLongAddr(); - break; - case AbsoluteIndirectIndexedByX: - valueAddr = this->_getAbsoluteIndirectIndexedByXAddr(); - break; - default: - break; - } + uint24_t valueAddr = this->_getValueAddr(instruction); return instruction.cycleCount + (this->*instruction.call)(valueAddr, instruction.addressingMode); } diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 3e45f77..2d72b91 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -226,12 +226,10 @@ namespace ComSquare::CPU uint24_t _getAbsoluteIndexedByYAddr(); //! @brief The effective address is formed by adding the with X. uint24_t _getAbsoluteIndexedByXLongAddr(); - //! @brief The <8-bit signed exp> is added to PC (program counter) to form the new location. - uint24_t _getProgramCounterRelativeAddr(); - //! @brief The <16-bit signed exp> is added to PC (program counter) to form the new location. - uint24_t _getProgramCounterRelativeLongAddr(); //! @brief 2 bytes are pulled from the to form the effective address. uint24_t _getAbsoluteIndirectAddr(); + //! @brief 3 bytes are pulled from the to form the effective address. + uint24_t _getAbsoluteIndirectLongAddr(); //! @brief The is added with X, then 2 bytes are pulled from that address to form the new location. uint24_t _getAbsoluteIndirectIndexedByXAddr(); //! @brief 2 bytes are pulled from the direct page address to form the 16-bit address. It is combined with DBR to form a 24-bit effective address. @@ -260,6 +258,11 @@ namespace ComSquare::CPU //! @return The number of CPU cycles that the instruction took. virtual unsigned _executeInstruction(uint8_t opcode); + //! @brief Get the parameter address of an instruction from it's addressing mode. + //! @info The current program counter should point to the instruction's opcode + 1. + //! @return The address of the data to read on the instruction. + uint24_t _getValueAddr(Instruction &instruction); + //! @brief Break instruction - Causes a software break. The PC is loaded from a vector table. int BRK(uint24_t, AddressingMode); //! @brief Co-Processor Enable instruction - Causes a software break. The PC is loaded from a vector table. @@ -376,107 +379,147 @@ namespace ComSquare::CPU int JML(uint24_t valueAddr, AddressingMode); //! @brief No OP. int NOP(uint24_t, AddressingMode); + //! @brief Decrement the X register. + int DEX(uint24_t, AddressingMode); + //! @brief Decrement the Y register. + int DEY(uint24_t, AddressingMode); + //! @brief Or accumulator with memory. + int ORA(uint24_t valueAddr, AddressingMode mode); + //! @brief Return from subroutine. + int RTS(uint24_t, AddressingMode); + //! @brief Return from subroutine long. + int RTL(uint24_t, AddressingMode); + //! @brief Compare Accumulator with Memory. + int CMP(uint24_t, AddressingMode); + //! @brief Increment + int INC(uint24_t, AddressingMode); + //! @brief Decrement + int DEC(uint24_t, AddressingMode); + //! @brief XOR, Exclusive OR accumulator with memory. + int EOR(uint24_t, AddressingMode); + //! @brief Transfer 16 bit A to DP + int TCD(uint24_t, AddressingMode); + //! @brief Transfer 16 bit A to SP + int TCS(uint24_t, AddressingMode); + //! @brief Transfer DP to 16 bit A + int TDC(uint24_t, AddressingMode); + //! @brief Transfer DP to 16 bit A + int TSC(uint24_t, AddressingMode); + //! @brief Transfer SP to X + int TSX(uint24_t, AddressingMode); + //! @brief Transfer X to A + int TXA(uint24_t, AddressingMode); + //! @brief Transfer Y to A + int TYA(uint24_t, AddressingMode); + //! @brief Transfer X to Y + int TXY(uint24_t, AddressingMode); + //! @brief Transfer Y to X + int TYX(uint24_t, AddressingMode); + //! @brief Test and Set Memory Bits Against Accumulator + int TSB(uint24_t, AddressingMode); + //! @brief Exchange the B and A Accumulators + int XBA(uint24_t, AddressingMode); //! @brief All the instructions of the CPU. //! @info Instructions are indexed by their opcode Instruction _instructions[0x100] = { - {&CPU::BRK, 7, "brk", AddressingMode::Implied, 2}, // 00 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 01 - {&CPU::COP, 7, "cop", AddressingMode::Implied, 2}, // 02 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 03 - {&CPU::BRK, 7, "tsb #-#", AddressingMode::Implied, 2}, // 04 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 05 + {&CPU::BRK, 7, "brk", AddressingMode::Immediate8bits, 2}, // 00 + {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 01 + {&CPU::COP, 7, "cop", AddressingMode::Immediate8bits, 2}, // 02 + {&CPU::ORA, 4, "ora", AddressingMode::StackRelative, 2}, // 03 + {&CPU::TSB, 5, "tsb", AddressingMode::DirectPage, 2}, // 04 + {&CPU::ORA, 3, "ora", AddressingMode::DirectPage, 2}, // 05 {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 06 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 07 + {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectLong, 2}, // 07 {&CPU::PHP, 3, "php", AddressingMode::Implied, 3}, // 08 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 09 + {&CPU::ORA, 2, "ora", AddressingMode::ImmediateForA, 2}, // 09 {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0A {&CPU::PHD, 4, "phd", AddressingMode::Implied, 1}, // 0B - {&CPU::BRK, 7, "tsb #-#", AddressingMode::Implied, 2}, // 0C - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 0D + {&CPU::TSB, 6, "tsb", AddressingMode::Absolute, 3}, // 0C + {&CPU::ORA, 3, "ora", AddressingMode::Absolute, 4}, // 0D {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0E - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 0F - {&CPU::BPL, 7, "bpl", AddressingMode::Implied, 2}, // 10 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 11 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 12 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 13 + {&CPU::ORA, 5, "ora", AddressingMode::AbsoluteLong, 5}, // 0F + {&CPU::BPL, 7, "bpl", AddressingMode::Immediate8bits, 2}, // 10 + {&CPU::ORA, 5, "ora", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 11 + {&CPU::ORA, 5, "ora", AddressingMode::DirectPageIndirect, 2}, // 12 + {&CPU::ORA, 7, "ora", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 13 {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 14 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 15 + {&CPU::ORA, 4, "ora", AddressingMode::DirectPageIndexedByX, 2}, // 15 {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 16 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 17 + {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 17 {&CPU::CLC, 2, "clc", AddressingMode::Implied, 1}, // 18 - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 19 - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // 1A - {&CPU::BRK, 7, "tcs #-#", AddressingMode::Implied, 2}, // 1B + {&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByY, 3}, // 19 + {&CPU::INC, 2, "inc", AddressingMode::Implied, 1}, // 1A + {&CPU::TCS, 2, "tcs", AddressingMode::Implied, 1}, // 1B {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 1D + {&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByX, 3}, // 1D {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 1E - {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 1F + {&CPU::ORA, 5, "ora", AddressingMode::AbsoluteIndexedByXLong, 4}, // 1F {&CPU::JSR, 6, "jsr", AddressingMode::Absolute, 3}, // 20 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 21 + {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 21 {&CPU::JSL, 8, "jsl", AddressingMode::AbsoluteLong, 4}, // 22 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 23 + {&CPU::AND, 4, "and", AddressingMode::StackRelative, 2}, // 23 {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 24 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 25 + {&CPU::AND, 3, "and", AddressingMode::DirectPage, 2}, // 25 {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 26 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 27 + {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectLong, 2}, // 27 {&CPU::PLP, 4, "plp", AddressingMode::Implied, 1}, // 28 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 29 + {&CPU::AND, 2, "and", AddressingMode::ImmediateForA, 2}, // 29 {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2A {&CPU::PLD, 5, "pld", AddressingMode::Implied, 1}, // 2B {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 2C - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 2D + {&CPU::AND, 4, "and", AddressingMode::Absolute, 3}, // 2D {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2E - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 2F - {&CPU::BMI, 2, "bmi", AddressingMode::Implied, 2}, // 30 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 31 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 32 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 33 + {&CPU::AND, 5, "and", AddressingMode::AbsoluteLong, 4}, // 2F + {&CPU::BMI, 2, "bmi", AddressingMode::Immediate8bits, 2}, // 30 + {&CPU::AND, 5, "and", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 31 + {&CPU::AND, 5, "and", AddressingMode::DirectPageIndirect, 2}, // 32 + {&CPU::AND, 7, "and", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 33 {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 34 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 35 + {&CPU::AND, 4, "and", AddressingMode::DirectPageIndexedByX, 2}, // 35 {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 36 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 37 + {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 37 {&CPU::SEC, 2, "sec", AddressingMode::Implied, 1}, // 38 - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 39 - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // 3A - {&CPU::BRK, 7, "tsc #-#", AddressingMode::Implied, 2}, // 3B + {&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByY, 3}, // 39 + {&CPU::DEC, 2, "dec", AddressingMode::Implied, 1}, // 3A + {&CPU::TSC, 2, "tsc", AddressingMode::Implied, 1}, // 3B {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 3D + {&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByX, 3}, // 3D {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 3E - {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 3F + {&CPU::AND, 5, "and", AddressingMode::AbsoluteIndexedByXLong, 4}, // 3F {&CPU::RTI, 6, "rti", AddressingMode::Implied, 1}, // 40 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 41 + {&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 41 {&CPU::BRK, 7, "wdm #-#", AddressingMode::Implied, 2}, // 42 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 43 + {&CPU::EOR, 4, "eor", AddressingMode::StackRelative, 2}, // 43 {&CPU::BRK, 7, "mvp #-#", AddressingMode::Implied, 2}, // 44 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 45 + {&CPU::EOR, 3, "eor", AddressingMode::DirectPage, 2}, // 45 {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 46 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 47 + {&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectLong, 2}, // 47 {&CPU::PHA, 3, "pha", AddressingMode::Implied, 1}, // 48 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 49 + {&CPU::EOR, 2, "eor", AddressingMode::ImmediateForA, 2}, // 49 {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4A {&CPU::PHK, 3, "phk", AddressingMode::Implied, 1}, // 4B {&CPU::JMP, 3, "jmp", AddressingMode::Absolute, 3}, // 4C - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 4D + {&CPU::EOR, 4, "eor", AddressingMode::Absolute, 3}, // 4D {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4E - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 4F - {&CPU::BVC, 2, "bvc", AddressingMode::Implied, 2}, // 50 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 51 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 52 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 53 + {&CPU::EOR, 5, "eor", AddressingMode::AbsoluteLong, 4}, // 4F + {&CPU::BVC, 2, "bvc", AddressingMode::Immediate8bits, 2}, // 50 + {&CPU::EOR, 5, "eor", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 51 + {&CPU::EOR, 5, "eor", AddressingMode::DirectPageIndirect, 2}, // 52 + {&CPU::EOR, 4, "eor", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 53 {&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // 54 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 55 + {&CPU::EOR, 4, "eor", AddressingMode::DirectPageIndexedByX, 2}, // 55 {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 56 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 57 + {&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 57 {&CPU::CLI, 2, "cli", AddressingMode::Implied, 1}, // 58 - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 59 + {&CPU::EOR, 4, "eor", AddressingMode::AbsoluteIndexedByY, 3}, // 59 {&CPU::PHY, 3, "phy", AddressingMode::Implied, 1}, // 5A - {&CPU::BRK, 7, "tcd #-#", AddressingMode::Implied, 2}, // 5B + {&CPU::TCD, 2, "tcd", AddressingMode::Implied, 1}, // 5B {&CPU::JML, 4, "jml", AddressingMode::Implied, 4}, // 5C - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 5D + {&CPU::EOR, 4, "eor", AddressingMode::AbsoluteIndexedByX, 3}, // 5D {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 5E - {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 5F - {&CPU::BRK, 7, "rtl #-#", AddressingMode::Implied, 2}, // 60 + {&CPU::EOR, 5, "eor", AddressingMode::AbsoluteIndexedByXLong, 4}, // 5F + {&CPU::RTL, 6, "rtl", AddressingMode::Implied, 1}, // 60 {&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 61 {&CPU::BRK, 7, "per #-#", AddressingMode::Implied, 2}, // 62 {&CPU::ADC, 4, "adc", AddressingMode::StackRelative, 2}, // 63 @@ -487,12 +530,12 @@ namespace ComSquare::CPU {&CPU::PLA, 4, "pla", AddressingMode::Implied, 1}, // 68 {&CPU::ADC, 2, "adc", AddressingMode::ImmediateForA, 2}, // 69 {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6A - {&CPU::BRK, 7, "rts #-#", AddressingMode::Implied, 2}, // 6B + {&CPU::RTS, 6, "rts", AddressingMode::Implied, 1}, // 6B {&CPU::JMP, 5, "jmp", AddressingMode::AbsoluteIndirect, 3}, // 6C {&CPU::ADC, 4, "adc", AddressingMode::Absolute, 3}, // 6D {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6E {&CPU::ADC, 5, "adc", AddressingMode::AbsoluteLong, 4}, // 6F - {&CPU::BVS, 2, "bvs", AddressingMode::Implied, 2}, // 70 + {&CPU::BVS, 2, "bvs", AddressingMode::Immediate8bits, 2}, // 70 {&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 71 {&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirect, 2}, // 72 {&CPU::ADC, 7, "adc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 73 @@ -503,28 +546,28 @@ namespace ComSquare::CPU {&CPU::SEI, 2, "sei", AddressingMode::Implied, 1}, // 78 {&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByY, 2}, // 79 {&CPU::PLY, 4, "ply", AddressingMode::Implied, 1}, // 7A - {&CPU::BRK, 7, "tdc #-#", AddressingMode::Implied, 2}, // 7B + {&CPU::TDC, 2, "tdc", AddressingMode::Implied, 1}, // 7B {&CPU::JMP, 6, "jmp", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // 7C {&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByX, 3}, // 7D {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 7E {&CPU::ADC, 5, "adc", AddressingMode::AbsoluteIndexedByXLong, 4}, // 7F - {&CPU::BRA, 3, "bra", AddressingMode::Implied, 2}, // 80 + {&CPU::BRA, 3, "bra", AddressingMode::Immediate8bits, 2}, // 80 {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 81 - {&CPU::BRL, 4, "brl", AddressingMode::Implied, 3}, // 82 + {&CPU::BRL, 4, "brl", AddressingMode::Absolute, 3}, // 82 {&CPU::STA, 4, "sta", AddressingMode::StackRelative, 2}, // 83 {&CPU::STY, 3, "sty", AddressingMode::DirectPage, 2}, // 84 {&CPU::STA, 3, "sta", AddressingMode::DirectPage, 2}, // 85 {&CPU::STX, 3, "stx", AddressingMode::DirectPage, 2}, // 86 {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectLong, 2}, // 87 - {&CPU::BRK, 7, "dey #-#", AddressingMode::Implied, 2}, // 88 + {&CPU::DEY, 2, "dey", AddressingMode::Implied, 1}, // 88 {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 89 - {&CPU::BRK, 7, "txa #-#", AddressingMode::Implied, 2}, // 8A + {&CPU::TXA, 2, "txa", AddressingMode::Implied, 2}, // 8A {&CPU::PHB, 3, "phb", AddressingMode::Implied, 1}, // 8B {&CPU::STY, 4, "sty", AddressingMode::Absolute, 3}, // 8C {&CPU::STA, 4, "sta", AddressingMode::Absolute, 3}, // 8D {&CPU::STX, 4, "stx", AddressingMode::Absolute, 3}, // 8E {&CPU::STA, 5, "sta", AddressingMode::AbsoluteLong, 4}, // 8F - {&CPU::BCC, 2, "bcc", AddressingMode::Implied, 2}, // 90 + {&CPU::BCC, 2, "bcc", AddressingMode::Immediate8bits, 2}, // 90 {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 91 {&CPU::STA, 5, "sta", AddressingMode::DirectPageIndirect, 2}, // 92 {&CPU::STA, 7, "sta", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 93 @@ -532,10 +575,10 @@ namespace ComSquare::CPU {&CPU::STA, 4, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 95 {&CPU::STX, 4, "stx", AddressingMode::DirectPageIndexedByY, 2}, // 96 {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 97 - {&CPU::BRK, 7, "tya #-#", AddressingMode::Implied, 2}, // 98 + {&CPU::TYA, 2, "tya", AddressingMode::Implied, 1}, // 98 {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByY, 3}, // 99 {&CPU::TXS, 2, "txs", AddressingMode::Implied, 1}, // 9A - {&CPU::BRK, 7, "txy #-#", AddressingMode::Implied, 2}, // 9B + {&CPU::TXY, 2, "txy", AddressingMode::Implied, 1}, // 9B {&CPU::STZ, 4, "stz", AddressingMode::Absolute, 3}, // 9C {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByX, 3}, // 9D {&CPU::STZ, 5, "stz", AddressingMode::AbsoluteIndexedByX, 3}, // 9E @@ -556,7 +599,7 @@ namespace ComSquare::CPU {&CPU::LDA, 4, "lda", AddressingMode::Absolute, 3}, // AD {&CPU::LDX, 4, "ldx", AddressingMode::Absolute, 3}, // AE {&CPU::LDA, 5, "lda", AddressingMode::AbsoluteLong, 4}, // AF - {&CPU::BCS, 2, "bcs", AddressingMode::Implied, 2}, // B0 + {&CPU::BCS, 2, "bcs", AddressingMode::Immediate8bits, 2}, // B0 {&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirectIndexedByY, 2}, // B1 {&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirect, 2}, // B2 {&CPU::LDA, 7, "lda", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // B3 @@ -566,67 +609,67 @@ namespace ComSquare::CPU {&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // B7 {&CPU::CLV, 7, "clv", AddressingMode::Implied, 1}, // B8 {&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByY, 3}, // B9 - {&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // BA - {&CPU::BRK, 7, "tyx #-#", AddressingMode::Implied, 2}, // BB + {&CPU::TSX, 2, "tsx", AddressingMode::Implied, 1}, // BA + {&CPU::TYX, 2, "tyx", AddressingMode::Implied, 1}, // BB {&CPU::LDY, 4, "ldy", AddressingMode::AbsoluteIndexedByX, 3}, // BC {&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByX, 3}, // BD {&CPU::LDX, 4, "ldx", AddressingMode::AbsoluteIndexedByY, 3}, // BE {&CPU::LDA, 5, "lda", AddressingMode::AbsoluteIndexedByXLong, 4}, // BF - {&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C0 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C1 + {&CPU::CPY, 2, "cpy", AddressingMode::ImmediateForX, 2}, // C0 + {&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectIndexedByX, 2}, // C1 {&CPU::REP, 3, "rep", AddressingMode::Immediate8bits, 2}, // C2 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C3 - {&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C4 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C5 - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // C6 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C7 + {&CPU::CMP, 4, "cmp", AddressingMode::StackRelative, 2}, // C3 + {&CPU::CPY, 3, "cpy", AddressingMode::DirectPage, 2}, // C4 + {&CPU::CMP, 3, "cmp", AddressingMode::DirectPage, 2}, // C5 + {&CPU::DEC, 5, "dec", AddressingMode::DirectPage, 2}, // C6 + {&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectLong, 2}, // C7 {&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C9 - {&CPU::BRK, 7, "dex #-#", AddressingMode::Implied, 2}, // CA + {&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::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // CC - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CD - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // CE - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CF - {&CPU::BNE, 2, "bne", AddressingMode::Implied, 2}, // D0 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D1 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D2 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D3 + {&CPU::CPY, 4, "cpy", AddressingMode::Absolute, 3}, // CC + {&CPU::CMP, 4, "cmp", AddressingMode::Absolute, 3}, // CD + {&CPU::DEC, 6, "dec", AddressingMode::Absolute, 3}, // CE + {&CPU::CMP, 6, "cmp", AddressingMode::AbsoluteLong, 4}, // CF + {&CPU::BNE, 2, "bne", AddressingMode::Immediate8bits, 2}, // D0 + {&CPU::CMP, 5, "cmp", AddressingMode::DirectPageIndirectIndexedByY, 2}, // D1 + {&CPU::CMP, 5, "cmp", AddressingMode::DirectPageIndirect, 2}, // D2 + {&CPU::CMP, 7, "cmp", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // D3 {&CPU::BRK, 7, "pei #-#", AddressingMode::Implied, 2}, // D4 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D5 - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // D6 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D7 - {&CPU::CLD, 27, "cld", AddressingMode::Implied, 2}, // D8 - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D9 + {&CPU::CMP, 4, "cmp", AddressingMode::DirectPageIndexedByX, 2}, // D5 + {&CPU::DEC, 6, "dec", AddressingMode::DirectPageIndexedByX, 2}, // D6 + {&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // D7 + {&CPU::CLD, 2, "cld", AddressingMode::Implied, 2}, // D8 + {&CPU::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByY, 3}, // D9 {&CPU::PHX, 3, "phx", AddressingMode::Implied, 1}, // DA {&CPU::BRK, 7, "stp #-#", AddressingMode::Implied, 2}, // DB {&CPU::JML, 7, "jml", AddressingMode::AbsoluteIndirectLong, 2}, // DC - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DD - {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // DE - {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DF - {&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E0 + {&CPU::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByX, 3}, // DD + {&CPU::DEC, 7, "dec", AddressingMode::AbsoluteIndexedByX, 3}, // DE + {&CPU::CMP, 5, "cmp", AddressingMode::AbsoluteIndexedByXLong, 4}, // DF + {&CPU::CPX, 2, "cpx", AddressingMode::ImmediateForX, 2}, // E0 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // E1 {&CPU::SEP, 3, "sep", AddressingMode::Immediate8bits, 2}, // E2 {&CPU::SBC, 4, "sbc", AddressingMode::StackRelative, 2}, // E3 - {&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E4 + {&CPU::CPX, 3, "cpx", AddressingMode::DirectPage, 2}, // E4 {&CPU::SBC, 3, "sbc", AddressingMode::DirectPage, 2}, // E5 - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // E6 + {&CPU::INC, 5, "inc", AddressingMode::DirectPage, 2}, // E6 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectLong, 2}, // E7 {&CPU::INX, 2, "inx", AddressingMode::Implied, 1}, // E8 {&CPU::SBC, 2, "sbc", AddressingMode::ImmediateForA, 2}, // E9 {&CPU::NOP, 2, "nop", AddressingMode::Implied, 1}, // EA - {&CPU::BRK, 7, "xba #-#", AddressingMode::Implied, 2}, // EB - {&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // EC + {&CPU::XBA, 3, "xba", AddressingMode::Implied, 1}, // EB + {&CPU::CPX, 4, "cpx", AddressingMode::Absolute, 3}, // EC {&CPU::SBC, 4, "sbc", AddressingMode::Absolute, 3}, // ED - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // EE + {&CPU::INC, 6, "inc", AddressingMode::Absolute, 3}, // EE {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteLong, 4}, // EF - {&CPU::BEQ, 2, "beq", AddressingMode::Implied, 2}, // F0 + {&CPU::BEQ, 2, "beq", AddressingMode::Immediate8bits, 2}, // F0 {&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // F1 {&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirect, 2}, // F2 {&CPU::SBC, 7, "sbc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // F3 {&CPU::BRK, 7, "pea #-#", AddressingMode::Implied, 2}, // F4 {&CPU::SBC, 4, "sbc", AddressingMode::DirectPageIndexedByX, 2}, // F5 - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // F6 + {&CPU::INC, 6, "inc", AddressingMode::DirectPageIndexedByX, 2}, // F6 {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // F7 {&CPU::SED, 2, "sed", AddressingMode::Implied, 1}, // F8 {&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByY, 3}, // F9 @@ -634,7 +677,7 @@ namespace ComSquare::CPU {&CPU::XCE, 2, "xce", AddressingMode::Implied, 1}, // FB {&CPU::JSR, 8, "jsr", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // FC {&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByX, 3}, // FD - {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // FE + {&CPU::INC, 7, "inc", AddressingMode::AbsoluteIndexedByX, 3}, // FE {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF }; public: diff --git a/sources/CPU/Instruction.hpp b/sources/CPU/Instruction.hpp index 5af02f4..8061d1e 100644 --- a/sources/CPU/Instruction.hpp +++ b/sources/CPU/Instruction.hpp @@ -41,9 +41,6 @@ namespace ComSquare::CPU StackRelativeIndirectIndexedByY, - ProgramCounterRelative, - ProgramCounterRelativeLong, - AbsoluteIndirect, AbsoluteIndirectIndexedByX, diff --git a/sources/CPU/Instructions/BitsInstructions.cpp b/sources/CPU/Instructions/BitsInstructions.cpp index d3ecefa..737bdc9 100644 --- a/sources/CPU/Instructions/BitsInstructions.cpp +++ b/sources/CPU/Instructions/BitsInstructions.cpp @@ -2,42 +2,29 @@ // Created by anonymus-raccoon on 2/20/20. // +#include #include "../../Models/Int24.hpp" #include "../CPU.hpp" namespace ComSquare::CPU { - int CPU::AND(uint24_t valueAddr, AddressingMode mode) + int CPU::TSB(uint24_t valueAddr, AddressingMode mode) { - unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; - unsigned value = this->_bus->read(valueAddr); + uint16_t value = this->_bus->read(valueAddr); if (!this->_registers.p.m) value += this->_bus->read(valueAddr + 1) << 8u; + value |= this->_registers.a; + this->_bus->write(valueAddr, value); + if (!this->_registers.p.m) + this->_bus->write(valueAddr + 1, value >> 8u); - this->_registers.a &= value; - this->_registers.p.n = this->_registers.a & negativeMask; - this->_registers.p.z = this->_registers.a == 0; + this->_registers.p.z = value == 0; - int cycles = !this->_registers.p.m; - switch (mode) { - case DirectPage: - case DirectPageIndirect: - case DirectPageIndirectLong: - case DirectPageIndexedByX: - case DirectPageIndirectIndexedByX: - case DirectPageIndirectIndexedByYLong: + int cycles = 0; + if (!this->_registers.p.m) + cycles += 2; + if (mode == DirectPage) cycles += this->_registers.dl != 0; - break; - case AbsoluteIndexedByX: - case AbsoluteIndexedByY: - cycles += this->_hasIndexCrossedPageBoundary; - break; - case DirectPageIndirectIndexedByY: - cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; - break; - default: - break; - } return cycles; } } \ No newline at end of file diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp index 782bfbb..1fc020a 100644 --- a/sources/CPU/Instructions/InternalInstruction.cpp +++ b/sources/CPU/Instructions/InternalInstruction.cpp @@ -199,72 +199,6 @@ namespace ComSquare::CPU return 0; } - int CPU::INX(uint24_t, AddressingMode) - { - this->_registers.x++; - - if (this->_registers.p.x_b) - this->_registers.x %= 0x100; - - unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; - this->_registers.p.z = this->_registers.x == 0; - this->_registers.p.n = this->_registers.x & negativeFlag; - return 0; - } - - int CPU::INY(uint24_t, AddressingMode) - { - this->_registers.y++; - - if (this->_registers.p.x_b) - this->_registers.y %= 0x100; - - unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; - this->_registers.p.z = this->_registers.y == 0; - this->_registers.p.n = this->_registers.y & negativeFlag; - return 0; - } - - int CPU::CPX(uint24_t valueAddr, AddressingMode mode) - { - unsigned value = this->_bus->read(valueAddr++); - - if (this->_registers.p.x_b) { - uint8_t x = this->_registers.x; - x -= value; - this->_registers.p.z = x == 0; - this->_registers.p.n = x & 0x80u; - } else { - value += this->_bus->read(valueAddr) << 8u; - uint16_t x = this->_registers.x; - x -= value; - this->_registers.p.z = x == 0; - this->_registers.p.n = x & 0x8000u; - } - this->_registers.p.c = this->_registers.x >= value; - return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0); - } - - int CPU::CPY(uint24_t valueAddr, AddressingMode mode) - { - unsigned value = this->_bus->read(valueAddr++); - - this->_registers.p.c = this->_registers.y >= value; - if (this->_registers.p.x_b) { - uint8_t y = this->_registers.y; - y -= value; - this->_registers.p.z = y == 0; - this->_registers.p.n = y & 0x80u; - } else { - value += this->_bus->read(valueAddr) << 8u; - uint16_t y = this->_registers.y; - y -= value; - this->_registers.p.z = y == 0; - this->_registers.p.n = y & 0x8000u; - } - return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0); - } - int CPU::BCC(uint24_t valueAddr, AddressingMode) { if (!this->_registers.p.c) @@ -352,4 +286,17 @@ namespace ComSquare::CPU { return 0; } + + int CPU::RTS(uint24_t, AddressingMode) + { + this->_registers.pc = this->_pop16() + 1; + return 0; + } + + int CPU::RTL(uint24_t, AddressingMode) + { + this->_registers.pc = this->_pop16() + 1; + this->_registers.dbr = this->_pop(); + return 0; + } } \ No newline at end of file diff --git a/sources/CPU/Instructions/Interrupts.cpp b/sources/CPU/Instructions/Interrupts.cpp index 1155da4..2e09647 100644 --- a/sources/CPU/Instructions/Interrupts.cpp +++ b/sources/CPU/Instructions/Interrupts.cpp @@ -24,16 +24,14 @@ namespace ComSquare::CPU int CPU::BRK(uint24_t, AddressingMode) { if (this->_isEmulationMode) { - this->_registers.pc += 2; this->_push(this->_registers.pc); - this->_registers.p.x_b = true; 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.brk; } else { this->_push(this->_registers.pbr); - this->_registers.pc += 2; this->_push(this->_registers.pc); this->_push(this->_registers.p.flags); this->_registers.p.i = true; @@ -47,16 +45,14 @@ namespace ComSquare::CPU int CPU::COP(uint24_t, AddressingMode) { if (this->_isEmulationMode) { - this->_registers.pc += 2; 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->_registers.pc += 2; this->_push(this->_registers.pc); this->_push(this->_registers.p.flags); this->_registers.p.i = true; diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp index 5b6e9e1..7d95161 100644 --- a/sources/CPU/Instructions/MathematicalOperations.cpp +++ b/sources/CPU/Instructions/MathematicalOperations.cpp @@ -12,8 +12,8 @@ namespace ComSquare::CPU unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c; if (!this->_registers.p.m) value += this->_bus->read(valueAddr + 1) << 8u; - unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; - unsigned maxValue = this->_isEmulationMode ? UINT8_MAX : UINT16_MAX; + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + unsigned maxValue = this->_registers.p.m ? UINT8_MAX : UINT16_MAX; this->_registers.p.c = static_cast(this->_registers.a) + value > maxValue; if ((this->_registers.a & negativeMask) == (value & negativeMask)) @@ -21,7 +21,7 @@ namespace ComSquare::CPU else this->_registers.p.v = false; this->_registers.a += value; - if (this->_isEmulationMode) + if (this->_registers.p.m) this->_registers.a %= 0x100; this->_registers.p.z = this->_registers.a == 0; this->_registers.p.n = this->_registers.a & negativeMask; @@ -51,7 +51,7 @@ namespace ComSquare::CPU int CPU::SBC(uint24_t valueAddr, AddressingMode mode) { - unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; unsigned value = this->_bus->read(valueAddr); if (!this->_registers.p.m) value += this->_bus->read(valueAddr + 1) << 8u; @@ -63,7 +63,7 @@ namespace ComSquare::CPU else this->_registers.p.v = false; this->_registers.a += ~value + oldCarry; - if (this->_isEmulationMode) + if (this->_registers.p.m) this->_registers.a %= 0x100; this->_registers.p.z = this->_registers.a == 0; this->_registers.p.n = this->_registers.a & negativeMask; @@ -90,4 +90,322 @@ namespace ComSquare::CPU } return cycles; } + + int CPU::ORA(uint24_t valueAddr, AddressingMode mode) + { + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + unsigned value = this->_bus->read(valueAddr); + if (!this->_registers.p.m) + value += this->_bus->read(valueAddr + 1) << 8u; + this->_registers.a |= value; + this->_registers.p.z = this->_registers.a == 0; + this->_registers.p.n = this->_registers.a & negativeMask; + + int cycles = !this->_registers.p.m; + switch (mode) { + case DirectPage: + case DirectPageIndirect: + case DirectPageIndirectLong: + case DirectPageIndexedByX: + case DirectPageIndirectIndexedByX: + case DirectPageIndirectIndexedByYLong: + cycles += this->_registers.dl != 0; + break; + case AbsoluteIndexedByX: + case AbsoluteIndexedByY: + cycles += this->_hasIndexCrossedPageBoundary; + break; + case DirectPageIndirectIndexedByY: + cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; + break; + default: + break; + } + return cycles; + } + + int CPU::DEX(uint24_t, AddressingMode) + { + unsigned negativeMask = this->_registers.p.x_b ? 0x80 : 0x8000; + + this->_registers.x--; + if (this->_registers.p.x_b) + this->_registers.xh = 0; + this->_registers.p.z = this->_registers.x == 0; + this->_registers.p.n = this->_registers.x & negativeMask; + return 0; + } + + int CPU::DEY(uint24_t, AddressingMode) + { + unsigned negativeMask = this->_registers.p.x_b ? 0x80 : 0x8000; + + this->_registers.y--; + if (this->_registers.p.x_b) + this->_registers.yh = 0; + this->_registers.p.z = this->_registers.y == 0; + this->_registers.p.n = this->_registers.y & negativeMask; + return 0; + } + + int CPU::CMP(uint24_t valueAddr, AddressingMode mode) + { + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + unsigned value = this->_bus->read(valueAddr); + if (!this->_registers.p.m) + value += this->_bus->read(valueAddr + 1) << 8u; + unsigned result = this->_registers.a - value; + if (this->_registers.p.m) + result %= 0x100; + + this->_registers.p.n = result & negativeMask; + this->_registers.p.z = result == 0; + this->_registers.p.c = this->_registers.a >= result; + + int cycles = !this->_registers.p.m; + switch (mode) { + case DirectPage: + case DirectPageIndirect: + case DirectPageIndirectLong: + case DirectPageIndexedByX: + case DirectPageIndirectIndexedByX: + case DirectPageIndirectIndexedByYLong: + cycles += this->_registers.dl != 0; + break; + case AbsoluteIndexedByX: + case AbsoluteIndexedByY: + cycles += this->_hasIndexCrossedPageBoundary; + break; + case DirectPageIndirectIndexedByY: + cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; + break; + default: + break; + } + return cycles; + } + + + int CPU::INX(uint24_t, AddressingMode) + { + this->_registers.x++; + + if (this->_registers.p.x_b) + this->_registers.x %= 0x100; + + unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; + this->_registers.p.z = this->_registers.x == 0; + this->_registers.p.n = this->_registers.x & negativeFlag; + return 0; + } + + int CPU::INY(uint24_t, AddressingMode) + { + this->_registers.y++; + + if (this->_registers.p.x_b) + this->_registers.y %= 0x100; + + unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; + this->_registers.p.z = this->_registers.y == 0; + this->_registers.p.n = this->_registers.y & negativeFlag; + return 0; + } + + int CPU::CPX(uint24_t valueAddr, AddressingMode mode) + { + unsigned value = this->_bus->read(valueAddr++); + + if (this->_registers.p.x_b) { + uint8_t x = this->_registers.x; + x -= value; + this->_registers.p.z = x == 0; + this->_registers.p.n = x & 0x80u; + } else { + value += this->_bus->read(valueAddr) << 8u; + uint16_t x = this->_registers.x; + x -= value; + this->_registers.p.z = x == 0; + this->_registers.p.n = x & 0x8000u; + } + this->_registers.p.c = this->_registers.x >= value; + return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0); + } + + int CPU::CPY(uint24_t valueAddr, AddressingMode mode) + { + unsigned value = this->_bus->read(valueAddr++); + + this->_registers.p.c = this->_registers.y >= value; + if (this->_registers.p.x_b) { + uint8_t y = this->_registers.y; + y -= value; + this->_registers.p.z = y == 0; + this->_registers.p.n = y & 0x80u; + } else { + value += this->_bus->read(valueAddr) << 8u; + uint16_t y = this->_registers.y; + y -= value; + this->_registers.p.z = y == 0; + this->_registers.p.n = y & 0x8000u; + } + return !this->_registers.p.x_b + (mode == DirectPage && this->_registers.dl != 0); + } + + int CPU::AND(uint24_t valueAddr, AddressingMode mode) + { + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + unsigned value = this->_bus->read(valueAddr); + if (!this->_registers.p.m) + value += this->_bus->read(valueAddr + 1) << 8u; + + this->_registers.a &= value; + this->_registers.p.n = this->_registers.a & negativeMask; + this->_registers.p.z = this->_registers.a == 0; + + int cycles = !this->_registers.p.m; + switch (mode) { + case DirectPage: + case DirectPageIndirect: + case DirectPageIndirectLong: + case DirectPageIndexedByX: + case DirectPageIndirectIndexedByX: + case DirectPageIndirectIndexedByYLong: + cycles += this->_registers.dl != 0; + break; + case AbsoluteIndexedByX: + case AbsoluteIndexedByY: + cycles += this->_hasIndexCrossedPageBoundary; + break; + case DirectPageIndirectIndexedByY: + cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; + break; + default: + break; + } + return cycles; + } + + int CPU::INC(uint24_t valueAddr, AddressingMode mode) + { + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + + unsigned result; + if (mode == Implied) { + this->_registers.a++; + if (this->_registers.p.m) + this->_registers.ah = 0; + result = this->_registers.a; + } else if (!this->_registers.p.m) { + result = this->_bus->read(valueAddr); + result += this->_bus->read(valueAddr + 1) << 8u; + result = (uint16_t)(result + 1); + this->_bus->write(valueAddr, result); + this->_bus->write(valueAddr + 1, result << 8u); + } else { + result = this->_bus->read(valueAddr); + result = (uint8_t)(result + 1); + this->_bus->write(valueAddr, result); + } + + this->_registers.p.z = result == 0; + this->_registers.p.n = result & negativeMask; + + switch (mode) { + case Implied: + return 0; + case Absolute: + return this->_registers.p.m == 0 ? 2 : 0; + case DirectPage: + case DirectPageIndexedByX: + return (this->_registers.p.m == 0 ? 2 : 0) + this->_registers.dl != 0 ; + case AbsoluteIndexedByX: + return (this->_registers.p.m == 0 ? 2 : 0) + this->_hasIndexCrossedPageBoundary; + default: + return 0; + } + } + + int CPU::DEC(uint24_t valueAddr, AddressingMode mode) + { + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + + unsigned result; + if (mode == Implied) { + this->_registers.a--; + if (this->_registers.p.m) + this->_registers.ah = 0; + result = this->_registers.a; + } else if (!this->_registers.p.m) { + result = this->_bus->read(valueAddr); + result += this->_bus->read(valueAddr + 1) << 8u; + result = (uint16_t)(result - 1); + this->_bus->write(valueAddr, result); + this->_bus->write(valueAddr + 1, result << 8u); + } else { + result = this->_bus->read(valueAddr); + result = (uint8_t)(result - 1); + this->_bus->write(valueAddr, result); + } + + this->_registers.p.z = result == 0; + this->_registers.p.n = result & negativeMask; + + switch (mode) { + case Implied: + return 0; + case Absolute: + return this->_registers.p.m == 0 ? 2 : 0; + case DirectPage: + case DirectPageIndexedByX: + return (this->_registers.p.m == 0 ? 2 : 0) + this->_registers.dl != 0 ; + case AbsoluteIndexedByX: + return (this->_registers.p.m == 0 ? 2 : 0) + this->_hasIndexCrossedPageBoundary; + default: + return 0; + } + } + + int CPU::EOR(uint24_t valueAddr, AddressingMode mode) + { + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + unsigned value = this->_bus->read(valueAddr); + if (!this->_registers.p.m) + value += this->_bus->read(valueAddr + 1) << 8u; + this->_registers.a ^= value; + this->_registers.p.z = this->_registers.a == 0; + this->_registers.p.n = this->_registers.a & negativeMask; + + int cycles = !this->_registers.p.m; + switch (mode) { + case DirectPage: + case DirectPageIndirect: + case DirectPageIndirectLong: + case DirectPageIndexedByX: + case DirectPageIndirectIndexedByX: + case DirectPageIndirectIndexedByYLong: + cycles += this->_registers.dl != 0; + break; + case AbsoluteIndexedByX: + case AbsoluteIndexedByY: + cycles += this->_hasIndexCrossedPageBoundary; + break; + case DirectPageIndirectIndexedByY: + cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; + break; + default: + break; + } + return cycles; + } + + int CPU::XBA(uint24_t, AddressingMode) + { + int tmp = this->_registers.ah; + this->_registers.ah = this->_registers.al; + this->_registers.al = tmp; + this->_registers.p.n = this->_registers.al & 0x80u; + this->_registers.p.z = this->_registers.al == 0; + return 0; + } } \ No newline at end of file diff --git a/sources/CPU/Instructions/TransferRegisters.cpp b/sources/CPU/Instructions/TransferRegisters.cpp index 4905071..18efae8 100644 --- a/sources/CPU/Instructions/TransferRegisters.cpp +++ b/sources/CPU/Instructions/TransferRegisters.cpp @@ -48,4 +48,106 @@ namespace ComSquare::CPU } return 0; } + + int CPU::TCD(uint24_t, AddressingMode) + { + this->_registers.d = this->_registers.a; + this->_registers.p.n = this->_registers.d & 0x8000u; + this->_registers.p.z = this->_registers.d == 0; + return 0; + } + + int CPU::TCS(uint24_t, AddressingMode) + { + this->_registers.s = this->_registers.a; + if (this->_isEmulationMode) + this->_registers.sh = 1; + return 0; + } + + int CPU::TDC(uint24_t, AddressingMode) + { + this->_registers.a = this->_registers.d; + this->_registers.p.n = this->_registers.a & 0x8000u; + this->_registers.p.z = this->_registers.a == 0; + return 0; + } + + int CPU::TSC(uint24_t, AddressingMode) + { + this->_registers.a = this->_registers.s; + this->_registers.p.n = this->_registers.a & 0x8000u; + this->_registers.p.z = this->_registers.a == 0; + return 0; + } + + int CPU::TSX(uint24_t, AddressingMode) + { + unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; + + this->_registers.x = this->_registers.s; + if (this->_registers.p.x_b) + this->_registers.xh = 0; + this->_registers.p.n = this->_registers.x & negativeFlag; + this->_registers.p.z = this->_registers.x == 0; + return 0; + } + + int CPU::TXA(uint24_t, AddressingMode) + { + unsigned negativeFlag = this->_registers.p.m ? 0x80u : 0x8000u; + + if (this->_registers.p.m) + this->_registers.al = this->_registers.xl; + else { + this->_registers.a = this->_registers.x; + if (this->_registers.p.x_b) + this->_registers.ah = 0; + } + this->_registers.p.n = this->_registers.a & negativeFlag; + this->_registers.p.z = this->_registers.a == 0; + return 0; + } + + int CPU::TYA(uint24_t, AddressingMode) + { + unsigned negativeFlag = this->_registers.p.m ? 0x80u : 0x8000u; + + if (this->_registers.p.m) + this->_registers.al = this->_registers.yl; + else { + this->_registers.a = this->_registers.y; + if (this->_registers.p.x_b) + this->_registers.ah = 0; + } + this->_registers.p.n = this->_registers.a & negativeFlag; + this->_registers.p.z = this->_registers.a == 0; + return 0; + } + + int CPU::TXY(uint24_t, AddressingMode) + { + unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; + + if (this->_registers.p.x_b) + this->_registers.yl = this->_registers.xl; + else + this->_registers.y = this->_registers.x; + this->_registers.p.n = this->_registers.y & negativeFlag; + this->_registers.p.z = this->_registers.y == 0; + return 0; + } + + int CPU::TYX(uint24_t, AddressingMode) + { + unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; + + if (this->_registers.p.x_b) + this->_registers.xl = this->_registers.yl; + else + this->_registers.x = this->_registers.y; + this->_registers.p.n = this->_registers.y & negativeFlag; + this->_registers.p.z = this->_registers.y == 0; + return 0; + } } \ No newline at end of file diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPU/CPUDebug.cpp similarity index 55% rename from sources/Debugger/CPUDebug.cpp rename to sources/Debugger/CPU/CPUDebug.cpp index 170fb23..5be3734 100644 --- a/sources/Debugger/CPUDebug.cpp +++ b/sources/Debugger/CPU/CPUDebug.cpp @@ -3,9 +3,9 @@ // #include "CPUDebug.hpp" -#include "../Utility/Utility.hpp" -#include "../Exceptions/InvalidOpcode.hpp" -#include "../CPU/CPU.hpp" +#include "../../Utility/Utility.hpp" +#include "../../Exceptions/InvalidOpcode.hpp" +#include "../../CPU/CPU.hpp" #include #include #include @@ -21,6 +21,7 @@ namespace ComSquare::Debugger _ui(), _model(*this), _painter(*this), + _stackModel(*this->_bus, *this), _snes(snes) { this->_window->setContextMenuPolicy(Qt::NoContextMenu); @@ -29,14 +30,26 @@ namespace ComSquare::Debugger this->_ui.setupUi(this->_window); - this->_updateDisassembly(0xFFFF - this->_registers.pc); //Parse the first page of the ROM (the code can't reach the second page without a jump). + this->_updateDisassembly(this->_cartridgeHeader.emulationInterrupts.reset, 0xFFFF - this->_cartridgeHeader.emulationInterrupts.reset); //Parse the first page of the ROM (the code can't reach the second page without a jump). this->_ui.disassembly->setModel(&this->_model); + this->_ui.disassembly->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); this->_ui.disassembly->horizontalHeader()->setStretchLastSection(true); - this->_ui.disassembly->resizeColumnsToContents(); - this->_ui.disassembly->verticalHeader()->setSectionResizeMode (QHeaderView::Fixed); + this->_ui.disassembly->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); this->_ui.disassembly->verticalHeader()->setHighlightSections(false); this->_ui.disassembly->setItemDelegate(&this->_painter); + this->_ui.stackView->setModel(&this->_stackModel); + this->_ui.stackView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + this->_ui.stackView->verticalHeader()->setSectionResizeMode (QHeaderView::Fixed); + this->_ui.stackView->verticalHeader()->setHighlightSections(false); + + + this->_ui.history->setModel(&this->_historyModel); + this->_ui.history->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + this->_ui.history->horizontalHeader()->setStretchLastSection(true); + this->_ui.history->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + this->_ui.history->verticalHeader()->hide(); + QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause); QMainWindow::connect(this->_ui.actionStep, &QAction::triggered, this, &CPUDebug::step); QMainWindow::connect(this->_ui.actionNext, &QAction::triggered, this, &CPUDebug::next); @@ -44,6 +57,7 @@ namespace ComSquare::Debugger QMainWindow::connect(this->_ui.disassembly->verticalHeader(), &QHeaderView::sectionClicked, this, &CPUDebug::toggleBreakpoint); this->_window->show(); this->_updateRegistersPanel(); + this->_updateDisassembly(this->_registers.pac, 0); } bool CPUDebug::isDebugger() @@ -65,7 +79,7 @@ namespace ComSquare::Debugger return 0xFF; if (this->_isStepping) { cycles = this->_executeInstruction(this->readPC()); - this->_updateDisassembly(); + this->_updateDisassembly(this->_registers.pac); return cycles; } @@ -102,7 +116,10 @@ namespace ComSquare::Debugger uint24_t pc = (this->_registers.pbr << 16u) | (this->_registers.pc - 1u); DisassemblyContext ctx = this->_getDisassemblyContext(); DisassembledInstruction instruction = this->_parseInstruction(pc, ctx); - this->_ui.logger->append((instruction.toString() + " - " + Utility::to_hex(opcode)).c_str()); + this->_registers.pc--; + this->_historyModel.log({opcode, instruction.name, instruction.argument, this->getProceededParameters()}); + this->_ui.history->scrollToBottom(); + this->_registers.pc++; unsigned ret = CPU::_executeInstruction(opcode); this->_updateRegistersPanel(); return ret; @@ -115,7 +132,7 @@ namespace ComSquare::Debugger this->_ui.actionPause->setText("Resume"); else this->_ui.actionPause->setText("Pause"); - this->_updateDisassembly(); + this->_updateDisassembly(this->_registers.pac); } void CPUDebug::step() @@ -164,8 +181,20 @@ namespace ComSquare::Debugger this->_ui.xIndexLineEdit->setText(Utility::to_hex(this->_registers.xl).c_str()); this->_ui.yIndexLineEdit->setText(Utility::to_hex(this->_registers.yl).c_str()); } - this->_ui.flagsLineEdit->setText(this->_getFlagsString().c_str()); this->_ui.emulationModeCheckBox->setCheckState(this->_isEmulationMode ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + + this->_ui.mCheckbox->setCheckState(this->_registers.p.m ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->_ui.xCheckbox->setCheckState(this->_registers.p.x_b ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->_ui.bCheckbox->setCheckState(this->_registers.p.x_b ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->_ui.iCheckbox->setCheckState(this->_registers.p.i ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->_ui.vCheckbox->setCheckState(this->_registers.p.v ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->_ui.dCheckbox->setCheckState(this->_registers.p.d ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->_ui.cCheckbox->setCheckState(this->_registers.p.c ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->_ui.zCheckbox->setCheckState(this->_registers.p.z ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->_ui.nCheckbox->setCheckState(this->_registers.p.n ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + + auto index = this->_stackModel.index(this->_registers.s / 2, 0); + this->_ui.stackView->scrollTo(index, QAbstractItemView::PositionAtCenter); } std::string CPUDebug::_getFlagsString() @@ -187,166 +216,44 @@ namespace ComSquare::Debugger void CPUDebug::clearHistory() { - this->_ui.logger->clear(); + this->_historyModel.clear(); } - void CPUDebug::_updateDisassembly(uint24_t refreshSize) + void CPUDebug::_updateDisassembly(uint24_t start, uint24_t refreshSize) { - auto first = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [this](DisassembledInstruction &i) { - return i.address >= this->_registers.pac; + auto first = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [start](DisassembledInstruction &i) { + return i.address >= start; }); - auto end = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(),[this, refreshSize](DisassembledInstruction &i) { - return i.address >= this->_registers.pac + refreshSize; + auto end = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(),[start, refreshSize](DisassembledInstruction &i) { + return i.address >= start + refreshSize; }); this->disassembledInstructions.erase(first, end); - auto next = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [this](DisassembledInstruction &i) { - return i.address >= this->_registers.pac; + auto next = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [start](DisassembledInstruction &i) { + return i.address >= start; }); - int row = next - this->disassembledInstructions.begin(); DisassemblyContext ctx = this->_getDisassemblyContext(); - std::vector nextInstructions = this->_disassemble(this->_registers.pac, refreshSize, ctx); + std::vector nextInstructions = this->_disassemble(start, refreshSize, ctx); this->disassembledInstructions.insert(next, nextInstructions.begin(), nextInstructions.end()); - if (this->_ui.disassembly->rowAt(0) > row || this->_ui.disassembly->rowAt(this->_ui.disassembly->height()) < row) - this->_ui.disassembly->scrollTo(this->_model.index(row, 0), QAbstractItemView::PositionAtCenter); + + int row = next - this->disassembledInstructions.begin(); + if (this->_ui.disassembly->rowAt(0) > row || this->_ui.disassembly->rowAt(this->_ui.disassembly->height()) < row) { + auto index = this->_model.index(row, 0); + this->_ui.disassembly->scrollTo(index, QAbstractItemView::PositionAtCenter); + } this->_ui.disassembly->viewport()->repaint(); } DisassemblyContext CPUDebug::_getDisassemblyContext() { - return {this->_registers.p.m, this->_registers.p.x_b, false}; - } - - std::vector CPUDebug::_disassemble(uint24_t pc, uint24_t length, DisassemblyContext &ctx) - { - std::vector map; - uint24_t endAddr = pc + length; - - while (pc < endAddr) { - DisassembledInstruction instruction = this->_parseInstruction(pc, ctx); - instruction.level = ctx.level; - map.push_back(instruction); - pc += instruction.size; - if (instruction.addressingMode == ImmediateForA && !ctx.mFlag) - pc++; - if (instruction.addressingMode == ImmediateForX && !ctx.xFlag) - pc++; - - if (instruction.opcode == 0x40 && ctx.isEmulationMode) { // RTI - ctx.mFlag = true; - ctx.xFlag = true; - } - if (instruction.opcode == 0xC2) { // REP - if (ctx.isEmulationMode) { - ctx.mFlag = true; - ctx.xFlag = true; - } else { - uint8_t m = this->_bus->read(pc - 1); - ctx.mFlag &= ~m & 0b00100000u; - ctx.xFlag &= ~m & 0b00010000u; - } - } - if (instruction.opcode == 0xE2) { // SEP - uint8_t m = this->_bus->read(pc - 1); - ctx.mFlag |= m & 0b00100000u; - ctx.xFlag |= m & 0b00010000u; - } - if (instruction.opcode == 0x28) { // PLP - if (ctx.isEmulationMode) { - ctx.mFlag = true; - ctx.xFlag = true; - } else - ctx.level = Compromised; - } - if (instruction.opcode == 0xFB) {// XCE - ctx.level = Unsafe; - ctx.isEmulationMode = false; // The most common use of the XCE is to enable native mode at the start of the ROM so we guess that it has done that. - } - } - return map; - } - - DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc, DisassemblyContext &ctx) - { - uint24_t opcode = this->_bus->read(pc, true); - Instruction instruction = this->_instructions[opcode]; - std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx); - return DisassembledInstruction(instruction, pc, argument, opcode); - } - - std::string CPUDebug::_getInstructionParameter(Instruction &instruction, uint24_t pc, DisassemblyContext &ctx) - { - switch (instruction.addressingMode) { - case Implied: - return ""; - case ImmediateForA: - return this->_getImmediateValue(pc, !ctx.mFlag); - case ImmediateForX: - return this->_getImmediateValue(pc, !ctx.xFlag); - case Immediate8bits: - return this->_getImmediateValue(pc, false); - 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 "???"; - } - } - - std::string CPUDebug::_getImmediateValue(uint24_t pc, bool dual) - { - unsigned value = this->_bus->read(pc, true); - - if (dual) - value += this->_bus->read(pc + 1, true) << 8u; - std::stringstream ss; - ss << "#$" << std::hex << value; - return ss.str(); - } - - std::string CPUDebug::_getDirectValue(uint24_t pc) - { - std::stringstream ss; - ss << "$" << std::hex << static_cast(this->_bus->read(pc, true)); - return ss.str(); - } - - std::string CPUDebug::_getAbsoluteValue(uint24_t pc) - { - std::stringstream ss; - ss << "$" << std::hex << (this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u)); - return ss.str(); - } - - std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc) - { - unsigned value = this->_bus->read(pc++, true); - value += this->_bus->read(pc++, true) << 8u; - value += this->_bus->read(pc, true) << 16u; - - std::stringstream ss; - ss << "$" << std::hex << value; - return ss.str(); - } - - std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc) - { - unsigned value = this->_bus->read(pc, true); - - std::stringstream ss; - ss << "$" << std::hex << value << ", x"; - return ss.str(); + return {this->_registers.p.m, this->_registers.p.x_b, this->_isEmulationMode}; } int CPUDebug::RESB() { CPU::RESB(); + this->disassembledInstructions.clear(); + this->_updateDisassembly(0xFFFF - this->_cartridgeHeader.emulationInterrupts.reset); this->_updateRegistersPanel(); return (0); } @@ -361,12 +268,22 @@ namespace ComSquare::Debugger return this->_registers.pac; } - DisassembledInstruction::DisassembledInstruction(const CPU::Instruction &instruction, uint24_t addr, std::string arg, uint8_t op) - : CPU::Instruction(instruction), address(addr), argument(std::move(arg)), opcode(op) {} - - std::string DisassembledInstruction::toString() + uint16_t CPUDebug::getStackPointer() { - return this->name + " " + this->argument; + return this->_registers.s; + } + + std::string CPUDebug::getProceededParameters() + { + uint24_t pac = this->_registers.pac; + this->_bus->forceSilence = true; + Instruction instruction = this->_instructions[this->readPC()]; + uint24_t valueAddr = this->_getValueAddr(instruction); + this->_registers.pac = pac; + this->_bus->forceSilence = false; + if (instruction.size == 1) + return ""; + return "[" + Utility::to_hex(valueAddr, Utility::AsmPrefix) + "]"; } } @@ -384,21 +301,28 @@ int DisassemblyModel::rowCount(const QModelIndex &) const QVariant DisassemblyModel::data(const QModelIndex &index, int role) const { - if (role != Qt::DisplayRole && role != Qt::DecorationRole) - return QVariant(); ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[index.row()]; - if (role == Qt::DecorationRole) { - if (index.column() == 3 && instruction.level == ComSquare::Debugger::TrustLevel::Unsafe) + + switch (role) { + case Qt::DecorationRole: + if (index.column() == 2 && instruction.level == ComSquare::Debugger::TrustLevel::Unsafe) return QColor(Qt::yellow); - if (index.column() == 3 && instruction.level == ComSquare::Debugger::TrustLevel::Compromised) + if (index.column() == 2 && instruction.level == ComSquare::Debugger::TrustLevel::Compromised) return QColor(Qt::red); return QVariant(); - } - switch (index.column()) { - case 0: - return QString(instruction.name.c_str()); - case 1: - return QString(instruction.argument.c_str()); + case Qt::DisplayRole: + switch (index.column()) { + case 0: + return QString(instruction.name.c_str()); + case 1: + return QString(instruction.argument.c_str()); + case 3: + if (instruction.address != this->_cpu.getPC()) + return QVariant(); + return QString(this->_cpu.getProceededParameters().c_str()); + default: + return QVariant(); + } default: return QVariant(); } @@ -406,8 +330,20 @@ QVariant DisassemblyModel::data(const QModelIndex &index, int role) const QVariant DisassemblyModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Horizontal) - return QVariant(); + if (orientation == Qt::Horizontal) { + switch (section) { + case 0: + return QString("INST"); + case 1: + return QString("Parameter"); + case 2: + return QString("Thrust"); + case 3: + return QString("Data Address"); + default: + return QVariant(); + } + } if (role != Qt::DisplayRole) return QVariant(); ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[section]; @@ -442,3 +378,114 @@ QSize RowPainter::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) co { return QSize(); } + +StackModel::StackModel(ComSquare::Memory::MemoryBus &bus, ComSquare::Debugger::CPUDebug &cpu) : _bus(bus), _cpu(cpu) { } + +int StackModel::rowCount(const QModelIndex &) const +{ + return 0x10000 / 2; +} + +int StackModel::columnCount(const QModelIndex &) const +{ + return 2; +} + +QVariant StackModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::BackgroundRole) { + if (index.row() * 2 + index.column() == this->_cpu.getStackPointer()) + return QColor(Qt::darkBlue); + if (index.row() * 2 + index.column() == this->_cpu.initialStackPointer) + return QColor(Qt::darkCyan); + } + if (role == Qt::TextAlignmentRole) + return Qt::AlignCenter; + if (role != Qt::DisplayRole) + return QVariant(); + uint16_t addr = index.row() * 2 + index.column(); + try { + uint8_t value = this->_bus.read(addr); + return (ComSquare::Utility::to_hex(value, ComSquare::Utility::NoPrefix).c_str()); + } catch (std::exception &) { + return "??"; + } +} + +QVariant StackModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal) + return QVariant(); + if (role != Qt::DisplayRole) + return QVariant(); + uint16_t addr = section * 2; + return QString(ComSquare::Utility::to_hex(addr, ComSquare::Utility::HexString::NoPrefix).c_str()); +} + +HistoryModel::HistoryModel() = default; + +int HistoryModel::rowCount(const QModelIndex &) const +{ + return this->_instructions.size(); +} + +int HistoryModel::columnCount(const QModelIndex &) const +{ + return 4; +} + +QVariant HistoryModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::TextAlignmentRole) + return Qt::AlignCenter; + if (role != Qt::DisplayRole) + return QVariant(); + + ComSquare::Debugger::ExecutedInstruction instruction = this->_instructions[index.row()]; + switch (index.column()) { + case 0: + return QString(ComSquare::Utility::to_hex(instruction.opcode, ComSquare::Utility::NoPrefix).c_str()); + case 1: + return QString(instruction.name.c_str()); + case 2: + return QString(instruction.params.c_str()); + case 3: + return QString(instruction.proceededParams.c_str()); + default: + return QVariant(); + } +} + +QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Vertical || role != Qt::DisplayRole) + return QVariant(); + switch (section) { + case 0: + return QString("op"); + case 1: + return QString("ins"); + case 2: + return QString("Parameter"); + case 3: + return QString("Pointer"); + default: + return QVariant(); + } +} + +void HistoryModel::log(const ComSquare::Debugger::ExecutedInstruction& instruction) +{ + int row = this->_instructions.size(); + this->beginInsertRows(QModelIndex(), row, row); + this->_instructions.push_back(instruction); + this->insertRow(row); + this->endInsertRows(); +} + +void HistoryModel::clear() +{ + this->beginResetModel(); + this->_instructions.clear(); + this->endResetModel(); +} \ No newline at end of file diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPU/CPUDebug.hpp similarity index 60% rename from sources/Debugger/CPUDebug.hpp rename to sources/Debugger/CPU/CPUDebug.hpp index fb04acb..ab596d0 100644 --- a/sources/Debugger/CPUDebug.hpp +++ b/sources/Debugger/CPU/CPUDebug.hpp @@ -6,17 +6,79 @@ #define COMSQUARE_CPUDEBUG_HPP #include -#include "../CPU/CPU.hpp" -#include "../Renderer/SFRenderer.hpp" -#include "../SNES.hpp" -#include "../../ui/ui_cpu.h" -#include "ClosableWindow.hpp" +#include "../../CPU/CPU.hpp" +#include "../../Renderer/SFRenderer.hpp" +#include "../../SNES.hpp" +#include "../../../ui/ui_cpu.h" +#include "../ClosableWindow.hpp" namespace ComSquare::Debugger { class CPUDebug; + + //! @brief An instruction that has already been executed. Used for the history viewer + struct ExecutedInstruction { + //! @brief Opcode of the instruction + uint8_t opcode; + //! @brief The name of the instruction + std::string name; + //! @brief Readable parameters (disassembly style) + std::string params; + //! @brief The address to read from after processing the parameter. + std::string proceededParams; + }; } +//! @brief The qt model that show the stack. +class StackModel : public QAbstractTableModel +{ +Q_OBJECT +private: + ComSquare::Memory::MemoryBus &_bus; + ComSquare::Debugger::CPUDebug &_cpu; +public: + explicit StackModel(ComSquare::Memory::MemoryBus &bus, ComSquare::Debugger::CPUDebug &cpu); + StackModel(const StackModel &) = delete; + const StackModel &operator=(const StackModel &) = delete; + ~StackModel() override = default; + + //! @brief The number of row the table has. + int rowCount(const QModelIndex &parent) const override; + //! @brief The number of column the table has. + int columnCount(const QModelIndex &parent) const override; + //! @brief Return a data representing the table cell. + 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 The qt model that show the history. +class HistoryModel : public QAbstractTableModel +{ +Q_OBJECT +private: + std::vector _instructions = {}; +public: + HistoryModel(); + HistoryModel(const HistoryModel &) = delete; + const HistoryModel &operator=(const HistoryModel &) = delete; + ~HistoryModel() override = default; + + //! @brief Log a new instruction + void log(const ComSquare::Debugger::ExecutedInstruction &); + //! @brief Remove every instructions of the history. + void clear(); + + //! @brief The number of row the table has. + int rowCount(const QModelIndex &parent) const override; + //! @brief The number of column the table has. + int columnCount(const QModelIndex &parent) const override; + //! @brief Return a data representing the table cell. + 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 The qt model that show the disassembly. class DisassemblyModel : public QAbstractTableModel { @@ -114,6 +176,10 @@ namespace ComSquare::Debugger DisassemblyModel _model; //! @brief A custom painter that highlight breakpoints and the PC's position. RowPainter _painter; + //! @brief The stack viewer's model. + StackModel _stackModel; + //! @brief The history model. + HistoryModel _historyModel; //! @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. @@ -128,7 +194,7 @@ namespace ComSquare::Debugger //! @param ctx The initial context of the processor before the disassembly begin. std::vector _disassemble(uint24_t startAddr, uint24_t size, DisassemblyContext &ctx); //! @brief Update disassembly with the new state of the processor. - void _updateDisassembly(uint24_t refreshSize = 0xFF); + void _updateDisassembly(uint24_t start, uint24_t refreshSize = 0xFF); //! @brief Parse the instruction at the program counter given to have human readable information. DisassembledInstruction _parseInstruction(uint24_t pc, DisassemblyContext &ctx); //! @brief Get the parameter of the instruction as an hexadecimal string. @@ -141,14 +207,42 @@ namespace ComSquare::Debugger //! @brief Return a printable string corresponding to the value of a 8 or 16 bits immediate addressing mode. //! @param dual Set this to true if the instruction take 16bits and not 8. (used for the immediate by a when the flag m is not set or the immediate by x if the flag x is not set). std::string _getImmediateValue(uint24_t pc, bool dual); - //! @brief Return a printable string corresponding to the value of a direct addressing mode. - std::string _getDirectValue(uint24_t pc); //! @brief Return a printable string corresponding to the value of an absolute addressing mode. std::string _getAbsoluteValue(uint24_t pc); //! @brief Return a printable string corresponding to the value of an absolute long addressing mode. std::string _getAbsoluteLongValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a direct addressing mode. + std::string _getDirectValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a direct indirect addressing mode. + std::string _getDirectIndirectValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a direct indirect long addressing mode. + std::string _getDirectIndirectLongValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a absolute indexed by x addressing mode. + std::string _getAbsoluteIndexByXValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a absolute indexed by x long addressing mode. + std::string _getAbsoluteIndexByXLongValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a absolute indexed by y addressing mode. + std::string _getAbsoluteIndexByYValue(uint24_t pc); //! @brief Return a printable string corresponding to the value of a direct index by x addressing mode. std::string _getDirectIndexedByXValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a direct index by y addressing mode. + std::string _getDirectIndexedByYValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a direct indirect index by x addressing mode. + std::string _getDirectIndexedByXIndirectValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a direct indirect index by y addressing mode. + std::string _getDirectIndirectIndexedByYValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a direct indirect index by y long addressing mode. + std::string _getDirectIndirectIndexedByYLongValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a stack relative addressing mode. + std::string _getStackRelativeValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a stack relative indirect indexed by y addressing mode. + std::string _getStackRelativeIndiretIndexdeByYValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a absolute indirect addressing mode. + std::string _getAbsoluteIndirectValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a absolute indirect indexed by x addressing mode. + std::string _getAbsoluteIndirectIndexedByXValue(uint24_t pc); + //! @brief Return a printable string corresponding to the value of a absolute indirect long addressing mode. + std::string _getAbsoluteIndirectLongValue(uint24_t pc); public: //! @brief Pause/Resume the CPU. @@ -167,8 +261,14 @@ namespace ComSquare::Debugger std::vector disassembledInstructions; //! @brief The list of breakpoints the user has set. std::vector breakpoints; + //! @brief Get a string representing the actual value of the arguments of the next instruction to execute. + std::string getProceededParameters(); //! @brief Return the current program counter of this CPU. uint24_t getPC(); + //! @brief Return the current stack pointer. + uint16_t getStackPointer(); + //! @brief The stack pointer before the execution of any instructions. + uint16_t initialStackPointer = this->_registers.s; //! @brief Update the UI when resetting the CPU. int RESB() override; //! @brief Convert a basic CPU to a debugging CPU. diff --git a/sources/Debugger/CPU/Disassembly.cpp b/sources/Debugger/CPU/Disassembly.cpp new file mode 100644 index 0000000..7541dd7 --- /dev/null +++ b/sources/Debugger/CPU/Disassembly.cpp @@ -0,0 +1,272 @@ +// +// Created by anonymus-raccoon on 4/3/20. +// + +#include +#include "CPUDebug.hpp" +#include "../../Utility/Utility.hpp" + +using namespace ComSquare::CPU; + +namespace ComSquare::Debugger +{ + DisassembledInstruction::DisassembledInstruction(const CPU::Instruction &instruction, uint24_t addr, std::string arg, uint8_t op) + : CPU::Instruction(instruction), address(addr), argument(std::move(arg)), opcode(op), level(Safe) {} + + std::string DisassembledInstruction::toString() + { + return this->name + " " + this->argument; + } + + std::vector CPUDebug::_disassemble(uint24_t pc, uint24_t length, DisassemblyContext &ctx) + { + std::vector map; + uint24_t endAddr = pc + length; + + while (pc < endAddr) { + DisassembledInstruction instruction = this->_parseInstruction(pc, ctx); + instruction.level = ctx.level; + map.push_back(instruction); + pc += instruction.size; + if (instruction.addressingMode == ImmediateForA && !ctx.mFlag) + pc++; + if (instruction.addressingMode == ImmediateForX && !ctx.xFlag) + pc++; + + if (instruction.opcode == 0x40 && ctx.isEmulationMode) { // RTI + ctx.mFlag = true; + ctx.xFlag = true; + } + if (instruction.opcode == 0xC2) { // REP + if (ctx.isEmulationMode) { + ctx.mFlag = true; + ctx.xFlag = true; + } else { + uint8_t m = this->_bus->read(pc - 1); + ctx.mFlag &= ~m & 0b00100000u; + ctx.xFlag &= ~m & 0b00010000u; + } + } + if (instruction.opcode == 0xE2) { // SEP + uint8_t m = this->_bus->read(pc - 1); + ctx.mFlag |= m & 0b00100000u; + ctx.xFlag |= m & 0b00010000u; + } + if (instruction.opcode == 0x28) { // PLP + if (ctx.isEmulationMode) { + ctx.mFlag = true; + ctx.xFlag = true; + } else + ctx.level = Compromised; + } + if (instruction.opcode == 0xFB) {// XCE + ctx.level = Unsafe; + ctx.isEmulationMode = false; // The most common use of the XCE is to enable native mode at the start of the ROM so we guess that it has done that. + } + } + return map; + } + + DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc, DisassemblyContext &ctx) + { + uint24_t opcode = this->_bus->read(pc, true); + Instruction instruction = this->_instructions[opcode]; + std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx); + return DisassembledInstruction(instruction, pc, argument, opcode); + } + + std::string CPUDebug::_getInstructionParameter(Instruction &instruction, uint24_t pc, DisassemblyContext &ctx) + { + switch (instruction.addressingMode) { + case Implied: + return ""; + + case Immediate8bits: + return this->_getImmediateValue(pc, false); + case ImmediateForA: + return this->_getImmediateValue(pc, !ctx.mFlag); + case ImmediateForX: + return this->_getImmediateValue(pc, !ctx.xFlag); + + case Absolute: + return this->_getAbsoluteValue(pc); + case AbsoluteLong: + return this->_getAbsoluteLongValue(pc); + + case DirectPage: + return this->_getDirectValue(pc); + case DirectPageIndexedByX: + return this->_getDirectIndexedByXValue(pc); + + case DirectPageIndirect: + return this->_getDirectIndirectValue(pc); + case DirectPageIndirectLong: + return this->_getDirectIndirectLongValue(pc); + case AbsoluteIndexedByX: + return this->_getAbsoluteIndexByXValue(pc); + case AbsoluteIndexedByXLong: + return this->_getAbsoluteIndexByXLongValue(pc); + case AbsoluteIndexedByY: + return this->_getAbsoluteIndexByYValue(pc); + case DirectPageIndexedByY: + return this->_getDirectIndexedByYValue(pc); + case DirectPageIndirectIndexedByX: + return this->_getDirectIndexedByXIndirectValue(pc); + case DirectPageIndirectIndexedByY: + return this->_getDirectIndirectIndexedByYValue(pc); + case DirectPageIndirectIndexedByYLong: + return this->_getDirectIndirectIndexedByYLongValue(pc); + case StackRelative: + return this->_getStackRelativeValue(pc); + case StackRelativeIndirectIndexedByY: + return this->_getStackRelativeIndiretIndexdeByYValue(pc); + case AbsoluteIndirect: + return this->_getAbsoluteIndirectValue(pc); + case AbsoluteIndirectIndexedByX: + return this->_getAbsoluteIndirectIndexedByXValue(pc); + case AbsoluteIndirectLong: + return this->_getAbsoluteIndirectLongValue(pc); + + default: + return "???"; + } + } + + std::string CPUDebug::_getImmediateValue(uint24_t pc, bool dual) + { + unsigned value = this->_bus->read(pc, true); + + if (dual) + value += this->_bus->read(pc + 1, true) << 8u; + std::stringstream ss; + ss << "#$" << std::hex << value; + return ss.str(); + } + + std::string CPUDebug::_getDirectValue(uint24_t pc) + { + return Utility::to_hex(this->_bus->read(pc, true), Utility::HexString::AsmPrefix); + } + + std::string CPUDebug::_getAbsoluteValue(uint24_t pc) + { + uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u); + return Utility::to_hex(value, Utility::HexString::AsmPrefix); + } + + std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc++, true); + value += this->_bus->read(pc++, true) << 8u; + value += this->_bus->read(pc, true) << 16u; + + return Utility::to_hex(value, Utility::HexString::AsmPrefix); + } + + std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc, true); + + std::stringstream ss; + ss << "$" << std::hex << value << ", x"; + return ss.str(); + } + + std::string CPUDebug::_getDirectIndexedByYValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc, true); + + std::stringstream ss; + ss << "$" << std::hex << value << ", y"; + return ss.str(); + } + + std::string CPUDebug::_getDirectIndirectValue(uint24_t pc) + { + return "(" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ")"; + } + + std::string CPUDebug::_getDirectIndirectLongValue(uint24_t pc) + { + return "[" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + "]"; + } + + std::string CPUDebug::_getAbsoluteIndexByXValue(uint24_t pc) + { + uint24_t value = this->_bus->read(pc) + (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); + return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", y"; + } + + std::string CPUDebug::_getAbsoluteIndexByXLongValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc++, true); + value += this->_bus->read(pc++, true) << 8u; + value += this->_bus->read(pc, true) << 16u; + + return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x"; + } + + std::string CPUDebug::_getDirectIndexedByXIndirectValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc, true); + + std::stringstream ss; + ss << "($" << std::hex << value << ", x)"; + return ss.str(); + } + + std::string CPUDebug::_getDirectIndirectIndexedByYValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc, true); + + std::stringstream ss; + ss << "($" << std::hex << value << "), y"; + return ss.str(); + } + + std::string CPUDebug::_getDirectIndirectIndexedByYLongValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc, true); + + std::stringstream ss; + ss << "[$" << std::hex << value << "], y"; + return ss.str(); + } + + std::string CPUDebug::_getStackRelativeValue(uint24_t pc) + { + return Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ", s"; + } + + std::string CPUDebug::_getStackRelativeIndiretIndexdeByYValue(uint24_t pc) + { + return "(" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ", s), y"; + } + + std::string CPUDebug::_getAbsoluteIndirectValue(uint24_t pc) + { + uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u); + return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")"; + } + + std::string CPUDebug::_getAbsoluteIndirectLongValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc++, true); + value += this->_bus->read(pc++, true) << 8u; + value += this->_bus->read(pc, true) << 16u; + + return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")"; + } + + std::string CPUDebug::_getAbsoluteIndirectIndexedByXValue(uint24_t pc) + { + uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u); + return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x)"; + } +} \ No newline at end of file diff --git a/sources/Debugger/MemoryBusDebug.cpp b/sources/Debugger/MemoryBusDebug.cpp index f8997fe..65ee12d 100644 --- a/sources/Debugger/MemoryBusDebug.cpp +++ b/sources/Debugger/MemoryBusDebug.cpp @@ -150,10 +150,14 @@ namespace ComSquare::Debugger uint8_t MemoryBusDebug::read(uint24_t addr, bool silence) { - if (!silence) { + if (!silence && !forceSilence) { auto accessor = this->getAccessor(addr); - uint8_t value = accessor->read(addr - accessor->getStart()); - this->_model.log(BusLog(false, addr, accessor, value, value)); + if (!accessor) { + this->_model.log(BusLog(true, addr, accessor, this->_openBus, this->_openBus)); + } else { + uint8_t value = accessor->read(addr - accessor->getStart()); + this->_model.log(BusLog(false, addr, accessor, value, value)); + } } return MemoryBus::read(addr); } @@ -167,7 +171,8 @@ namespace ComSquare::Debugger } catch (InvalidAddress &) { value = std::nullopt; } - this->_model.log(BusLog(true, addr, accessor, value, data)); + if (!forceSilence) + this->_model.log(BusLog(true, addr, accessor, value, data)); MemoryBus::write(addr, data); } diff --git a/sources/Memory/ARectangleMemory.cpp b/sources/Memory/ARectangleMemory.cpp index b60aa66..e7e9ff4 100644 --- a/sources/Memory/ARectangleMemory.cpp +++ b/sources/Memory/ARectangleMemory.cpp @@ -5,6 +5,7 @@ #include #include "ARectangleMemory.hpp" #include "../Exceptions/InvalidAddress.hpp" +#include "../Utility/Utility.hpp" namespace ComSquare::Memory { diff --git a/sources/Memory/ARectangleMemory.hpp b/sources/Memory/ARectangleMemory.hpp index f3adb8f..0a8f028 100644 --- a/sources/Memory/ARectangleMemory.hpp +++ b/sources/Memory/ARectangleMemory.hpp @@ -12,7 +12,7 @@ namespace ComSquare::Memory { //! @brief Superset of the AMemory to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at 0000 or end at FFFF). class ARectangleMemory : public AMemory { - private: + protected: //! @brief The first bank to map to. uint8_t _startBank = 0; //! @brief The last bank to map to. diff --git a/sources/Memory/MemoryBus.hpp b/sources/Memory/MemoryBus.hpp index 983ebfd..044462d 100644 --- a/sources/Memory/MemoryBus.hpp +++ b/sources/Memory/MemoryBus.hpp @@ -22,20 +22,22 @@ namespace ComSquare //! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector. std::vector> _memoryAccessors; - //! @brief The last value read via the memory bus. - uint8_t _openBus = 0; - //! @brief WRam, CPU, PPU & APU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring. //! @param console All the components. //! @param i Base address for the mirrors. void _mirrorComponents(SNES &console, unsigned i); - + protected: + //! @brief The last value read via the memory bus. + uint8_t _openBus = 0; public: MemoryBus() = default; MemoryBus(const MemoryBus &) = default; MemoryBus &operator=(const MemoryBus &) = default; ~MemoryBus() = default; + //! @brief Force silencing read to the bus. + bool forceSilence = false; + //! @brief Read data at a global address. //! @param addr The address to read from. //! @param silence Disable login to the memory bus's debugger (if enabled). Should only be used by other debuggers. diff --git a/sources/Memory/RectangleShadow.cpp b/sources/Memory/RectangleShadow.cpp index 9d924d4..424724a 100644 --- a/sources/Memory/RectangleShadow.cpp +++ b/sources/Memory/RectangleShadow.cpp @@ -3,6 +3,7 @@ // #include "RectangleShadow.hpp" +#include "../Utility/Utility.hpp" #include #include @@ -17,13 +18,13 @@ namespace ComSquare::Memory uint8_t RectangleShadow::read_internal(uint24_t addr) { - addr += this->_bankOffset << 16u; + addr += this->_bankOffset * (this->_endPage - this->_startPage); return this->_initial->read_internal(addr); } void RectangleShadow::write_internal(uint24_t addr, uint8_t data) { - addr += this->_bankOffset << 16u; + addr += this->_bankOffset * (this->_endPage - this->_startPage); this->_initial->write_internal(addr, data); } diff --git a/sources/Memory/RectangleShadow.hpp b/sources/Memory/RectangleShadow.hpp index d3130d9..365c85f 100644 --- a/sources/Memory/RectangleShadow.hpp +++ b/sources/Memory/RectangleShadow.hpp @@ -22,7 +22,7 @@ namespace ComSquare::Memory explicit RectangleShadow(std::shared_ptr initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage); RectangleShadow(const RectangleShadow &) = default; RectangleShadow &operator=(const RectangleShadow &) = default; - ~RectangleShadow() = default; + ~RectangleShadow() override = default; //! @brief Internal component read. Implement this as you would implement a basic AMemory's read. //! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous diff --git a/sources/SNES.cpp b/sources/SNES.cpp index 0686da6..6271b69 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -6,7 +6,7 @@ #include #include "SNES.hpp" #ifdef DEBUGGER_ENABLED -#include "Debugger/CPUDebug.hpp" +#include "Debugger/CPU/CPUDebug.hpp" #include "Debugger/APUDebug.hpp" #include "Debugger/MemoryBusDebug.hpp" #include "Debugger/CGramDebug.hpp" diff --git a/tests/CPU/Math/testADC.cpp b/tests/CPU/Math/testADC.cpp index 00a5106..3d4f193 100644 --- a/tests/CPU/Math/testADC.cpp +++ b/tests/CPU/Math/testADC.cpp @@ -67,7 +67,7 @@ Test(ADC, overflowEmulation) Test(ADC, signedOverflow) { Init() - snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = false; snes.cpu->_registers.a = 0x7FFF; snes.wram->_data[0] = 0x1; snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied); @@ -81,7 +81,7 @@ Test(ADC, signedOverflow) Test(ADC, signedOverflowEmulated) { Init() - snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; snes.cpu->_registers.a = 0x007F; snes.wram->_data[0] = 0x1; snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied); @@ -95,7 +95,7 @@ Test(ADC, signedOverflowEmulated) Test(ADC, negative) { Init() - snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = false; snes.cpu->_registers.a = 0x8FFF; snes.wram->_data[0] = 0x1; snes.cpu->ADC(0x0, ComSquare::CPU::AddressingMode::Implied); diff --git a/tests/CPU/Math/testCMP.cpp b/tests/CPU/Math/testCMP.cpp new file mode 100644 index 0000000..47968d4 --- /dev/null +++ b/tests/CPU/Math/testCMP.cpp @@ -0,0 +1,73 @@ +// +// Created by anonymus-raccoon on 4/6/20. +// + +#include +#include +#include "../../tests.hpp" +#include "../../../sources/SNES.hpp" +using namespace ComSquare; + +Test(CMP, underflow) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0; + snes.wram->_data[0] = 0x1; + snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(CMP, zero) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x5; + snes.wram->_data[0] = 0x5; + snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(CMP, nativeModeZero) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x5000; + snes.wram->_data[0] = 0x00; + snes.wram->_data[1] = 0x50; + snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(CMP, nativeModeNothing) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x8000; + snes.wram->_data[0] = 0x00; + snes.wram->_data[1] = 0x50; + snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(CMP, negative) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0xB000; + snes.wram->_data[0] = 0x00; + snes.wram->_data[1] = 0x10; + snes.cpu->CMP(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + diff --git a/tests/CPU/Math/testOthersMath.cpp b/tests/CPU/Math/testOthersMath.cpp new file mode 100644 index 0000000..a8a6093 --- /dev/null +++ b/tests/CPU/Math/testOthersMath.cpp @@ -0,0 +1,343 @@ +// +// Created by anonymus-raccoon on 4/3/20. +// + +#include +#include +#include "../../tests.hpp" +#include "../../../sources/SNES.hpp" +using namespace ComSquare; + +Test(DEX, simple) +{ + Init() + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.x = 0x57; + snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0x56, "The x index value should be 0x56 but it was 0x%x.", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEX, overflowEmul) +{ + Init() + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.x = 0; + snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0xFF, "The x index value should be 0xFF but it was 0x%x.", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEX, fakeOverflowNonEmul) +{ + Init() + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.x = 0xFF00; + snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0xFEFF, "The x index value should be 0xFEFF but it was 0x%x.", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEX, nonNegative) +{ + Init() + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.x = 0x80; + snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0x7F, "The x index value should be 0x7F but it was 0x%x.", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEX, zero) +{ + Init() + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.x = 1; + snes.cpu->DEX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0, "The x index value should be 0 but it was 0x%x.", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(DEY, simple) +{ + Init() + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.y = 0x57; + snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.y, 0x56, "The x index value should be 0x56 but it was 0x%x.", snes.cpu->_registers.y); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEY, overflowEmul) +{ + Init() + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.y = 0; + snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.y, 0xFF, "The x index value should be 0xFF but it was 0x%x.", snes.cpu->_registers.y); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEY, fakeOverflowNonEmul) +{ + Init() + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.y = 0xFF00; + snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.y, 0xFEFF, "The x index value should be 0xFEFF but it was 0x%x.", snes.cpu->_registers.y); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEY, nonNegative) +{ + Init() + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.y = 0x80; + snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.y, 0x7F, "The x index value should be 0x7F but it was 0x%x.", snes.cpu->_registers.y); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEY, zero) +{ + Init() + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.y = 1; + snes.cpu->DEY(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.y, 0, "The x index value should be 0 but it was 0x%x.", snes.cpu->_registers.y); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(ORA, simple) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x80; + snes.wram->_data[0] = 0x0F; + snes.cpu->ORA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x8F, "The accumulator's value should be 0x8F but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(ORA, simple2) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x80; + snes.wram->_data[0] = 0xF0; + snes.cpu->ORA(0x00, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0xF0, "The accumulator's value should be 0xF0 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(ORA, zero) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x00; + snes.wram->_data[0] = 0x00; + snes.cpu->ORA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x00, "The accumulator's value should be 0x00 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(INC, simple) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.wram->_data[0] = 0x56; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Absolute); + cr_assert_eq(snes.wram->_data[0], 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, negative) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.wram->_data[0] = 0x7F; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Absolute); + cr_assert_eq(snes.wram->_data[0], 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, accumulator) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x56; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, negativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x7F; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, nativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x5600; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x5601, "The incremented value should be 0x5601 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(INC, negativeNativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x8FFF; + snes.cpu->INC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x9000, "The incremented value should be 0x9000 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEC, simple) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.wram->_data[0] = 0x58; + snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Absolute); + cr_assert_eq(snes.wram->_data[0], 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEC, negative) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.wram->_data[0] = 0x81; + snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Absolute); + cr_assert_eq(snes.wram->_data[0], 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEC, accumulator) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x58; + snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x57, "The incremented value should be 0x57 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEC, negativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x81; + snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x80, "The incremented value should be 0x80 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEC, nativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x5602; + snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x5601, "The incremented value should be 0x5601 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(DEC, negativeNativeAccumulator) +{ + Init() + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x9001; + snes.cpu->DEC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x9000, "The incremented value should be 0x9000 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(EOR, simple) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x80; + snes.wram->_data[0] = 0x0F; + snes.cpu->EOR(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x8F, "The accumulator's value should be 0x8F but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(EOR, simple2) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x80; + snes.wram->_data[0] = 0xF0; + snes.cpu->EOR(0x00, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x70, "The accumulator's value should be 0x70 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(EOR, zero) +{ + Init() + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.a = 0x00; + snes.wram->_data[0] = 0x00; + snes.cpu->EOR(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x00, "The accumulator's value should be 0x00 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(XBA, zero) +{ + Init() + snes.cpu->_registers.a = 0x0001; + snes.cpu->XBA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x0100, "The accumulator's value should be 0x0100 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(XBA, negative) +{ + Init() + snes.cpu->_registers.a = 0x8001; + snes.cpu->XBA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x0180, "The accumulator's value should be 0x0180 but it was 0x%x.", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flags should be not set."); +} diff --git a/tests/CPU/Math/testSBC.cpp b/tests/CPU/Math/testSBC.cpp index 52b0186..e784481 100644 --- a/tests/CPU/Math/testSBC.cpp +++ b/tests/CPU/Math/testSBC.cpp @@ -62,7 +62,7 @@ Test(SBC, overflowEmulation) Init() snes.cpu->_isEmulationMode = true; snes.cpu->_registers.a = 0x1; - snes.cpu->_registers.p.m = false; + snes.cpu->_registers.p.m = true; snes.cpu->_registers.p.c = false; snes.wram->_data[0] = 0x02; snes.cpu->SBC(0x0, ComSquare::CPU::AddressingMode::Implied); diff --git a/tests/CPU/TransferRegisters.cpp b/tests/CPU/TransferRegisters.cpp index c840e2a..91ab304 100644 --- a/tests/CPU/TransferRegisters.cpp +++ b/tests/CPU/TransferRegisters.cpp @@ -144,4 +144,295 @@ Test(TXS, 8bitsIndex) cr_assert_eq(snes.cpu->_registers.s, 0x00CD, "The stack pointer should be 0x00CD but it was %x", snes.cpu->_registers.s); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TCD, emulationMode) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.d = 0x5656; + snes.cpu->_registers.a = 0xABCD; + snes.cpu->TCD(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.d, 0xABCD, "The direct page should be 0xABCD but it was %x", snes.cpu->_registers.d); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TCD, zero) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.d = 0x5656; + snes.cpu->_registers.a = 0x0; + snes.cpu->TCD(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.d, 0, "The direct page should be 0x0 but it was %x", snes.cpu->_registers.d); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); +} + +Test(TCS, emulationMode) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.s = 0x0156; + snes.cpu->_registers.a = 0xABCD; + snes.cpu->TCS(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.s, 0x01CD, "The stack pointer should be 0x01CD but it was %x", snes.cpu->_registers.s); +} + +Test(TCS, native) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.s = 0x0156; + snes.cpu->_registers.a = 0xABCD; + snes.cpu->TCS(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.s, 0xABCD, "The stack pointer should be 0xABCD but it was %x", snes.cpu->_registers.s); +} + +Test(TDC, emulationMode) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.d = 0xABCD; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TDC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0xABCD, "The accumulator should be 0xABCD but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TDC, zero) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.d = 0x0; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TDC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator should be 0x0 but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); +} + +Test(TSC, emulationMode) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.s = 0xABCD; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TSC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0xABCD, "The accumulator should be 0xABCD but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TSC, zero) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.s = 0x0; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TSC(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator should be 0x0 but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); +} + +Test(TSX, emulationMode) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.s = 0xABCD; + snes.cpu->_registers.x = 0x5656; + snes.cpu->TSX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0x00CD, "The x index should be 0x00CD but it was %x", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TSX, native) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.s = 0x8F00; + snes.cpu->_registers.x = 0x5656; + snes.cpu->TSX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0x8F00, "The x index should be 0x8F00 but it was %x", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TXA, double8bits) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.x = 0xABCD; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TXA, index8bits) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.x = 0x0BCD; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x00CD, "The accumulator should be 0x00CD but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TXA, accumulator8bits) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.x = 0x0BCD; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TXA, double16bits) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.x = 0xAB0D; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0xAB0D, "The accumulator should be 0xAB0D but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + + +Test(TYA, double8bits) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.y = 0xABCD; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TYA, index8bits) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.y = 0x0BCD; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x00CD, "The accumulator should be 0x00CD but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TYA, accumulator8bits) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = true; + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.y = 0x0BCD; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TYA, double16bits) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.y = 0xAB0D; + snes.cpu->_registers.a = 0x5656; + snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.a, 0xAB0D, "The accumulator should be 0xAB0D but it was %x", snes.cpu->_registers.a); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TXY, emulationMode) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.x = 0x0BCD; + snes.cpu->_registers.y = 0x5656; + snes.cpu->TXY(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.y, 0x56CD, "The y index should be 0x56CD but it was %x", snes.cpu->_registers.y); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TXY, nativeMode) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.x = 0xAB0D; + snes.cpu->_registers.y = 0x5656; + snes.cpu->TXY(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.y, 0xAB0D, "The y index should be 0xAB0D but it was %x", snes.cpu->_registers.y); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TYX, emulationMode) +{ + Init() + snes.cpu->_isEmulationMode = true; + snes.cpu->_registers.p.x_b = true; + snes.cpu->_registers.y = 0x0BCD; + snes.cpu->_registers.x = 0x5656; + snes.cpu->TYX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0x56CD, "The x index should be 0x56CD but it was %x", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); +} + +Test(TYX, nativeMode) +{ + Init() + snes.cpu->_isEmulationMode = false; + snes.cpu->_registers.p.x_b = false; + snes.cpu->_registers.y = 0xAB0D; + snes.cpu->_registers.x = 0x5656; + snes.cpu->TYX(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.x, 0xAB0D, "The x index should be 0xAB0D but it was %x", snes.cpu->_registers.x); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); } \ No newline at end of file diff --git a/tests/CPU/testAddressingMode.cpp b/tests/CPU/testAddressingMode.cpp index 485366e..f4ed3e4 100644 --- a/tests/CPU/testAddressingMode.cpp +++ b/tests/CPU/testAddressingMode.cpp @@ -181,45 +181,45 @@ Test(AddrMode, AbsoluteLongIndexByX) cr_assert_eq(snes.cpu->_registers.pac, 0x808003); } -Test(AddrMode, ProgramCounterRelativePositive) -{ - Init() - snes.cpu->_registers.pac = 0x808010; - snes.cartridge->_data[0x10] = 0x15; - cr_assert_eq(snes.cpu->_getProgramCounterRelativeAddr(), 0x808025, "Returned address was %x but was expecting 0x808025.", snes.cpu->_getProgramCounterRelativeAddr()); - cr_assert_eq(snes.cpu->_registers.pac, 0x808011); -} - -Test(AddrMode, ProgramCounterRelativeNegative) -{ - Init() - snes.cpu->_registers.pac = 0x808010; - snes.cartridge->_data[0x10] = -0x15; - cr_assert_eq(snes.cpu->_getProgramCounterRelativeAddr(), 0x807FFB, "Returned address was %x but was expecting 0x807FFB.", snes.cpu->_getProgramCounterRelativeAddr()); - cr_assert_eq(snes.cpu->_registers.pac, 0x808011); -} - -Test(AddrMode, ProgramCounterRelativeLongPositive) -{ - Init() - snes.cpu->_registers.pac = 0x808010; - snes.cartridge->_data[0x10] = 0x15; - snes.cartridge->_data[0x11] = 0x10; - auto addr = snes.cpu->_getProgramCounterRelativeLongAddr(); - cr_assert_eq(addr, 0x809025, "Returned address was %x but was expecting 0x809025.", addr); - cr_assert_eq(snes.cpu->_registers.pac, 0x808012); -} - -Test(AddrMode, ProgramCounterRelativeLongNegative) -{ - Init() - snes.cpu->_registers.pac = 0x808010; - snes.cartridge->_data[0x10] = 0x10; - snes.cartridge->_data[0x11] = -0x15; - auto addr = snes.cpu->_getProgramCounterRelativeLongAddr(); - cr_assert_eq(addr, 0x806B00, "Returned address was %x but was expecting 0x806B00.", addr); - cr_assert_eq(snes.cpu->_registers.pac, 0x808012); -} +//Test(AddrMode, ProgramCounterRelativePositive) +//{ +// Init() +// snes.cpu->_registers.pac = 0x808010; +// snes.cartridge->_data[0x10] = 0x15; +// cr_assert_eq(snes.cpu->_getProgramCounterRelativeAddr(), 0x808025, "Returned address was %x but was expecting 0x808025.", snes.cpu->_getProgramCounterRelativeAddr()); +// cr_assert_eq(snes.cpu->_registers.pac, 0x808011); +//} +// +//Test(AddrMode, ProgramCounterRelativeNegative) +//{ +// Init() +// snes.cpu->_registers.pac = 0x808010; +// snes.cartridge->_data[0x10] = -0x15; +// cr_assert_eq(snes.cpu->_getProgramCounterRelativeAddr(), 0x807FFB, "Returned address was %x but was expecting 0x807FFB.", snes.cpu->_getProgramCounterRelativeAddr()); +// cr_assert_eq(snes.cpu->_registers.pac, 0x808011); +//} +// +//Test(AddrMode, ProgramCounterRelativeLongPositive) +//{ +// Init() +// snes.cpu->_registers.pac = 0x808010; +// snes.cartridge->_data[0x10] = 0x15; +// snes.cartridge->_data[0x11] = 0x10; +// auto addr = snes.cpu->_getProgramCounterRelativeLongAddr(); +// cr_assert_eq(addr, 0x809025, "Returned address was %x but was expecting 0x809025.", addr); +// cr_assert_eq(snes.cpu->_registers.pac, 0x808012); +//} +// +//Test(AddrMode, ProgramCounterRelativeLongNegative) +//{ +// Init() +// snes.cpu->_registers.pac = 0x808010; +// snes.cartridge->_data[0x10] = 0x10; +// snes.cartridge->_data[0x11] = -0x15; +// auto addr = snes.cpu->_getProgramCounterRelativeLongAddr(); +// cr_assert_eq(addr, 0x806B00, "Returned address was %x but was expecting 0x806B00.", addr); +// cr_assert_eq(snes.cpu->_registers.pac, 0x808012); +//} Test(AddrMode, AbsoluteIndirect) { diff --git a/tests/CPU/testBits.cpp b/tests/CPU/testBits.cpp index a06c7af..5c4b334 100644 --- a/tests/CPU/testBits.cpp +++ b/tests/CPU/testBits.cpp @@ -35,7 +35,6 @@ Test(AND, nativeNegative) cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); } - Test(AND, emulationTest) { Init() @@ -48,3 +47,27 @@ Test(AND, emulationTest) cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); } +Test(TSB, emulationTest) +{ + Init() + snes.wram->_data[0] = 0b00110011; + snes.cpu->_registers.a = 0b00110111; + snes.cpu->_registers.p.m = true; + snes.cpu->TSB(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.wram->_data[0], 0b00110111, "The data in ram should be 0b00110111 but it was %x", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); +} + +Test(TSB, nativeTest) +{ + Init() + snes.wram->_data[0] = 0xF0; + snes.wram->_data[1] = 0x0F; + snes.cpu->_registers.a = 0x8008; + snes.cpu->_registers.p.m = false; + snes.cpu->TSB(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.wram->_data[0], 0xF8, "The first data in ram should be 0xF8 but it was %x", snes.wram->_data[0]); + cr_assert_eq(snes.wram->_data[1], 0x8F, "The second data in ram should be 0x8F but it was %x", snes.wram->_data[1]); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); +} + diff --git a/tests/CPU/testInterupts.cpp b/tests/CPU/testInterupts.cpp index cfb7a77..1a3b3e6 100644 --- a/tests/CPU/testInterupts.cpp +++ b/tests/CPU/testInterupts.cpp @@ -20,14 +20,14 @@ Test(CPU_emulated, BRK) snes.cpu->_registers.pbr = 0x15; snes.cpu->BRK(0x0, ComSquare::CPU::AddressingMode::Implied); cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc); - cr_assert_eq(snes.cpu->_registers.pbr, 0x15, "The PBR should be 0x15 but it was 0x%X", snes.cpu->_registers.pbr); + cr_assert_eq(snes.cpu->_registers.pbr, 0x0, "The PBR should be 0x0 but it was 0x%X", snes.cpu->_registers.pbr); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.i, true, "The Interrupt disable flag should be set."); cr_assert_eq(snes.cpu->_registers.p.x_b, true, "The break flag should be set."); int data = snes.cpu->_pop(); cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data); data = snes.cpu->_pop16(); - cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); + cr_assert_eq(data, 0x156u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); } Test(CPU_native, BRK) @@ -46,7 +46,7 @@ Test(CPU_native, BRK) int data = snes.cpu->_pop(); cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data); data = snes.cpu->_pop16(); - cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); + cr_assert_eq(data, 0x156u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x156).", data); data = snes.cpu->_pop(); cr_assert_eq(data, 0x15, "The program bank register should be pushed on the stack but it was 0x%X (expected 0x15).", data); } @@ -61,14 +61,14 @@ Test(CPU_emulated, COP) snes.cpu->_registers.pbr = 0x15; snes.cpu->COP(0x0, ComSquare::CPU::AddressingMode::Implied); cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc); - cr_assert_eq(snes.cpu->_registers.pbr, 0x15, "The PBR should be 0x15 but it was 0x%X", snes.cpu->_registers.pbr); + cr_assert_eq(snes.cpu->_registers.pbr, 0x0, "The PBR should be 0x0 but it was 0x%X", snes.cpu->_registers.pbr); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.i, true, "The Interrupt disable flag should be set."); cr_assert_eq(snes.cpu->_registers.p.x_b, false, "The break flag should not be set."); int data = snes.cpu->_pop(); cr_assert_eq(data, 0x0F, "The Status Registers should be pushed into the stack with the value 0x0F but it was 0x%X (expected 0xF1).", data); data = snes.cpu->_pop16(); - cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); + cr_assert_eq(data, 0x156u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); } Test(CPU_native, COP) @@ -87,7 +87,7 @@ Test(CPU_native, COP) int data = snes.cpu->_pop(); cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data); data = snes.cpu->_pop16(); - cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data); + cr_assert_eq(data, 0x156u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x156).", data); data = snes.cpu->_pop(); cr_assert_eq(data, 0x15, "The program bank register should be pushed on the stack but it was 0x%X (expected 0x15).", data); } \ No newline at end of file diff --git a/tests/testRectangleMemory.cpp b/tests/testRectangleMemory.cpp new file mode 100644 index 0000000..71edf33 --- /dev/null +++ b/tests/testRectangleMemory.cpp @@ -0,0 +1,89 @@ +// +// Created by anonymus-raccoon on 4/6/20. +// + +#include +#include +#include "tests.hpp" +#include "../sources/SNES.hpp" +#include "../sources/Renderer/NoRenderer.hpp" +#include "../sources/PPU/PPU.hpp" +#include "../sources/Memory/RectangleShadow.hpp" +#include "../sources/Utility/Utility.hpp" + +using namespace ComSquare; + +Test(RectangleMemory, HorizontalRamRead) +{ + Ram::Ram ram(0xFF, Component::Rom, "Rom"); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + for (int i = 0x00; i < 0xFF; i++) + ram._data[i] = i; + for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000) + cr_assert_eq(ram.read(i), i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i), i >> 16, i); +} + +Test(RectangleMemory, HorizontalRamWrite) +{ + Ram::Ram ram(0xFF, Component::Rom, "Rom"); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000) + ram.write(i, i >> 16u); + for (int i = 0x00; i < 0xFF; i++) + cr_assert_eq(ram._data[i], i, "The ram's write put 0x%x but it should had put: 0x%x (addr: 0x%06x)", ram._data[i], i, i << 16u); +} + +Test(RectangleMemory, DualLineRamRead) +{ + Ram::Ram ram(0xFF * 2, Component::Rom, "Rom"); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0002); + for (int i = 0x00; i < 0xFF * 2; i++) + ram._data[i] = i; + for (uint24_t i = 0x000000, v = 0; v < 0xFF * 2; i += 0x010000, v += 2) { + cr_assert_eq(ram.read(i), (uint8_t)(v), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i), (uint8_t)(v), i); + cr_assert_eq(ram.read(i + 1), (uint8_t)(v + 1), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i + 1), (uint8_t)(v + 1), i + 1); + } +} + +Test(RectangleMemory, HorizontalRamShadowRead) +{ + std::shared_ptr ram = std::make_shared(0xFF, Component::Rom, "Rom"); + ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + Memory::RectangleShadow shadow(ram, 0x00, 0xFF, 0x8000, 0x8001); + for (int i = 0x00; i < 0xFF; i++) + ram->_data[i] = i; + for (uint24_t i = 0x008000; i < 0xFF8000; i += 0x010000) { + uint8_t v = shadow.read(i - shadow.getStart()); + cr_assert_eq(v, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, i >> 16, i); + }} + +Test(RectangleMemory, HorizontalRamShadowReadWithBankOffset) +{ + std::shared_ptr ram = std::make_shared(0xFF, Component::Rom, "Rom"); + ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + Memory::RectangleShadow shadow(ram, 0x80, 0xFF, 0x8000, 0x8001); + for (int i = 0x00; i < 0xFF; i++) + ram->_data[i] = i; + shadow.setBankOffset(0x80); + for (uint24_t i = 0x808000; i < 0xFF8000; i += 0x010000) { + uint8_t v = shadow.read(i - shadow.getStart()); + cr_assert_eq(v, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, i >> 16, i); + } +} + +Test(RectangleMemory, ShadowOffsetCartridge) +{ + std::shared_ptr ram = std::make_shared(0x3fff80, Component::Rom, "Rom"); + ram->setMemoryRegion(0x80, 0xFF, 0x8000, 0xFFFF); + Memory::RectangleShadow shadow(ram, 0xC0, 0xEF, 0x0000, 0x7FFF); + for (int i = 0x00; i < 0x3fff80; i++) + ram->_data[i] = i; + shadow.setBankOffset(0x40); + for (uint24_t i = 0xC00000; i < 0xEF7FFF; i += 0x1) { + if ((uint16_t)i > 0x7FFFu) + i += 0x010000 - 0x8000; + uint8_t v = shadow.read(i - shadow.getStart()); + uint8_t r = ram->read(i + 0x8000 - ram->getStart()); + cr_assert_eq(v, r, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, r, i); + } +} \ No newline at end of file diff --git a/ui/cpu.ui b/ui/cpu.ui index bbaf550..0f8d2f2 100644 --- a/ui/cpu.ui +++ b/ui/cpu.ui @@ -6,8 +6,8 @@ 0 0 - 971 - 709 + 1058 + 673 @@ -21,8 +21,8 @@ false - - + + @@ -54,6 +54,27 @@ + + + + + false + + + + + + + Stack Viewer + + + Qt::AlignCenter + + + + + + @@ -140,23 +161,13 @@ - - - Flags - - - - - - - Emulation mode - + Qt::RightToLeft @@ -168,15 +179,8 @@ - + - - - - Clear History - - - @@ -187,11 +191,180 @@ + + + + Clear History + + + - + + + + + Flags + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + false + + + + QLayout::SetDefaultConstraint + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + 26 + + + 7 + + + 0 + + + + + Memory Select (M) + + + + + + + Qt::RightToLeft + + + + + + + Index Select (X) + + + + + + + Qt::RightToLeft + + + + + + + Interupt Request Disable (I) + + + + + + + Qt::RightToLeft + + + + + + + Overflow (V) + + + + + + + Qt::RightToLeft + + + + + + + Decimal (D) + + + + + + + Qt::RightToLeft + + + + + + + Carry (C) + + + + + + + Qt::RightToLeft + + + + + + + Zero (Z) + + + + + + + Negative (N) + + + + + + + Qt::RightToLeft + + + + + + + Qt::RightToLeft + + + + + + + Break (B) + + + + + + + Qt::RightToLeft + + + + + + diff --git a/ui/ui_cpu.h b/ui/ui_cpu.h new file mode 100644 index 0000000..97769dd --- /dev/null +++ b/ui/ui_cpu.h @@ -0,0 +1,457 @@ +/******************************************************************************** +** Form generated from reading UI file 'cpu.ui' +** +** Created by: Qt User Interface Compiler version 5.14.1 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_CPU_H +#define UI_CPU_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_CPUView +{ +public: + QAction *actionPause; + QAction *actionStep; + QAction *actionNext; + QWidget *centralwidget; + QGridLayout *gridLayout_3; + QTableView *disassembly; + QGridLayout *gridLayout_2; + QTableView *stackView; + QLabel *label; + QFormLayout *formLayout; + QLabel *accumulatorLabel; + QLineEdit *accumulatorLineEdit; + QLabel *programBankRegisterLabel; + QLineEdit *programBankRegisterLineEdit; + QLabel *programCounterLabel; + QLineEdit *programCounterLineEdit; + QLabel *directBankLabel; + QLineEdit *directBankLineEdit; + QLabel *directPageLabel; + QLineEdit *directPageLineEdit; + QLabel *stackPointerLabel; + QLineEdit *stackPointerLineEdit; + QLabel *xIndexLabel; + QLineEdit *xIndexLineEdit; + QLabel *yIndexLabel; + QLineEdit *yIndexLineEdit; + QLabel *emulationModeLabel; + QCheckBox *emulationModeCheckBox; + QGridLayout *gridLayout; + QLabel *loggerLabel; + QPushButton *clear; + QTableView *history; + QGroupBox *formGroupBox; + QFormLayout *formLayout_2; + QLabel *negativeLabel; + QCheckBox *mCheckbox; + QLabel *zeroLabel; + QCheckBox *xCheckbox; + QLabel *carryLabel; + QCheckBox *iCheckbox; + QLabel *Overflow; + QCheckBox *vCheckbox; + QLabel *decimalLabel; + QCheckBox *dCheckbox; + QLabel *memoryAccumulatorSelectLabel; + QCheckBox *cCheckbox; + QLabel *indeXSelectLabel; + QLabel *irqDisableLabel; + QCheckBox *nCheckbox; + QCheckBox *zCheckbox; + QLabel *breakBLabel; + QCheckBox *bCheckbox; + QToolBar *toolBar; + + void setupUi(QMainWindow *CPUView) + { + if (CPUView->objectName().isEmpty()) + CPUView->setObjectName(QString::fromUtf8("CPUView")); + CPUView->resize(1058, 673); + QIcon icon; + icon.addFile(QString::fromUtf8(":/resources/Logo.png"), QSize(), QIcon::Normal, QIcon::Off); + CPUView->setWindowIcon(icon); + CPUView->setAutoFillBackground(false); + actionPause = new QAction(CPUView); + actionPause->setObjectName(QString::fromUtf8("actionPause")); + QIcon icon1; + icon1.addFile(QString::fromUtf8(":/resources/icons/play.svg"), QSize(), QIcon::Normal, QIcon::Off); + actionPause->setIcon(icon1); + actionStep = new QAction(CPUView); + actionStep->setObjectName(QString::fromUtf8("actionStep")); + QIcon icon2; + icon2.addFile(QString::fromUtf8(":/resources/icons/step.svg"), QSize(), QIcon::Normal, QIcon::Off); + actionStep->setIcon(icon2); + actionNext = new QAction(CPUView); + actionNext->setObjectName(QString::fromUtf8("actionNext")); + QIcon icon3; + icon3.addFile(QString::fromUtf8(":/resources/icons/continue.svg"), QSize(), QIcon::Normal, QIcon::Off); + actionNext->setIcon(icon3); + centralwidget = new QWidget(CPUView); + centralwidget->setObjectName(QString::fromUtf8("centralwidget")); + gridLayout_3 = new QGridLayout(centralwidget); + gridLayout_3->setObjectName(QString::fromUtf8("gridLayout_3")); + disassembly = new QTableView(centralwidget); + disassembly->setObjectName(QString::fromUtf8("disassembly")); + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + sizePolicy.setHorizontalStretch(1); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(disassembly->sizePolicy().hasHeightForWidth()); + disassembly->setSizePolicy(sizePolicy); + disassembly->setStyleSheet(QString::fromUtf8("")); + disassembly->setSelectionMode(QAbstractItemView::ExtendedSelection); + disassembly->setSelectionBehavior(QAbstractItemView::SelectRows); + disassembly->setShowGrid(false); + disassembly->setGridStyle(Qt::NoPen); + disassembly->horizontalHeader()->setVisible(false); + disassembly->horizontalHeader()->setHighlightSections(false); + + gridLayout_3->addWidget(disassembly, 0, 0, 3, 1); + + gridLayout_2 = new QGridLayout(); + gridLayout_2->setObjectName(QString::fromUtf8("gridLayout_2")); + stackView = new QTableView(centralwidget); + stackView->setObjectName(QString::fromUtf8("stackView")); + stackView->horizontalHeader()->setVisible(false); + + gridLayout_2->addWidget(stackView, 1, 0, 1, 1); + + label = new QLabel(centralwidget); + label->setObjectName(QString::fromUtf8("label")); + label->setAlignment(Qt::AlignCenter); + + gridLayout_2->addWidget(label, 0, 0, 1, 1); + + + gridLayout_3->addLayout(gridLayout_2, 0, 1, 1, 1); + + formLayout = new QFormLayout(); + formLayout->setObjectName(QString::fromUtf8("formLayout")); + accumulatorLabel = new QLabel(centralwidget); + accumulatorLabel->setObjectName(QString::fromUtf8("accumulatorLabel")); + + formLayout->setWidget(0, QFormLayout::LabelRole, accumulatorLabel); + + accumulatorLineEdit = new QLineEdit(centralwidget); + accumulatorLineEdit->setObjectName(QString::fromUtf8("accumulatorLineEdit")); + + formLayout->setWidget(0, QFormLayout::FieldRole, accumulatorLineEdit); + + programBankRegisterLabel = new QLabel(centralwidget); + programBankRegisterLabel->setObjectName(QString::fromUtf8("programBankRegisterLabel")); + + formLayout->setWidget(1, QFormLayout::LabelRole, programBankRegisterLabel); + + programBankRegisterLineEdit = new QLineEdit(centralwidget); + programBankRegisterLineEdit->setObjectName(QString::fromUtf8("programBankRegisterLineEdit")); + + formLayout->setWidget(1, QFormLayout::FieldRole, programBankRegisterLineEdit); + + programCounterLabel = new QLabel(centralwidget); + programCounterLabel->setObjectName(QString::fromUtf8("programCounterLabel")); + + formLayout->setWidget(2, QFormLayout::LabelRole, programCounterLabel); + + programCounterLineEdit = new QLineEdit(centralwidget); + programCounterLineEdit->setObjectName(QString::fromUtf8("programCounterLineEdit")); + + formLayout->setWidget(2, QFormLayout::FieldRole, programCounterLineEdit); + + directBankLabel = new QLabel(centralwidget); + directBankLabel->setObjectName(QString::fromUtf8("directBankLabel")); + + formLayout->setWidget(3, QFormLayout::LabelRole, directBankLabel); + + directBankLineEdit = new QLineEdit(centralwidget); + directBankLineEdit->setObjectName(QString::fromUtf8("directBankLineEdit")); + + formLayout->setWidget(3, QFormLayout::FieldRole, directBankLineEdit); + + directPageLabel = new QLabel(centralwidget); + directPageLabel->setObjectName(QString::fromUtf8("directPageLabel")); + + formLayout->setWidget(4, QFormLayout::LabelRole, directPageLabel); + + directPageLineEdit = new QLineEdit(centralwidget); + directPageLineEdit->setObjectName(QString::fromUtf8("directPageLineEdit")); + + formLayout->setWidget(4, QFormLayout::FieldRole, directPageLineEdit); + + stackPointerLabel = new QLabel(centralwidget); + stackPointerLabel->setObjectName(QString::fromUtf8("stackPointerLabel")); + + formLayout->setWidget(5, QFormLayout::LabelRole, stackPointerLabel); + + stackPointerLineEdit = new QLineEdit(centralwidget); + stackPointerLineEdit->setObjectName(QString::fromUtf8("stackPointerLineEdit")); + + formLayout->setWidget(5, QFormLayout::FieldRole, stackPointerLineEdit); + + xIndexLabel = new QLabel(centralwidget); + xIndexLabel->setObjectName(QString::fromUtf8("xIndexLabel")); + + formLayout->setWidget(6, QFormLayout::LabelRole, xIndexLabel); + + xIndexLineEdit = new QLineEdit(centralwidget); + xIndexLineEdit->setObjectName(QString::fromUtf8("xIndexLineEdit")); + + formLayout->setWidget(6, QFormLayout::FieldRole, xIndexLineEdit); + + yIndexLabel = new QLabel(centralwidget); + yIndexLabel->setObjectName(QString::fromUtf8("yIndexLabel")); + + formLayout->setWidget(7, QFormLayout::LabelRole, yIndexLabel); + + yIndexLineEdit = new QLineEdit(centralwidget); + yIndexLineEdit->setObjectName(QString::fromUtf8("yIndexLineEdit")); + + formLayout->setWidget(7, QFormLayout::FieldRole, yIndexLineEdit); + + emulationModeLabel = new QLabel(centralwidget); + emulationModeLabel->setObjectName(QString::fromUtf8("emulationModeLabel")); + + formLayout->setWidget(8, QFormLayout::LabelRole, emulationModeLabel); + + emulationModeCheckBox = new QCheckBox(centralwidget); + emulationModeCheckBox->setObjectName(QString::fromUtf8("emulationModeCheckBox")); + emulationModeCheckBox->setLayoutDirection(Qt::RightToLeft); + emulationModeCheckBox->setCheckable(true); + + formLayout->setWidget(8, QFormLayout::FieldRole, emulationModeCheckBox); + + + gridLayout_3->addLayout(formLayout, 0, 2, 2, 1); + + gridLayout = new QGridLayout(); + gridLayout->setObjectName(QString::fromUtf8("gridLayout")); + loggerLabel = new QLabel(centralwidget); + loggerLabel->setObjectName(QString::fromUtf8("loggerLabel")); + loggerLabel->setAlignment(Qt::AlignCenter); + + gridLayout->addWidget(loggerLabel, 0, 0, 1, 1); + + clear = new QPushButton(centralwidget); + clear->setObjectName(QString::fromUtf8("clear")); + + gridLayout->addWidget(clear, 2, 0, 1, 1); + + history = new QTableView(centralwidget); + history->setObjectName(QString::fromUtf8("history")); + + gridLayout->addWidget(history, 1, 0, 1, 1); + + + gridLayout_3->addLayout(gridLayout, 1, 1, 2, 1); + + formGroupBox = new QGroupBox(centralwidget); + formGroupBox->setObjectName(QString::fromUtf8("formGroupBox")); + formGroupBox->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); + formGroupBox->setFlat(false); + formGroupBox->setCheckable(false); + formLayout_2 = new QFormLayout(formGroupBox); + formLayout_2->setObjectName(QString::fromUtf8("formLayout_2")); + formLayout_2->setSizeConstraint(QLayout::SetDefaultConstraint); + formLayout_2->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); + formLayout_2->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); + formLayout_2->setContentsMargins(26, 7, 0, -1); + negativeLabel = new QLabel(formGroupBox); + negativeLabel->setObjectName(QString::fromUtf8("negativeLabel")); + + formLayout_2->setWidget(0, QFormLayout::LabelRole, negativeLabel); + + mCheckbox = new QCheckBox(formGroupBox); + mCheckbox->setObjectName(QString::fromUtf8("mCheckbox")); + mCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(0, QFormLayout::FieldRole, mCheckbox); + + zeroLabel = new QLabel(formGroupBox); + zeroLabel->setObjectName(QString::fromUtf8("zeroLabel")); + + formLayout_2->setWidget(1, QFormLayout::LabelRole, zeroLabel); + + xCheckbox = new QCheckBox(formGroupBox); + xCheckbox->setObjectName(QString::fromUtf8("xCheckbox")); + xCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(1, QFormLayout::FieldRole, xCheckbox); + + carryLabel = new QLabel(formGroupBox); + carryLabel->setObjectName(QString::fromUtf8("carryLabel")); + + formLayout_2->setWidget(3, QFormLayout::LabelRole, carryLabel); + + iCheckbox = new QCheckBox(formGroupBox); + iCheckbox->setObjectName(QString::fromUtf8("iCheckbox")); + iCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(3, QFormLayout::FieldRole, iCheckbox); + + Overflow = new QLabel(formGroupBox); + Overflow->setObjectName(QString::fromUtf8("Overflow")); + + formLayout_2->setWidget(4, QFormLayout::LabelRole, Overflow); + + vCheckbox = new QCheckBox(formGroupBox); + vCheckbox->setObjectName(QString::fromUtf8("vCheckbox")); + vCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(4, QFormLayout::FieldRole, vCheckbox); + + decimalLabel = new QLabel(formGroupBox); + decimalLabel->setObjectName(QString::fromUtf8("decimalLabel")); + + formLayout_2->setWidget(5, QFormLayout::LabelRole, decimalLabel); + + dCheckbox = new QCheckBox(formGroupBox); + dCheckbox->setObjectName(QString::fromUtf8("dCheckbox")); + dCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(5, QFormLayout::FieldRole, dCheckbox); + + memoryAccumulatorSelectLabel = new QLabel(formGroupBox); + memoryAccumulatorSelectLabel->setObjectName(QString::fromUtf8("memoryAccumulatorSelectLabel")); + + formLayout_2->setWidget(6, QFormLayout::LabelRole, memoryAccumulatorSelectLabel); + + cCheckbox = new QCheckBox(formGroupBox); + cCheckbox->setObjectName(QString::fromUtf8("cCheckbox")); + cCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(6, QFormLayout::FieldRole, cCheckbox); + + indeXSelectLabel = new QLabel(formGroupBox); + indeXSelectLabel->setObjectName(QString::fromUtf8("indeXSelectLabel")); + + formLayout_2->setWidget(7, QFormLayout::LabelRole, indeXSelectLabel); + + irqDisableLabel = new QLabel(formGroupBox); + irqDisableLabel->setObjectName(QString::fromUtf8("irqDisableLabel")); + + formLayout_2->setWidget(8, QFormLayout::LabelRole, irqDisableLabel); + + nCheckbox = new QCheckBox(formGroupBox); + nCheckbox->setObjectName(QString::fromUtf8("nCheckbox")); + nCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(8, QFormLayout::FieldRole, nCheckbox); + + zCheckbox = new QCheckBox(formGroupBox); + zCheckbox->setObjectName(QString::fromUtf8("zCheckbox")); + zCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(7, QFormLayout::FieldRole, zCheckbox); + + breakBLabel = new QLabel(formGroupBox); + breakBLabel->setObjectName(QString::fromUtf8("breakBLabel")); + + formLayout_2->setWidget(2, QFormLayout::LabelRole, breakBLabel); + + bCheckbox = new QCheckBox(formGroupBox); + bCheckbox->setObjectName(QString::fromUtf8("bCheckbox")); + bCheckbox->setLayoutDirection(Qt::RightToLeft); + + formLayout_2->setWidget(2, QFormLayout::FieldRole, bCheckbox); + + + gridLayout_3->addWidget(formGroupBox, 2, 2, 1, 1); + + CPUView->setCentralWidget(centralwidget); + toolBar = new QToolBar(CPUView); + toolBar->setObjectName(QString::fromUtf8("toolBar")); + toolBar->setMinimumSize(QSize(0, 0)); + toolBar->setMovable(false); + toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + toolBar->setFloatable(true); + CPUView->addToolBar(Qt::TopToolBarArea, toolBar); + + toolBar->addAction(actionPause); + toolBar->addAction(actionNext); + toolBar->addAction(actionStep); + + retranslateUi(CPUView); + + QMetaObject::connectSlotsByName(CPUView); + } // setupUi + + void retranslateUi(QMainWindow *CPUView) + { + CPUView->setWindowTitle(QCoreApplication::translate("CPUView", "CPU's Debugger", nullptr)); + actionPause->setText(QCoreApplication::translate("CPUView", "Continue", nullptr)); +#if QT_CONFIG(tooltip) + actionPause->setToolTip(QCoreApplication::translate("CPUView", "Pause or Resume instruction execution.", nullptr)); +#endif // QT_CONFIG(tooltip) +#if QT_CONFIG(shortcut) + actionPause->setShortcut(QCoreApplication::translate("CPUView", "C", nullptr)); +#endif // QT_CONFIG(shortcut) + actionStep->setText(QCoreApplication::translate("CPUView", "Step", nullptr)); +#if QT_CONFIG(tooltip) + actionStep->setToolTip(QCoreApplication::translate("CPUView", "Execute a single instruction", nullptr)); +#endif // QT_CONFIG(tooltip) +#if QT_CONFIG(shortcut) + actionStep->setShortcut(QCoreApplication::translate("CPUView", "S", nullptr)); +#endif // QT_CONFIG(shortcut) + actionNext->setText(QCoreApplication::translate("CPUView", "Next", nullptr)); +#if QT_CONFIG(tooltip) + actionNext->setToolTip(QCoreApplication::translate("CPUView", "Continue execution to the next line.", nullptr)); +#endif // QT_CONFIG(tooltip) +#if QT_CONFIG(shortcut) + actionNext->setShortcut(QCoreApplication::translate("CPUView", "N", nullptr)); +#endif // QT_CONFIG(shortcut) + label->setText(QCoreApplication::translate("CPUView", "Stack Viewer", nullptr)); + accumulatorLabel->setText(QCoreApplication::translate("CPUView", "Accumulator", nullptr)); + accumulatorLineEdit->setText(QString()); + programBankRegisterLabel->setText(QCoreApplication::translate("CPUView", "Program Bank", nullptr)); + programCounterLabel->setText(QCoreApplication::translate("CPUView", "Program Counter", nullptr)); + directBankLabel->setText(QCoreApplication::translate("CPUView", "Direct Bank", nullptr)); + directPageLabel->setText(QCoreApplication::translate("CPUView", "Direct Page", nullptr)); + stackPointerLabel->setText(QCoreApplication::translate("CPUView", "Stack Pointer", nullptr)); + xIndexLabel->setText(QCoreApplication::translate("CPUView", "X Index", nullptr)); + yIndexLabel->setText(QCoreApplication::translate("CPUView", "Y Index", nullptr)); + emulationModeLabel->setText(QCoreApplication::translate("CPUView", "Emulation mode", nullptr)); + loggerLabel->setText(QCoreApplication::translate("CPUView", "Instructions History", nullptr)); + clear->setText(QCoreApplication::translate("CPUView", "Clear History", nullptr)); + formGroupBox->setTitle(QCoreApplication::translate("CPUView", "Flags", nullptr)); + negativeLabel->setText(QCoreApplication::translate("CPUView", "Memory Select (M)", nullptr)); + zeroLabel->setText(QCoreApplication::translate("CPUView", "Index Select (X)", nullptr)); + carryLabel->setText(QCoreApplication::translate("CPUView", "Interupt Request Disable (I)", nullptr)); + Overflow->setText(QCoreApplication::translate("CPUView", "Overflow (V)", nullptr)); + decimalLabel->setText(QCoreApplication::translate("CPUView", "Decimal (D)", nullptr)); + memoryAccumulatorSelectLabel->setText(QCoreApplication::translate("CPUView", "Carry (C)", nullptr)); + indeXSelectLabel->setText(QCoreApplication::translate("CPUView", "Zero (Z)", nullptr)); + irqDisableLabel->setText(QCoreApplication::translate("CPUView", "Negative (N)", nullptr)); + breakBLabel->setText(QCoreApplication::translate("CPUView", "Break (B)", nullptr)); + toolBar->setWindowTitle(QCoreApplication::translate("CPUView", "toolBar", nullptr)); + } // retranslateUi + +}; + +namespace Ui { + class CPUView: public Ui_CPUView {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_CPU_H