From 83b8c83e6e044550f1d5198a4a8f0851d2a5e03f Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Mon, 6 Apr 2020 17:12:12 +0200
Subject: [PATCH] Implementing the CMP
---
CMakeLists.txt | 2 +-
sources/CPU/CPU.hpp | 34 +++++----
.../Instructions/MathematicalOperations.cpp | 37 ++++++++++
tests/CPU/Math/testCMP.cpp | 73 +++++++++++++++++++
4 files changed, 129 insertions(+), 17 deletions(-)
create mode 100644 tests/CPU/Math/testCMP.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5bdd37c..18c98a8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -97,7 +97,7 @@ add_executable(unit_tests
sources/Exceptions/DebuggableError.hpp
tests/CPU/Math/testOthersMath.cpp
tests/testRectangleMemory.cpp
-)
+ tests/CPU/Math/testCMP.cpp)
# include criterion & coverage
target_link_libraries(unit_tests criterion -lgcov)
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index e498095..a0598b6 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -389,6 +389,8 @@ namespace ComSquare::CPU
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 All the instructions of the CPU.
//! @info Instructions are indexed by their opcode
@@ -586,37 +588,37 @@ namespace ComSquare::CPU
{&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::CMP, 6, "cmp", AddressingMode::DirectPageIndirectIndexedByX, 2}, // C1
{&CPU::REP, 3, "rep", AddressingMode::Immediate8bits, 2}, // C2
- {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C3
+ {&CPU::CMP, 4, "cmp", AddressingMode::StackRelative, 2}, // C3
{&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C4
- {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C5
+ {&CPU::CMP, 3, "cmp", AddressingMode::DirectPage, 2}, // C5
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // C6
- {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C7
+ {&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::CMP, 2, "cmp", AddressingMode::Implied, 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::CMP, 4, "cmp", AddressingMode::Absolute, 3}, // CD
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // CE
- {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CF
+ {&CPU::CMP, 6, "cmp", AddressingMode::AbsoluteLong, 4}, // 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::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::CMP, 4, "cmp", AddressingMode::DirectPageIndexedByX, 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, 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::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByX, 3}, // DD
{&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // DE
- {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DF
+ {&CPU::CMP, 5, "cmp", AddressingMode::AbsoluteIndexedByXLong, 4}, // DF
{&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E0
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // E1
{&CPU::SEP, 3, "sep", AddressingMode::Immediate8bits, 2}, // E2
diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp
index 4872cbb..776a810 100644
--- a/sources/CPU/Instructions/MathematicalOperations.cpp
+++ b/sources/CPU/Instructions/MathematicalOperations.cpp
@@ -147,4 +147,41 @@ namespace ComSquare::CPU
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;
+ }
}
\ No newline at end of file
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.");
+}
+