diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index bdf0dd1..dc39527 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -348,6 +348,9 @@ namespace ComSquare::CPU case Instructions::TAY: this->TAY(); return 2; case Instructions::TXS: this->TXS(); return 2; + case Instructions::INX: this->INX(); return 2; + case Instructions::INY: this->INY(); return 2; + default: throw InvalidOpcode("CPU", opcode); } diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index ac0fecb..405d19b 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -330,7 +330,10 @@ namespace ComSquare::CPU TAX = 0xAA, TAY = 0xA8, - TXS = 0x9A + TXS = 0x9A, + + INX = 0xE8, + INY = 0xC8 }; //! @brief The main CPU @@ -490,6 +493,10 @@ namespace ComSquare::CPU void TAY(); //! @brief Transfer X to SP void TXS(); + //! @brief Increment the X register + void INX(); + //! @brief Increment the Y register + void INY(); public: explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader); CPU(const CPU &) = default; diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp index 6d13a76..dcc4421 100644 --- a/sources/CPU/Instructions/InternalInstruction.cpp +++ b/sources/CPU/Instructions/InternalInstruction.cpp @@ -164,4 +164,28 @@ namespace ComSquare::CPU this->_registers.yh = 0; } } + + void CPU::INX() + { + 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; + } + + void CPU::INY() + { + 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; + } } \ No newline at end of file diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp index 251b510..ac37181 100644 --- a/sources/Debugger/CPUDebug.cpp +++ b/sources/Debugger/CPUDebug.cpp @@ -171,6 +171,15 @@ namespace ComSquare::Debugger return ss.str(); } + std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc) + { + unsigned value = this->_bus->read(pc); + + std::stringstream ss; + ss << "$" << std::hex << value << ", x"; + return ss.str(); + } + std::string CPUDebug::_getInstructionString(uint24_t pc) { uint8_t opcode = this->_bus->read(pc++); @@ -191,7 +200,7 @@ namespace ComSquare::Debugger case Instructions::ADC_ABSX: return "ADC"; case Instructions::ADC_ABSXl:return "ADC"; case Instructions::ADC_ABSY: return "ADC"; - case Instructions::ADC_DPX: return "ADC"; + case Instructions::ADC_DPX: return "ADC " + this->_getDirectIndexedByXValue(pc); case Instructions::ADC_DPXi: return "ADC"; case Instructions::ADC_DPYi: return "ADC"; case Instructions::ADC_DPYil:return "ADC"; @@ -206,7 +215,7 @@ namespace ComSquare::Debugger case Instructions::STA_ABSX: return "STA"; case Instructions::STA_ABSXl:return "STA"; case Instructions::STA_ABSY: return "STA"; - case Instructions::STA_DPX: return "STA"; + case Instructions::STA_DPX: return "STA " + this->_getDirectIndexedByXValue(pc); case Instructions::STA_DPXi: return "STA"; case Instructions::STA_DPYi: return "STA"; case Instructions::STA_DPYil:return "STA"; @@ -219,12 +228,12 @@ namespace ComSquare::Debugger case Instructions::STY_ABS: return "STY " + this->_getAbsoluteValue(pc); case Instructions::STY_DP: return "STY " + this->_getDirectValue(pc); - case Instructions::STY_DPX: return "STY"; + case Instructions::STY_DPX: return "STY " + this->_getDirectIndexedByXValue(pc); case Instructions::STZ_ABS: return "STZ " + this->_getAbsoluteValue(pc); case Instructions::STZ_DP: return "STZ " + this->_getDirectValue(pc); case Instructions::STZ_ABSX: return "STZ"; - case Instructions::STZ_DPX: return "STZ"; + case Instructions::STZ_DPX: return "STZ " + this->_getDirectIndexedByXValue(pc); case Instructions::LDA_IM: return "LDA " + this->_getImmediateValueForA(pc); case Instructions::LDA_ABS: return "LDA " + this->_getAbsoluteValue(pc); @@ -235,7 +244,7 @@ namespace ComSquare::Debugger case Instructions::LDA_ABSX: return "LDA"; case Instructions::LDA_ABSXl:return "LDA"; case Instructions::LDA_ABSY: return "LDA"; - case Instructions::LDA_DPX: return "LDA"; + case Instructions::LDA_DPX: return "LDA " + this->_getDirectIndexedByXValue(pc); case Instructions::LDA_DPXi: return "LDA"; case Instructions::LDA_DPYi: return "LDA"; case Instructions::LDA_DPYil:return "LDA"; @@ -296,7 +305,7 @@ namespace ComSquare::Debugger case Instructions::AND_ABSX: return "AND"; case Instructions::AND_ABSXl:return "AND"; case Instructions::AND_ABSY: return "AND"; - case Instructions::AND_DPX: return "AND"; + case Instructions::AND_DPX: return "AND " + this->_getDirectIndexedByXValue(pc); case Instructions::AND_DPXi: return "AND"; case Instructions::AND_DPYi: return "AND"; case Instructions::AND_DPYil:return "AND"; @@ -314,7 +323,7 @@ namespace ComSquare::Debugger case Instructions::SBC_ABSX: return "SBC"; case Instructions::SBC_ABSXl:return "SBC"; case Instructions::SBC_ABSY: return "SBC"; - case Instructions::SBC_DPX: return "SBC"; + case Instructions::SBC_DPX: return "SBC " + this->_getDirectIndexedByXValue(pc); case Instructions::SBC_DPXi: return "SBC"; case Instructions::SBC_DPYi: return "SBC"; case Instructions::SBC_DPYil:return "SBC"; @@ -325,6 +334,9 @@ namespace ComSquare::Debugger case Instructions::TAY: return "TAY"; case Instructions::TXS: return "TXS"; + case Instructions::INX: return "INX"; + case Instructions::INY: return "INY"; + default: return "Unknown"; } } diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp index 5928c94..6489a71 100644 --- a/sources/Debugger/CPUDebug.hpp +++ b/sources/Debugger/CPUDebug.hpp @@ -44,6 +44,8 @@ namespace ComSquare::Debugger 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 index by x addressing mode. + std::string _getDirectIndexedByXValue(uint24_t pc); public slots: //! @brief Pause/Resume the CPU. diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp index cd2c124..55e8b9b 100644 --- a/tests/CPU/testInternal.cpp +++ b/tests/CPU/testInternal.cpp @@ -8,6 +8,8 @@ #include "../tests.hpp" #include "../../sources/SNES.hpp" #include "../../sources/Memory/MemoryBus.hpp" +#include "../../sources/CPU/CPU.hpp" + using namespace ComSquare; Test(SEP, setall) @@ -484,4 +486,56 @@ Test(XCE, enableNative) cr_assert_eq(pair.second.cpu->_registers.p.x_b, true, "The index width flag should be set"); cr_assert_eq(pair.second.cpu->_registers.xh, 0, "The high byte of the x index flag should be set to 0"); cr_assert_eq(pair.second.cpu->_registers.yh, 0, "The high byte of the y index flag should be set to 0"); +} + +Test(INX, basic) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.p.x_b = false; + pair.second.cpu->_registers.x = 0xFF; + pair.second.cpu->INX(); + cr_assert_eq(pair.second.cpu->_registers.x, 0x0100, "The x register should be equal to 0x0100 but it was 0x%x.", pair.second.cpu->_registers.x); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should not be set"); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flag should not be set"); +} + +Test(INX, 8bits) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.p.x_b = true; + pair.second.cpu->_registers.x = 0xFF; + pair.second.cpu->INX(); + cr_assert_eq(pair.second.cpu->_registers.x, 0x00, "The x register should be equal to 0x00 but it was 0x%x.", pair.second.cpu->_registers.x); + cr_assert_eq(pair.second.cpu->_registers.p.z, true, "The zero flag should be set"); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flag should not be set"); +} + +Test(INY, basic) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.p.x_b = false; + pair.second.cpu->_registers.y = 0xFF; + pair.second.cpu->INY(); + cr_assert_eq(pair.second.cpu->_registers.y, 0x0100, "The y register should be equal to 0x0100 but it was 0x%x.", pair.second.cpu->_registers.y); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should not be set"); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flag should not be set"); +} + +Test(INY, 8bits) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.p.x_b = true; + pair.second.cpu->_registers.y = 0xFF; + pair.second.cpu->INY(); + cr_assert_eq(pair.second.cpu->_registers.y, 0x00, "The y register should be equal to 0x00 but it was 0x%x.", pair.second.cpu->_registers.y); + cr_assert_eq(pair.second.cpu->_registers.p.z, true, "The zero flag should be set"); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flag should not be set"); } \ No newline at end of file