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