From 68b82c9cdafb7fa5cb3ee413d2843e4b8b3064a8 Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Fri, 28 Feb 2020 17:23:27 +0100 Subject: [PATCH] Implementing CPX and CPY --- sources/CPU/CPU.cpp | 8 +++ sources/CPU/CPU.hpp | 14 +++- .../CPU/Instructions/InternalInstruction.cpp | 38 +++++++++++ sources/Debugger/CPUDebug.cpp | 8 +++ tests/CPU/testInternal.cpp | 66 +++++++++++++++++++ 5 files changed, 133 insertions(+), 1 deletion(-) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index dc39527..36ef7fb 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -351,6 +351,14 @@ namespace ComSquare::CPU case Instructions::INX: this->INX(); return 2; case Instructions::INY: this->INY(); return 2; + case Instructions::CPX_IM: this->CPX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; + case Instructions::CPX_ABS: this->CPX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; + case Instructions::CPX_DP: this->CPX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; + + case Instructions::CPY_IM: this->CPY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; + case Instructions::CPY_ABS: this->CPY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; + case Instructions::CPY_DP: this->CPY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; + default: throw InvalidOpcode("CPU", opcode); } diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 405d19b..ecbadff 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -333,7 +333,15 @@ namespace ComSquare::CPU TXS = 0x9A, INX = 0xE8, - INY = 0xC8 + INY = 0xC8, + + CPX_IM = 0xE0, + CPX_ABS = 0xEC, + CPX_DP = 0xE4, + + CPY_IM = 0xC0, + CPY_ABS = 0xCC, + CPY_DP = 0xC4 }; //! @brief The main CPU @@ -497,6 +505,10 @@ namespace ComSquare::CPU void INX(); //! @brief Increment the Y register void INY(); + //! @brief Compare the X register with the memory + void CPX(uint24_t valueAddr); + //! @brief Compare the Y register with the memory + void CPY(uint24_t valueAddr); 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 dcc4421..890ad93 100644 --- a/sources/CPU/Instructions/InternalInstruction.cpp +++ b/sources/CPU/Instructions/InternalInstruction.cpp @@ -188,4 +188,42 @@ namespace ComSquare::CPU this->_registers.p.z = this->_registers.y == 0; this->_registers.p.n = this->_registers.y & negativeFlag; } + + void CPU::CPX(uint24_t valueAddr) + { + 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; + } + + void CPU::CPY(uint24_t valueAddr) + { + 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; + } + } } \ No newline at end of file diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp index ac37181..e924a14 100644 --- a/sources/Debugger/CPUDebug.cpp +++ b/sources/Debugger/CPUDebug.cpp @@ -337,6 +337,14 @@ namespace ComSquare::Debugger case Instructions::INX: return "INX"; case Instructions::INY: return "INY"; + case Instructions::CPX_IM: return "CPX " + this->_getImmediateValueForX(pc); + case Instructions::CPX_ABS: return "CPX " + this->_getAbsoluteValue(pc); + case Instructions::CPX_DP: return "CPX"; + + case Instructions::CPY_IM: return "CPY " + this->_getImmediateValueForX(pc); + case Instructions::CPY_ABS: return "CPY " + this->_getAbsoluteValue(pc); + case Instructions::CPY_DP: return "CPY"; + default: return "Unknown"; } } diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp index 55e8b9b..061ba62 100644 --- a/tests/CPU/testInternal.cpp +++ b/tests/CPU/testInternal.cpp @@ -538,4 +538,70 @@ Test(INY, 8bits) 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"); +} + +Test(CPX, basic) +{ + auto pair = Init(); + pair.second.cpu->_registers.p.x_b = true; + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.x = 0xFF; + pair.second.wram->_data[0] = 0xFF; + pair.second.cpu->CPX(0x0); + 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"); + cr_assert_eq(pair.second.cpu->_registers.p.c, true, "The carry flag should be set"); +} + +Test(CPX, negative) +{ + auto pair = Init(); + pair.second.cpu->_registers.p.x_b = true; + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.x = 0x80; + pair.second.wram->_data[0] = 0xFF; + pair.second.cpu->CPX(0x0); + 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, true, "The negative flag should be set"); + cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flag should not be set"); +} + +Test(CPX, 16bits) +{ + auto pair = Init(); + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.p.x_b = false; + pair.second.cpu->_registers.x = 0x8888; + pair.second.wram->_data[0] = 0x88; + pair.second.wram->_data[1] = 0x98; + pair.second.cpu->CPX(0x0); + 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, true, "The negative flag should be set"); + cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flag should not be set"); +} + +Test(CPY, basic) +{ + auto pair = Init(); + pair.second.cpu->_registers.p.x_b = true; + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.y = 0xFF; + pair.second.wram->_data[0] = 0xFF; + pair.second.cpu->CPY(0x0); + 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"); + cr_assert_eq(pair.second.cpu->_registers.p.c, true, "The carry flag should be set"); +} + +Test(CPY, negative) +{ + auto pair = Init(); + pair.second.cpu->_registers.p.x_b = true; + pair.second.cpu->_registers.p.flags = 0; + pair.second.cpu->_registers.y = 0x80; + pair.second.wram->_data[0] = 0xFF; + pair.second.cpu->CPY(0x0); + 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, true, "The negative flag should be set"); + cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flag should not be set"); } \ No newline at end of file