diff --git a/sources/CPU/AddressingModes.cpp b/sources/CPU/AddressingModes.cpp index d19a985..3f649c2 100644 --- a/sources/CPU/AddressingModes.cpp +++ b/sources/CPU/AddressingModes.cpp @@ -14,6 +14,13 @@ namespace ComSquare::CPU return ret; } + uint24_t CPU::_getImmediateAddr16Bits() + { + uint24_t ret = this->_registers.pac; + this->_registers.pc += 2; + return ret; + } + uint24_t CPU::_getImmediateAddrForA() { uint24_t effective = this->_registers.pac; diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index 8116408..34a01ae 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -6,9 +6,7 @@ #include #include -#include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/InvalidAddress.hpp" -#include "../Exceptions/InvalidOpcode.hpp" namespace ComSquare::CPU { @@ -218,6 +216,8 @@ namespace ComSquare::CPU return 0; case Immediate8bits: return this->_getImmediateAddr8Bits(); + case Immediate16bits: + return this->_getImmediateAddr16Bits(); case ImmediateForA: return this->_getImmediateAddrForA(); case ImmediateForX: @@ -264,8 +264,6 @@ namespace ComSquare::CPU case AbsoluteIndirectIndexedByX: return this->_getAbsoluteIndirectIndexedByXAddr(); - default: - return 0; } } diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 1c6be7d..d0b0d47 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -198,8 +198,10 @@ namespace ComSquare::CPU //! @brief True if an addressing mode with an iterator (x, y) has crossed the page. (Used because crossing the page boundary take one more cycle to run certain instructions). bool _hasIndexCrossedPageBoundary = false; - //! @brief Immediate address mode is specified with a value in 8. (This functions returns the 24bit space address of the value). + //! @brief Immediate address mode is specified with a value in 8 bits. (This functions returns the 24bit space address of the value). uint24_t _getImmediateAddr8Bits(); + //! @brief Immediate address mode is specified with a value in 16 bits. (This functions returns the 24bit space address of the value). + uint24_t _getImmediateAddr16Bits(); //! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the m flag is unset. (This functions returns the 24bit space address of the value). uint24_t _getImmediateAddrForA(); //! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the x flag is unset. (This functions returns the 24bit space address of the value). @@ -431,6 +433,8 @@ namespace ComSquare::CPU int ROL(uint24_t, AddressingMode); // !@brief Rotate Right int ROR(uint24_t, AddressingMode); + //! @brief Push Effective PC Relative Indirect Address + int PER(uint24_t, AddressingMode); //! @brief All the instructions of the CPU. //! @info Instructions are indexed by their opcode @@ -533,7 +537,7 @@ namespace ComSquare::CPU {&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::PER, 6, "per", AddressingMode::Immediate16bits, 3}, // 62 {&CPU::ADC, 4, "adc", AddressingMode::StackRelative, 2}, // 63 {&CPU::STZ, 3, "stz", AddressingMode::DirectPage, 2}, // 64 {&CPU::ADC, 3, "adc", AddressingMode::DirectPage, 2}, // 65 @@ -606,7 +610,7 @@ namespace ComSquare::CPU {&CPU::TAY, 2, "tay", AddressingMode::Implied, 1}, // A8 {&CPU::LDA, 2, "lda", AddressingMode::ImmediateForA, 2}, // A9 {&CPU::TAX, 2, "tax", AddressingMode::Implied, 1}, // AA - {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // AB + {&CPU::BRK, 7, "plb #-#", AddressingMode::Implied, 2}, // AB {&CPU::LDY, 4, "ldy", AddressingMode::Absolute, 4}, // AC {&CPU::LDA, 4, "lda", AddressingMode::Absolute, 3}, // AD {&CPU::LDX, 4, "ldx", AddressingMode::Absolute, 3}, // AE diff --git a/sources/CPU/Instruction.hpp b/sources/CPU/Instruction.hpp index 8061d1e..f6ef811 100644 --- a/sources/CPU/Instruction.hpp +++ b/sources/CPU/Instruction.hpp @@ -17,6 +17,7 @@ namespace ComSquare::CPU Implied, Immediate8bits, + Immediate16bits, ImmediateForA, ImmediateForX, diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp index 1fc020a..d3ee972 100644 --- a/sources/CPU/Instructions/InternalInstruction.cpp +++ b/sources/CPU/Instructions/InternalInstruction.cpp @@ -184,6 +184,15 @@ namespace ComSquare::CPU return !this->_registers.p.x_b; } + int CPU::PER(uint24_t valueAddr, AddressingMode) + { + uint16_t value = this->_bus->read(valueAddr); + value += this->_bus->read(valueAddr + 1) << 8u; + value += this->_registers.pc; + this->_push(value); + return 0; + } + int CPU::XCE(uint24_t, AddressingMode) { bool oldCarry = this->_registers.p.c; diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp index 0619ece..6710426 100644 --- a/tests/CPU/testInternal.cpp +++ b/tests/CPU/testInternal.cpp @@ -914,4 +914,17 @@ Test(JML, simpleJump) snes.cpu->_registers.pc = 0x8000; snes.cpu->JML(0x10AB00, ComSquare::CPU::AddressingMode::Implied); cr_assert_eq(snes.cpu->_registers.pac, 0x10AB00, "The program counter should be equal to 0x10AB00 but it was 0x%x.", snes.cpu->_registers.pac); +} + +Test(PER, simple) +{ + Init() + snes.cpu->_registers.pac = 0x008005; + snes.cpu->_registers.s = 0x1FFF; + snes.wram->_data[0x0] = 0xFF; + snes.wram->_data[0x1] = 0xFF; + snes.cpu->PER(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.s, 0x1FFD, "The stack pointer should be equal to 0x1FFD but it was 0x%x.", snes.cpu->_registers.s); + uint16_t value = snes.cpu->_pop16(); + cr_assert_eq(value, 0x8004, "The pushed value should be equal to 0x8004 but it was 0x%x.", value); } \ No newline at end of file