From 38045afe15489d498b32114d13f5e81e7ce1ac82 Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Tue, 25 Feb 2020 22:09:37 +0100
Subject: [PATCH 01/16] Implementing the SET bits instructions
---
sources/CPU/CPU.cpp | 4 ++
sources/CPU/CPU.hpp | 10 ++++
.../CPU/Instructions/InternalInstruction.cpp | 55 ++++++++++++-------
sources/Debugger/CPUDebug.cpp | 4 ++
tests/CPU/testInternal.cpp | 24 ++++++++
5 files changed, 77 insertions(+), 20 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 96807c0..81eb58e 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -306,6 +306,10 @@ namespace ComSquare::CPU
case Instructions::CLD: this->CLD(); return 2;
case Instructions::CLV: this->CLV(); return 2;
+ case Instructions::SEC: this->SEC(); return 2;
+ case Instructions::SED: this->SED(); return 2;
+ case Instructions::SEI: this->SEI(); return 2;
+
case Instructions::AND_IM: this->AND(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
case Instructions::AND_ABS: this->AND(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::AND_ABSl: this->AND(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index d9def71..8015292 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -290,6 +290,10 @@ namespace ComSquare::CPU
CLD = 0xD8,
CLV = 0xB8,
+ SEC = 0x38,
+ SEI = 0x78,
+ SED = 0xF8,
+
AND_IM = 0x29,
AND_ABS = 0x2D,
AND_ABSl = 0x2F,
@@ -445,6 +449,12 @@ namespace ComSquare::CPU
void CLD();
//! @brief Clear the overflow flag.
void CLV();
+ //! @brief Set the carry Flag.
+ void SEC();
+ //! @brief Set the decimal flag.
+ void SED();
+ //! @brief Set the Interrupt Disable flag.
+ void SEI();
//! @brief And accumulator with memory.
void AND(uint24_t valueAddr);
public:
diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp
index e1e0555..c5891c3 100644
--- a/sources/CPU/Instructions/InternalInstruction.cpp
+++ b/sources/CPU/Instructions/InternalInstruction.cpp
@@ -6,6 +6,41 @@
namespace ComSquare::CPU
{
+ void CPU::SEC()
+ {
+ this->_registers.p.c = true;
+ }
+
+ void CPU::SED()
+ {
+ this->_registers.p.d = true;
+ }
+
+ void CPU::SEI()
+ {
+ this->_registers.p.i = true;
+ }
+
+ void CPU::CLC()
+ {
+ this->_registers.p.c = false;
+ }
+
+ void CPU::CLI()
+ {
+ this->_registers.p.i = false;
+ }
+
+ void CPU::CLD()
+ {
+ this->_registers.p.d = false;
+ }
+
+ void CPU::CLV()
+ {
+ this->_registers.p.v = false;
+ }
+
void CPU::SEP(uint24_t valueAddr)
{
this->_registers.p.flags |= this->_bus->read(valueAddr);
@@ -115,24 +150,4 @@ namespace ComSquare::CPU
this->_registers.p.z = this->_registers.y == 0;
this->_registers.p.n = this->_registers.y & 0x8000u;
}
-
- void CPU::CLC()
- {
- this->_registers.p.c = false;
- }
-
- void CPU::CLI()
- {
- this->_registers.p.i = false;
- }
-
- void CPU::CLD()
- {
- this->_registers.p.d = false;
- }
-
- void CPU::CLV()
- {
- this->_registers.p.v = false;
- }
}
\ No newline at end of file
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 9000853..1f2c8f3 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -218,6 +218,10 @@ namespace ComSquare::Debugger
case Instructions::CLD: return "CLD";
case Instructions::CLV: return "CLV";
+ case Instructions::SEC: return "SEC";
+ case Instructions::SED: return "SED";
+ case Instructions::SEI: return "SEI";
+
case Instructions::AND_IM: return "AND";
case Instructions::AND_ABS: return "AND";
case Instructions::AND_ABSl: return "AND";
diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp
index 6f01b28..c0b1538 100644
--- a/tests/CPU/testInternal.cpp
+++ b/tests/CPU/testInternal.cpp
@@ -437,4 +437,28 @@ Test(CLV, clear)
pair.second.cpu->_registers.p.flags = 0xFF;
pair.second.cpu->CLV();
cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flag should not be set");
+}
+
+Test(SEC, set)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.flags = 0x00;
+ pair.second.cpu->SEC();
+ cr_assert_eq(pair.second.cpu->_registers.p.c, true, "The carry flag should be set");
+}
+
+Test(SEI, set)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.flags = 0x00;
+ pair.second.cpu->SEI();
+ cr_assert_eq(pair.second.cpu->_registers.p.i, true, "The interrupt disabled flag should be set");
+}
+
+Test(SED, set)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.flags = 0x00;
+ pair.second.cpu->SED();
+ cr_assert_eq(pair.second.cpu->_registers.p.d, true, "The decimal flag should be set");
}
\ No newline at end of file
From 8dbaea89ed3786269b4b230d6cd5bd594d7a3c9b Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Tue, 25 Feb 2020 22:35:04 +0100
Subject: [PATCH 02/16] Fixing the cpu's debugger witch was miss interpreting
instructions
---
sources/Debugger/CPUDebug.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 1f2c8f3..0441109 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -43,8 +43,10 @@ namespace ComSquare::Debugger
unsigned CPUDebug::_executeInstruction(uint8_t opcode)
{
- if (this->_isPaused)
+ if (this->_isPaused) {
+ this->_registers.pac--;
return 0;
+ }
if (this->_isStepping) {
this->_isStepping = false;
this->_isPaused = true;
From 4da96894ae400d4c19286660f312b103f079bb6a Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Tue, 25 Feb 2020 23:05:15 +0100
Subject: [PATCH 03/16] Implementing the XCE instruction
---
sources/CPU/CPU.cpp | 2 ++
sources/CPU/CPU.hpp | 6 +++-
.../CPU/Instructions/InternalInstruction.cpp | 14 ++++++++
sources/Debugger/CPUDebug.cpp | 2 ++
tests/CPU/testInternal.cpp | 33 +++++++++++++++++++
5 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 81eb58e..718066a 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -326,6 +326,8 @@ namespace ComSquare::CPU
case Instructions::AND_SR: this->AND(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
case Instructions::AND_SRYi: this->AND(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
+ case Instructions::XCE: this->XCE(); return 2;
+
default:
throw InvalidOpcode("CPU", opcode);
}
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 8015292..ddd184a 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -308,7 +308,9 @@ namespace ComSquare::CPU
AND_DPYi = 0x31,
AND_DPYil = 0x37,
AND_SR = 0x23,
- AND_SRYi = 0x33
+ AND_SRYi = 0x33,
+
+ XCE = 0xFB
};
//! @brief The main CPU
@@ -455,6 +457,8 @@ namespace ComSquare::CPU
void SED();
//! @brief Set the Interrupt Disable flag.
void SEI();
+ //! @brief Exchange Carry and Emulation Flags
+ void XCE();
//! @brief And accumulator with memory.
void AND(uint24_t valueAddr);
public:
diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp
index c5891c3..b1ed4bc 100644
--- a/sources/CPU/Instructions/InternalInstruction.cpp
+++ b/sources/CPU/Instructions/InternalInstruction.cpp
@@ -150,4 +150,18 @@ namespace ComSquare::CPU
this->_registers.p.z = this->_registers.y == 0;
this->_registers.p.n = this->_registers.y & 0x8000u;
}
+
+ void CPU::XCE()
+ {
+ bool oldCarry = this->_registers.p.c;
+ this->_registers.p.c = this->_isEmulationMode;
+ this->_isEmulationMode = oldCarry;
+
+ if (!this->_isEmulationMode) {
+ this->_registers.p.m = true;
+ this->_registers.p.x_b = true;
+ this->_registers.xh = 0;
+ this->_registers.yh = 0;
+ }
+ }
}
\ No newline at end of file
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 0441109..9b4f02f 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -240,6 +240,8 @@ namespace ComSquare::Debugger
case Instructions::AND_SR: return "AND";
case Instructions::AND_SRYi: return "AND";
+ case Instructions::XCE: return "XCE";
+
default: return "Unknown";
}
}
diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp
index c0b1538..87bce8e 100644
--- a/tests/CPU/testInternal.cpp
+++ b/tests/CPU/testInternal.cpp
@@ -461,4 +461,37 @@ Test(SED, set)
pair.second.cpu->_registers.p.flags = 0x00;
pair.second.cpu->SED();
cr_assert_eq(pair.second.cpu->_registers.p.d, true, "The decimal flag should be set");
+}
+
+Test(XCE, enableEmulation)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.flags = 0;
+ pair.second.cpu->_registers.p.c = true;
+ pair.second.cpu->_registers.xh = 0xFF;
+ pair.second.cpu->_registers.yh = 0xFF;
+ pair.second.cpu->XCE();
+ cr_assert_eq(pair.second.cpu->_isEmulationMode, true, "The e flag should be set");
+ cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flag should not be set");
+ cr_assert_eq(pair.second.cpu->_registers.p.m, false, "The memory width flag should be untouched (unset)");
+ cr_assert_eq(pair.second.cpu->_registers.p.x_b, false, "The index width flag should be untouched (unset)");
+ cr_assert_eq(pair.second.cpu->_registers.xh, 0xFF, "The high byte of the x index flag should be untouched (0xFF)");
+ cr_assert_eq(pair.second.cpu->_registers.yh, 0xFF, "The high byte of the y index flag should be untouched (0xFF)");
+}
+
+Test(XCE, enableNative)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = true;
+ pair.second.cpu->_registers.p.flags = 0;
+ pair.second.cpu->_registers.xh = 0xFF;
+ pair.second.cpu->_registers.yh = 0xFF;
+ pair.second.cpu->XCE();
+ cr_assert_eq(pair.second.cpu->_isEmulationMode, false, "The e flag should be not set");
+ cr_assert_eq(pair.second.cpu->_registers.p.c, true, "The carry flag should be set");
+ cr_assert_eq(pair.second.cpu->_registers.p.m, true, "The memory width flag should be set");
+ 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");
}
\ No newline at end of file
From a421ef693fd3b2d299856ab5b59cab4bc238ce7a Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Tue, 25 Feb 2020 23:32:19 +0100
Subject: [PATCH 04/16] Starting the SBC instruction
---
sources/CPU/CPU.hpp | 3 ++-
sources/CPU/Instructions/MathematicalOperations.cpp | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index ddd184a..23d1f83 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -393,7 +393,6 @@ namespace ComSquare::CPU
//! @brief Return from Interrupt - Used to return from a interrupt handler.
void RTI();
//! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set.
- //! @return The number of extra cycles that this operation took.
void ADC(uint24_t valueAddr);
//! @brief Store the accumulator to memory.
void STA(uint24_t addr);
@@ -461,6 +460,8 @@ namespace ComSquare::CPU
void XCE();
//! @brief And accumulator with memory.
void AND(uint24_t valueAddr);
+ //! @brief Subtract with Borrow from Accumulator.
+ void SBC(uint24_t valueAddr);
public:
explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader);
CPU(const CPU &) = default;
diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp
index 83455f8..8300f69 100644
--- a/sources/CPU/Instructions/MathematicalOperations.cpp
+++ b/sources/CPU/Instructions/MathematicalOperations.cpp
@@ -26,4 +26,9 @@ namespace ComSquare::CPU
this->_registers.p.z = this->_registers.a == 0;
this->_registers.p.n = this->_registers.a & negativeMask;
}
+
+ void CPU::SBC(uint24_t valueAddr)
+ {
+
+ }
}
\ No newline at end of file
From 4394c7625e371196691e8ab217cf64ec90151a6d Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Thu, 27 Feb 2020 23:37:52 +0100
Subject: [PATCH 05/16] Implementing a SBC without decimal mode
---
CMakeLists.txt | 2 +-
sources/CPU/CPU.cpp | 16 ++++
sources/CPU/CPU.hpp | 18 +++-
.../Instructions/MathematicalOperations.cpp | 15 +++
sources/Debugger/CPUDebug.cpp | 16 ++++
tests/CPU/Math/testADC.cpp | 2 -
tests/CPU/Math/testSBC.cpp | 92 +++++++++++++++++++
7 files changed, 157 insertions(+), 4 deletions(-)
create mode 100644 tests/CPU/Math/testSBC.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6a0ca86..a24be7d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -77,7 +77,7 @@ add_executable(unit_tests
sources/APU/Instructions/Stack.cpp
sources/APU/Instructions/Subroutine.cpp
sources/APU/Instructions/ProgramFlow.cpp
-)
+ tests/CPU/Math/testSBC.cpp)
# include criterion & coverage
target_link_libraries(unit_tests criterion -lgcov)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 718066a..07f57b5 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -328,6 +328,22 @@ namespace ComSquare::CPU
case Instructions::XCE: this->XCE(); return 2;
+ case Instructions::SBC_IM: this->SBC(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
+ case Instructions::SBC_ABS: this->SBC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
+ case Instructions::SBC_ABSl: this->SBC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
+ case Instructions::SBC_DP: this->SBC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
+ case Instructions::SBC_DPi: this->SBC(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0;
+ case Instructions::SBC_DPil: this->SBC(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
+ case Instructions::SBC_ABSX: this->SBC(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
+ case Instructions::SBC_ABSXl:this->SBC(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m;
+ case Instructions::SBC_ABSY: this->SBC(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
+ case Instructions::SBC_DPX: this->SBC(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
+ case Instructions::SBC_DPXi: this->SBC(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
+ case Instructions::SBC_DPYi: this->SBC(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary;
+ case Instructions::SBC_DPYil:this->SBC(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0;
+ case Instructions::SBC_SR: this->SBC(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
+ case Instructions::SBC_SRYi: this->SBC(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
+
default:
throw InvalidOpcode("CPU", opcode);
}
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 23d1f83..710a05d 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -310,7 +310,23 @@ namespace ComSquare::CPU
AND_SR = 0x23,
AND_SRYi = 0x33,
- XCE = 0xFB
+ XCE = 0xFB,
+
+ SBC_IM = 0xE9,
+ SBC_ABS = 0xED,
+ SBC_ABSl = 0xEF,
+ SBC_DP = 0xE5,
+ SBC_DPi = 0xF2,
+ SBC_DPil = 0xE7,
+ SBC_ABSX = 0xFD,
+ SBC_ABSXl = 0xFF,
+ SBC_ABSY = 0xF9,
+ SBC_DPX = 0xF5,
+ SBC_DPXi = 0xE1,
+ SBC_DPYi = 0xF1,
+ SBC_DPYil = 0xF7,
+ SBC_SR = 0xE3,
+ SBC_SRYi = 0xF3,
};
//! @brief The main CPU
diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp
index 8300f69..f4ec41c 100644
--- a/sources/CPU/Instructions/MathematicalOperations.cpp
+++ b/sources/CPU/Instructions/MathematicalOperations.cpp
@@ -29,6 +29,21 @@ namespace ComSquare::CPU
void CPU::SBC(uint24_t valueAddr)
{
+ unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u;
+ unsigned value = this->_bus->read(valueAddr);
+ if (this->_registers.p.m)
+ value += this->_bus->read(valueAddr + 1) << 8u;
+ bool oldCarry = this->_registers.p.c;
+ this->_registers.p.c = this->_registers.a >= value;
+ if ((this->_registers.a & negativeMask) == (value & negativeMask))
+ this->_registers.p.v = (this->_registers.a & negativeMask) != ((this->_registers.a + value) & negativeMask);
+ else
+ this->_registers.p.v = false;
+ this->_registers.a += ~value + oldCarry;
+ if (this->_isEmulationMode)
+ this->_registers.a %= 0x100;
+ this->_registers.p.z = this->_registers.a == 0;
+ this->_registers.p.n = this->_registers.a & negativeMask;
}
}
\ No newline at end of file
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 9b4f02f..8b97400 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -242,6 +242,22 @@ namespace ComSquare::Debugger
case Instructions::XCE: return "XCE";
+ case Instructions::SBC_IM: return "SBC";
+ case Instructions::SBC_ABS: return "SBC";
+ case Instructions::SBC_ABSl: return "SBC";
+ case Instructions::SBC_DP: return "SBC";
+ case Instructions::SBC_DPi: return "SBC";
+ case Instructions::SBC_DPil: return "SBC";
+ 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_DPXi: return "SBC";
+ case Instructions::SBC_DPYi: return "SBC";
+ case Instructions::SBC_DPYil:return "SBC";
+ case Instructions::SBC_SR: return "SBC";
+ case Instructions::SBC_SRYi: return "SBC";
+
default: return "Unknown";
}
}
diff --git a/tests/CPU/Math/testADC.cpp b/tests/CPU/Math/testADC.cpp
index 4fcc3eb..8623d6d 100644
--- a/tests/CPU/Math/testADC.cpp
+++ b/tests/CPU/Math/testADC.cpp
@@ -3,11 +3,9 @@
//
#include
-#include
#include
#include "../../tests.hpp"
#include "../../../sources/SNES.hpp"
-#include "../../../sources/Memory/MemoryBus.hpp"
using namespace ComSquare;
Test(ADC, addingOne)
diff --git a/tests/CPU/Math/testSBC.cpp b/tests/CPU/Math/testSBC.cpp
new file mode 100644
index 0000000..e9360b0
--- /dev/null
+++ b/tests/CPU/Math/testSBC.cpp
@@ -0,0 +1,92 @@
+//
+// Created by anonymus-raccoon on 27/02/20.
+//
+
+#include
+#include
+#include "../../tests.hpp"
+#include "../../../sources/SNES.hpp"
+using namespace ComSquare;
+
+Test(SBC, removingOne)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.c = true;
+ pair.second.cpu->_registers.a = 0x1;
+ pair.second.wram->_data[0] = 0x1;
+ pair.second.cpu->SBC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", pair.second.cpu->_registers.a);
+ cr_assert_eq(pair.second.cpu->_registers.p.c, true, "The carry flags should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, true, "The zero flags should be set.");
+}
+
+Test(SBC, legitOverflowWithCarry)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.a = 0x1;
+ pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.p.c = true;
+ pair.second.wram->_data[0] = 0x03;
+ pair.second.wram->_data[1] = 0x20;
+ pair.second.cpu->SBC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.a, 0xDFFE, "The accumulator's value should be 0xDFFE but it was 0x%x.", pair.second.cpu->_registers.a);
+ cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flags should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set.");
+}
+
+Test(SBC, overflowWithCarry)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.a = 0x1;
+ pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.p.c = true;
+ pair.second.wram->_data[0] = 0x03;
+ pair.second.wram->_data[1] = 0x20;
+ pair.second.cpu->SBC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.a, 0xDFFE, "The accumulator's value should be 0xDFFE but it was 0x%x.", pair.second.cpu->_registers.a);
+ cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should be not set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flags should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set.");
+}
+
+Test(SBC, overflowEmulation)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = true;
+ pair.second.cpu->_registers.a = 0x1;
+ pair.second.cpu->_registers.p.m = false;
+ pair.second.cpu->_registers.p.c = false;
+ pair.second.wram->_data[0] = 0x02;
+ pair.second.cpu->SBC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.a, 0xFE, "The accumulator's value should be 0xFE but it was 0x%x.", pair.second.cpu->_registers.a);
+ cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flags should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should be not set.");
+}
+
+
+Test(SBC, decimal)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = true;
+ pair.second.cpu->_registers.a = 0x1;
+ pair.second.cpu->_registers.p.d = true;
+ pair.second.cpu->_registers.p.m = true;
+ pair.second.wram->_data[0] = 0x03;
+ pair.second.wram->_data[1] = 0x20;
+ pair.second.cpu->SBC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.a, 0x7998, "The accumulator's value should be 0x7998 but it was 0x%x.", pair.second.cpu->_registers.a);
+ cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should be not set.");
+}
From 6c3c832539f4c08599f542d41fff60b39b941086 Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Fri, 28 Feb 2020 00:37:17 +0100
Subject: [PATCH 06/16] Solving mistakes about the m flag
---
sources/CPU/CPU.cpp | 2 +-
sources/CPU/CPU.hpp | 4 +-
sources/CPU/Instructions/BitsInstructions.cpp | 2 +-
.../Instructions/MathematicalOperations.cpp | 4 +-
sources/Debugger/CPUDebug.cpp | 92 ++++++++++++-------
sources/Debugger/CPUDebug.hpp | 12 ++-
sources/Utility/Utility.cpp | 2 -
tests/CPU/Math/testADC.cpp | 2 +-
tests/CPU/Math/testSBC.cpp | 6 +-
tests/CPU/testAddressingMode.cpp | 6 +-
tests/CPU/testBits.cpp | 2 +-
11 files changed, 84 insertions(+), 50 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 07f57b5..2a5fc7a 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -377,7 +377,7 @@ namespace ComSquare::CPU
uint24_t CPU::_getImmediateAddr()
{
uint24_t effective = this->_registers.pac++;
- if (this->_registers.p.m)
+ if (!this->_registers.p.m)
this->_registers.pac++;
return effective;
}
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 710a05d..cb6f1bf 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -84,9 +84,9 @@ namespace ComSquare::CPU
bool i : 1;
//! @brief The Decimal mode flag
bool d : 1;
- //! @brief The indeX register _width flag (in native mode only) OR the Break flag (in emulation mode only)
+ //! @brief The indeX register width flag (in native mode only) OR the Break flag (in emulation mode only)
bool x_b : 1;
- //! @brief The accumulator and Memory _width flag (in native mode only)
+ //! @brief The accumulator and Memory width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode.
bool m : 1;
//! @brief The oVerflow flag
bool v : 1;
diff --git a/sources/CPU/Instructions/BitsInstructions.cpp b/sources/CPU/Instructions/BitsInstructions.cpp
index 3496f8f..46b2b6a 100644
--- a/sources/CPU/Instructions/BitsInstructions.cpp
+++ b/sources/CPU/Instructions/BitsInstructions.cpp
@@ -11,7 +11,7 @@ namespace ComSquare::CPU
{
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u;
unsigned value = this->_bus->read(valueAddr);
- if (this->_registers.p.m)
+ if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u;
this->_registers.a &= value;
diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp
index f4ec41c..75835ea 100644
--- a/sources/CPU/Instructions/MathematicalOperations.cpp
+++ b/sources/CPU/Instructions/MathematicalOperations.cpp
@@ -10,7 +10,7 @@ namespace ComSquare::CPU
void CPU::ADC(uint24_t valueAddr)
{
unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c;
- if (this->_registers.p.m)
+ if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u;
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u;
unsigned maxValue = this->_isEmulationMode ? UINT8_MAX : UINT16_MAX;
@@ -31,7 +31,7 @@ namespace ComSquare::CPU
{
unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u;
unsigned value = this->_bus->read(valueAddr);
- if (this->_registers.p.m)
+ if (!this->_registers.p.m)
value += this->_bus->read(valueAddr + 1) << 8u;
bool oldCarry = this->_registers.p.c;
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 8b97400..988201b 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -51,9 +51,10 @@ namespace ComSquare::Debugger
this->_isStepping = false;
this->_isPaused = true;
}
- this->_ui.logger->append(CPUDebug::_getInstructionString(opcode).c_str());
+ this->_ui.logger->append((CPUDebug::_getInstructionString(this->_registers.pac - 1) + " - " + Utility::to_hex(opcode)).c_str());
+ unsigned ret = CPU::_executeInstruction(opcode);
this->_updateRegistersPanel();
- return CPU::_executeInstruction(opcode);
+ return ret;
}
void CPUDebug::pause()
@@ -110,8 +111,35 @@ namespace ComSquare::Debugger
return str;
}
- std::string CPUDebug::_getInstructionString(uint8_t opcode)
+ std::string CPUDebug::_getImmediateValue(uint24_t pc)
{
+ unsigned value = this->_bus->read(pc);
+
+ if (!this->_registers.p.m)
+ value += this->_bus->read(pc + 1) << 8u;
+ std::stringstream ss;
+ ss << "#$" << std::hex << value;
+ return ss.str();
+ }
+
+ std::string CPUDebug::_getDirectValue(uint24_t pc)
+ {
+ std::stringstream ss;
+ ss << "$" << std::hex << static_cast(this->_bus->read(pc));
+ return ss.str();
+ }
+
+ std::string CPUDebug::_getAbsoluteValue(uint24_t pc)
+ {
+ std::stringstream ss;
+ ss << "$" << std::hex << (this->_bus->read(pc) + (this->_bus->read(pc + 1) << 8u));
+ return ss.str();
+ }
+
+ std::string CPUDebug::_getInstructionString(uint24_t pc)
+ {
+ uint8_t opcode = this->_bus->read(pc++);
+
switch (opcode) {
case Instructions::BRK: return "BRK";
@@ -119,10 +147,10 @@ namespace ComSquare::Debugger
case Instructions::RTI: return "RTI";
- case Instructions::ADC_IM: return "ADC";
- case Instructions::ADC_ABS: return "ADC";
+ case Instructions::ADC_IM: return "ADC " + this->_getImmediateValue(pc);
+ case Instructions::ADC_ABS: return "ADC " + this->_getAbsoluteValue(pc);
case Instructions::ADC_ABSl: return "ADC";
- case Instructions::ADC_DP: return "ADC";
+ case Instructions::ADC_DP: return "ADC " + this->_getDirectValue(pc);
case Instructions::ADC_DPi: return "ADC";
case Instructions::ADC_DPil: return "ADC";
case Instructions::ADC_ABSX: return "ADC";
@@ -135,9 +163,9 @@ namespace ComSquare::Debugger
case Instructions::ADC_SR: return "ADC";
case Instructions::ADC_SRYi: return "ADC";
- case Instructions::STA_ABS: return "STA";
+ case Instructions::STA_ABS: return "STA " + this->_getAbsoluteValue(pc);
case Instructions::STA_ABSl: return "STA";
- case Instructions::STA_DP: return "STA";
+ case Instructions::STA_DP: return "STA " + this->_getDirectValue(pc);
case Instructions::STA_DPi: return "STA";
case Instructions::STA_DPil: return "STA";
case Instructions::STA_ABSX: return "STA";
@@ -150,23 +178,23 @@ namespace ComSquare::Debugger
case Instructions::STA_SR: return "STA";
case Instructions::STA_SRYi: return "STA";
- case Instructions::STX_ABS: return "STX";
- case Instructions::STX_DP: return "STX";
+ case Instructions::STX_ABS: return "STX " + this->_getAbsoluteValue(pc);
+ case Instructions::STX_DP: return "STX " + this->_getDirectValue(pc);
case Instructions::STX_DPY: return "STX";
- case Instructions::STY_ABS: return "STX";
- case Instructions::STY_DP: return "STX";
+ case Instructions::STY_ABS: return "STX " + this->_getAbsoluteValue(pc);
+ case Instructions::STY_DP: return "STX " + this->_getDirectValue(pc);
case Instructions::STY_DPX: return "STX";
- case Instructions::STZ_ABS: return "STX";
- case Instructions::STZ_DP: return "STX";
+ case Instructions::STZ_ABS: return "STX " + this->_getAbsoluteValue(pc);
+ case Instructions::STZ_DP: return "STX " + this->_getDirectValue(pc);
case Instructions::STZ_ABSX: return "STX";
case Instructions::STZ_DPX: return "STX";
- case Instructions::LDA_IM: return "LDA";
- case Instructions::LDA_ABS: return "LDA";
+ case Instructions::LDA_IM: return "LDA " + this->_getImmediateValue(pc);
+ case Instructions::LDA_ABS: return "LDA " + this->_getAbsoluteValue(pc);
case Instructions::LDA_ABSl: return "LDA";
- case Instructions::LDA_DP: return "LDA";
+ case Instructions::LDA_DP: return "LDA " + this->_getDirectValue(pc);
case Instructions::LDA_DPi: return "LDA";
case Instructions::LDA_DPil: return "LDA";
case Instructions::LDA_ABSX: return "LDA";
@@ -179,21 +207,21 @@ namespace ComSquare::Debugger
case Instructions::LDA_SR: return "LDA";
case Instructions::LDA_SRYi: return "LDA";
- case Instructions::LDX_IM: return "LDX";
- case Instructions::LDX_ABS: return "LDX";
- case Instructions::LDX_DP: return "LDX";
+ case Instructions::LDX_IM: return "LDX " + this->_getImmediateValue(pc);
+ case Instructions::LDX_ABS: return "LDX " + this->_getAbsoluteValue(pc);
+ case Instructions::LDX_DP: return "LDX " + this->_getDirectValue(pc);
case Instructions::LDX_ABSY: return "LDX";
case Instructions::LDX_DPY: return "LDX";
- case Instructions::LDY_IM: return "LDY";
- case Instructions::LDY_ABS: return "LDY";
- case Instructions::LDY_DP: return "LDY";
+ case Instructions::LDY_IM: return "LDY " + this->_getImmediateValue(pc);
+ case Instructions::LDY_ABS: return "LDY " + this->_getAbsoluteValue(pc);
+ case Instructions::LDY_DP: return "LDY " + this->_getDirectValue(pc);
case Instructions::LDY_ABSY: return "LDY";
case Instructions::LDY_DPY: return "LDY";
- case Instructions::SEP: return "SEP";
+ case Instructions::SEP: return "SEP " + this->_getImmediateValue(pc);
- case Instructions::REP: return "REP";
+ case Instructions::REP: return "REP " + this->_getImmediateValue(pc);
case Instructions::PHA: return "PHA";
case Instructions::PHB: return "PHB";
@@ -210,7 +238,7 @@ namespace ComSquare::Debugger
case Instructions::PLX: return "PLX";
case Instructions::PLY: return "PLY";
- case Instructions::JSR_ABS: return "JSR";
+ case Instructions::JSR_ABS: return "JSR " + this->_getAbsoluteValue(pc);
case Instructions::JSR_ABSXi: return "JSR";
case Instructions::JSL: return "JSR";
@@ -224,10 +252,10 @@ namespace ComSquare::Debugger
case Instructions::SED: return "SED";
case Instructions::SEI: return "SEI";
- case Instructions::AND_IM: return "AND";
- case Instructions::AND_ABS: return "AND";
+ case Instructions::AND_IM: return "AND " + this->_getImmediateValue(pc);
+ case Instructions::AND_ABS: return "AND " + this->_getAbsoluteValue(pc);
case Instructions::AND_ABSl: return "AND";
- case Instructions::AND_DP: return "AND";
+ case Instructions::AND_DP: return "AND " + this->_getDirectValue(pc);
case Instructions::AND_DPi: return "AND";
case Instructions::AND_DPil: return "AND";
case Instructions::AND_ABSX: return "AND";
@@ -242,10 +270,10 @@ namespace ComSquare::Debugger
case Instructions::XCE: return "XCE";
- case Instructions::SBC_IM: return "SBC";
- case Instructions::SBC_ABS: return "SBC";
+ case Instructions::SBC_IM: return "SBC " + this->_getImmediateValue(pc);
+ case Instructions::SBC_ABS: return "SBC " + this->_getAbsoluteValue(pc);
case Instructions::SBC_ABSl: return "SBC";
- case Instructions::SBC_DP: return "SBC";
+ case Instructions::SBC_DP: return "SBC " + this->_getDirectValue(pc);
case Instructions::SBC_DPi: return "SBC";
case Instructions::SBC_DPil: return "SBC";
case Instructions::SBC_ABSX: return "SBC";
diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp
index e118495..92a7d83 100644
--- a/sources/Debugger/CPUDebug.hpp
+++ b/sources/Debugger/CPUDebug.hpp
@@ -25,12 +25,20 @@ namespace ComSquare::Debugger
SNES &_snes;
//! @brief Reimplement the basic instruction execution method to log instructions inside the logger view.
unsigned _executeInstruction(uint8_t opcode) override;
- //! @brief Get a printable string representing an instruction.
- static std::string _getInstructionString(uint8_t opcode);
+ //! @brief Get a printable string representing an instruction at the program counter given as parameter.
+ std::string _getInstructionString(uint24_t pc);
//! @brief Get a printable string representing the flags.
std::string _getFlagsString();
//! @brief Update the register's panel (accumulator, stack pointer...)
void _updateRegistersPanel();
+
+ //! @brief Return a printable string corresponding to the value of an immediate addressing mode.
+ std::string _getImmediateValue(uint24_t pc);
+ //! @brief Return a printable string corresponding to the value of a direct addressing mode.
+ std::string _getDirectValue(uint24_t pc);
+ //! @brief Return a printable string corresponding to the value of an absolute addressing mode.
+ std::string _getAbsoluteValue(uint24_t pc);
+
public slots:
//! @brief Pause/Resume the CPU.
void pause();
diff --git a/sources/Utility/Utility.cpp b/sources/Utility/Utility.cpp
index a56c99d..c66efbc 100644
--- a/sources/Utility/Utility.cpp
+++ b/sources/Utility/Utility.cpp
@@ -36,12 +36,10 @@ namespace ComSquare::Utility
std::string to_binary(uint16_t i)
{
return std::bitset<16>(i).to_string();
-
}
std::string to_binary(uint24_t i)
{
return std::bitset<24>(i).to_string();
-
}
}
\ No newline at end of file
diff --git a/tests/CPU/Math/testADC.cpp b/tests/CPU/Math/testADC.cpp
index 8623d6d..137493b 100644
--- a/tests/CPU/Math/testADC.cpp
+++ b/tests/CPU/Math/testADC.cpp
@@ -110,7 +110,7 @@ Test(ADC, memoryTwoBytes)
{
auto pair = Init();
pair.second.cpu->_isEmulationMode = false;
- pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.p.m = false;
pair.second.cpu->_registers.a = 0x000F;
pair.second.wram->_data[0] = 0x01;
pair.second.wram->_data[1] = 0x04;
diff --git a/tests/CPU/Math/testSBC.cpp b/tests/CPU/Math/testSBC.cpp
index e9360b0..3a76623 100644
--- a/tests/CPU/Math/testSBC.cpp
+++ b/tests/CPU/Math/testSBC.cpp
@@ -28,7 +28,7 @@ Test(SBC, legitOverflowWithCarry)
auto pair = Init();
pair.second.cpu->_isEmulationMode = false;
pair.second.cpu->_registers.a = 0x1;
- pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.p.m = false;
pair.second.cpu->_registers.p.c = true;
pair.second.wram->_data[0] = 0x03;
pair.second.wram->_data[1] = 0x20;
@@ -45,7 +45,7 @@ Test(SBC, overflowWithCarry)
auto pair = Init();
pair.second.cpu->_isEmulationMode = false;
pair.second.cpu->_registers.a = 0x1;
- pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.p.m = false;
pair.second.cpu->_registers.p.c = true;
pair.second.wram->_data[0] = 0x03;
pair.second.wram->_data[1] = 0x20;
@@ -80,7 +80,7 @@ Test(SBC, decimal)
pair.second.cpu->_isEmulationMode = true;
pair.second.cpu->_registers.a = 0x1;
pair.second.cpu->_registers.p.d = true;
- pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.p.m = false;
pair.second.wram->_data[0] = 0x03;
pair.second.wram->_data[1] = 0x20;
pair.second.cpu->SBC(0x0);
diff --git a/tests/CPU/testAddressingMode.cpp b/tests/CPU/testAddressingMode.cpp
index 3492fa2..9fa9ecb 100644
--- a/tests/CPU/testAddressingMode.cpp
+++ b/tests/CPU/testAddressingMode.cpp
@@ -23,7 +23,7 @@ Test(AddrMode, Immediate)
pair.second.cpu->_isEmulationMode = true;
pair.second.cpu->_registers.p.m = false;
cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x000015, "Got %x, Expected 0x000015");
- cr_assert_eq(pair.second.cpu->_registers.pac, 0x000016);
+ cr_assert_eq(pair.second.cpu->_registers.pac, 0x000017);
}
Test(AddrMode, ImmediateMemoryFlag)
@@ -31,7 +31,7 @@ Test(AddrMode, ImmediateMemoryFlag)
auto pair = Init();
pair.second.cpu->_isEmulationMode = true;
pair.second.cpu->_registers.pac = 0x000015;
- pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.p.m = false;
cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x000015, "Got %x, Expected 0x000015");
cr_assert_eq(pair.second.cpu->_registers.pac, 0x000017);
}
@@ -40,7 +40,7 @@ Test(AddrMode, ImmediateBankChange)
{
auto pair = Init();
pair.second.cpu->_registers.pac = 0x00FFFF;
- pair.second.cpu->_registers.p.m = false;
+ pair.second.cpu->_registers.p.m = true;
cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x00FFFF);
cr_assert_eq(pair.second.cpu->_registers.pac, 0x010000);
}
diff --git a/tests/CPU/testBits.cpp b/tests/CPU/testBits.cpp
index fc1d0c5..2902dfd 100644
--- a/tests/CPU/testBits.cpp
+++ b/tests/CPU/testBits.cpp
@@ -26,7 +26,7 @@ Test(AND, nativeNegative)
auto pair = Init();
pair.second.wram->_data[0] = 0xF0;
pair.second.wram->_data[1] = 0xF0;
- pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.p.m = false;
pair.second.cpu->_registers.a = 0xFF00;
pair.second.cpu->_isEmulationMode = false;
pair.second.cpu->AND(0x0);
From 825666dc5d74fe0ff231bb58ebbca3a2e3d97afe Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Fri, 28 Feb 2020 00:40:37 +0100
Subject: [PATCH 07/16] Adding informations for the x flag
---
sources/CPU/CPU.hpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index cb6f1bf..9280dcd 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -84,7 +84,7 @@ namespace ComSquare::CPU
bool i : 1;
//! @brief The Decimal mode flag
bool d : 1;
- //! @brief The indeX register width flag (in native mode only) OR the Break flag (in emulation mode only)
+ //! @brief The indeX register width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode OR the Break flag (in emulation mode only)
bool x_b : 1;
//! @brief The accumulator and Memory width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode.
bool m : 1;
From f2e59a32259a10b2d56ff529c4bf1ec71429ebbe Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 28 Feb 2020 11:04:55 +0100
Subject: [PATCH 08/16] Fixing CI
---
.github/workflows/build.yml | 4 +++-
sources/Renderer/QtRenderer/QtWidgetSFML.cpp | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2b7548f..494bef1 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,9 +11,11 @@ jobs:
steps:
- uses: actions/checkout@v1
- - name: Install Qt5 and the dependencies of the SFML.
+ - name: Install the dependencies of the SFML.
run: sudo apt-get update &&
sudo apt-get install --yes qt5-default libfreetype6-dev libxrandr-dev libudev-dev libogg-dev libflac-dev libvorbis-dev libopenal-dev freeglut3-dev
+ - name: Install Qt
+ uses: ouuan/install-qt-action@v2.3.1
- name: Install the SFML.
run: |
git clone https://github.com/SFML/SFML -b 2.5.x /tmp/sfml
diff --git a/sources/Renderer/QtRenderer/QtWidgetSFML.cpp b/sources/Renderer/QtRenderer/QtWidgetSFML.cpp
index e65076a..8cdfe10 100644
--- a/sources/Renderer/QtRenderer/QtWidgetSFML.cpp
+++ b/sources/Renderer/QtRenderer/QtWidgetSFML.cpp
@@ -29,7 +29,7 @@ namespace ComSquare::Renderer
#ifdef Q_WS_X11
XFlush(QX11Info::display());
#endif
- this->_window.create(this->winId());
+ this->_window.create((sf::WindowHandle)this->winId());
this->_onInit();
connect(&_timer, SIGNAL(timeout()), this, SLOT(repaint()));
From 3e2231482d7d0d1d5705a8769ad661f8e49d5ef4 Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 28 Feb 2020 11:30:08 +0100
Subject: [PATCH 09/16] Adding a clear button to the history
---
sources/Debugger/CPUDebug.cpp | 10 ++++++++--
sources/Debugger/CPUDebug.hpp | 2 ++
tests/CPU/Math/testSBC.cpp | 32 +++++++++++++++---------------
ui/cpu.ui | 37 +++++++++++++++++++++--------------
4 files changed, 48 insertions(+), 33 deletions(-)
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 988201b..53f2db7 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -19,6 +19,7 @@ namespace ComSquare::Debugger
this->_ui.setupUi(this);
QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause);
QMainWindow::connect(this->_ui.actionStep, &QAction::triggered, this, &CPUDebug::step);
+ QMainWindow::connect(this->_ui.clear, &QPushButton::released, this, &CPUDebug::clearHistory);
this->show();
this->_updateRegistersPanel();
}
@@ -35,8 +36,8 @@ namespace ComSquare::Debugger
return 0xFF;
return CPU::update();
} catch (InvalidOpcode &e) {
- this->pause();
- this->_ui.logger->append(e.what());
+ if (!this->_isPaused)
+ this->pause();
return 0xFF;
}
}
@@ -111,6 +112,11 @@ namespace ComSquare::Debugger
return str;
}
+ void CPUDebug::clearHistory()
+ {
+ this->_ui.logger->clear();
+ }
+
std::string CPUDebug::_getImmediateValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc);
diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp
index 92a7d83..88d9c95 100644
--- a/sources/Debugger/CPUDebug.hpp
+++ b/sources/Debugger/CPUDebug.hpp
@@ -44,6 +44,8 @@ namespace ComSquare::Debugger
void pause();
//! @brief Step - Execute a single instruction.
void step();
+ //! @brief Clear the history panel.
+ void clearHistory();
public:
//! @brief Update the UI when reseting the CPU.
void RESB() override;
diff --git a/tests/CPU/Math/testSBC.cpp b/tests/CPU/Math/testSBC.cpp
index 3a76623..4543749 100644
--- a/tests/CPU/Math/testSBC.cpp
+++ b/tests/CPU/Math/testSBC.cpp
@@ -74,19 +74,19 @@ Test(SBC, overflowEmulation)
}
-Test(SBC, decimal)
-{
- auto pair = Init();
- pair.second.cpu->_isEmulationMode = true;
- pair.second.cpu->_registers.a = 0x1;
- pair.second.cpu->_registers.p.d = true;
- pair.second.cpu->_registers.p.m = false;
- pair.second.wram->_data[0] = 0x03;
- pair.second.wram->_data[1] = 0x20;
- pair.second.cpu->SBC(0x0);
- cr_assert_eq(pair.second.cpu->_registers.a, 0x7998, "The accumulator's value should be 0x7998 but it was 0x%x.", pair.second.cpu->_registers.a);
- cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set.");
- cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set.");
- cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set.");
- cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should be not set.");
-}
+//Test(SBC, decimal)
+//{
+// auto pair = Init();
+// pair.second.cpu->_isEmulationMode = true;
+// pair.second.cpu->_registers.a = 0x1;
+// pair.second.cpu->_registers.p.d = true;
+// pair.second.cpu->_registers.p.m = false;
+// pair.second.wram->_data[0] = 0x03;
+// pair.second.wram->_data[1] = 0x20;
+// pair.second.cpu->SBC(0x0);
+// cr_assert_eq(pair.second.cpu->_registers.a, 0x7998, "The accumulator's value should be 0x7998 but it was 0x%x.", pair.second.cpu->_registers.a);
+// cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set.");
+// cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set.");
+// cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set.");
+// cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should be not set.");
+//}
diff --git a/ui/cpu.ui b/ui/cpu.ui
index 2e0e1bd..09dd3ed 100644
--- a/ui/cpu.ui
+++ b/ui/cpu.ui
@@ -7,7 +7,7 @@
0
0
420
- 405
+ 438
@@ -22,7 +22,27 @@
- -
+
-
+
+
+ Instructions History
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ -
+
+
+ Clear History
+
+
+
+ -
-
@@ -134,19 +154,6 @@
- -
-
-
- Instructions History
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
From ddaee431891ab4dc33ff579344e1adec510924b4 Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 28 Feb 2020 13:46:31 +0100
Subject: [PATCH 10/16] Implementing some transfer registers instructions
---
CMakeLists.txt | 4 +-
sources/CPU/CPU.cpp | 4 +
sources/CPU/CPU.hpp | 10 ++
.../CPU/Instructions/TransferRegisters.cpp | 48 ++++++
sources/Debugger/CPUDebug.cpp | 4 +
tests/CPU/TransferRegisters.cpp | 147 ++++++++++++++++++
6 files changed, 215 insertions(+), 2 deletions(-)
create mode 100644 sources/CPU/Instructions/TransferRegisters.cpp
create mode 100644 tests/CPU/TransferRegisters.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a24be7d..e12549a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -77,7 +77,7 @@ add_executable(unit_tests
sources/APU/Instructions/Stack.cpp
sources/APU/Instructions/Subroutine.cpp
sources/APU/Instructions/ProgramFlow.cpp
- tests/CPU/Math/testSBC.cpp)
+ tests/CPU/Math/testSBC.cpp sources/CPU/Instructions/TransferRegisters.cpp tests/CPU/TransferRegisters.cpp)
# include criterion & coverage
target_link_libraries(unit_tests criterion -lgcov)
@@ -166,7 +166,7 @@ add_executable(ComSquare
sources/APU/Instructions/Stack.cpp
sources/APU/Instructions/Subroutine.cpp
sources/APU/Instructions/ProgramFlow.cpp
-)
+ sources/CPU/Instructions/TransferRegisters.cpp)
target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 2a5fc7a..beb5fec 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -344,6 +344,10 @@ namespace ComSquare::CPU
case Instructions::SBC_SR: this->SBC(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
case Instructions::SBC_SRYi: this->SBC(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
+ case Instructions::TAX: this->TAX(); return 2;
+ case Instructions::TAY: this->TAY(); return 2;
+ case Instructions::TXS: this->TXS(); return 2;
+
default:
throw InvalidOpcode("CPU", opcode);
}
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 9280dcd..cec7a62 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -327,6 +327,10 @@ namespace ComSquare::CPU
SBC_DPYil = 0xF7,
SBC_SR = 0xE3,
SBC_SRYi = 0xF3,
+
+ TAX = 0xAA,
+ TAY = 0xA8,
+ TXS = 0x9A
};
//! @brief The main CPU
@@ -478,6 +482,12 @@ namespace ComSquare::CPU
void AND(uint24_t valueAddr);
//! @brief Subtract with Borrow from Accumulator.
void SBC(uint24_t valueAddr);
+ //! @brief Transfer A to X
+ void TAX();
+ //! @brief Transfer A to Y
+ void TAY();
+ //! @brief Transfer X to SP
+ void TXS();
public:
explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader);
CPU(const CPU &) = default;
diff --git a/sources/CPU/Instructions/TransferRegisters.cpp b/sources/CPU/Instructions/TransferRegisters.cpp
new file mode 100644
index 0000000..4b95092
--- /dev/null
+++ b/sources/CPU/Instructions/TransferRegisters.cpp
@@ -0,0 +1,48 @@
+//
+// Created by anonymus-raccoon on 2/28/20.
+//
+
+#include "../CPU.hpp"
+
+namespace ComSquare::CPU
+{
+ void CPU::TAX()
+ {
+ if (this->_registers.p.x_b) {
+ this->_registers.xl = this->_registers.al;
+ this->_registers.p.z = this->_registers.xl == 0;
+ this->_registers.p.n = this->_registers.x & 0x80u;
+ } else {
+ this->_registers.x = this->_registers.a;
+ this->_registers.p.z = this->_registers.x == 0;
+ this->_registers.p.n = this->_registers.x & 0x8000u;
+ }
+ }
+
+ void CPU::TAY()
+ {
+ if (this->_registers.p.x_b) {
+ this->_registers.yl = this->_registers.al;
+ this->_registers.p.z = this->_registers.yl == 0;
+ this->_registers.p.n = this->_registers.y & 0x80u;
+ } else {
+ this->_registers.y = this->_registers.a;
+ this->_registers.p.z = this->_registers.y == 0;
+ this->_registers.p.n = this->_registers.y & 0x8000u;
+ }
+ }
+
+ void CPU::TXS()
+ {
+ if (this->_registers.p.x_b) {
+ this->_registers.sh = 0;
+ this->_registers.sl = this->_registers.xl;
+ this->_registers.p.z = this->_registers.sl == 0;
+ this->_registers.p.n = this->_registers.s & 0x80u;
+ } else {
+ this->_registers.s = this->_registers.x;
+ this->_registers.p.z = this->_registers.s == 0;
+ this->_registers.p.n = this->_registers.s & 0x8000u;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 53f2db7..cc88cae 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -292,6 +292,10 @@ namespace ComSquare::Debugger
case Instructions::SBC_SR: return "SBC";
case Instructions::SBC_SRYi: return "SBC";
+ case Instructions::TAX: return "TAX";
+ case Instructions::TAY: return "TAY";
+ case Instructions::TXS: return "TXS";
+
default: return "Unknown";
}
}
diff --git a/tests/CPU/TransferRegisters.cpp b/tests/CPU/TransferRegisters.cpp
new file mode 100644
index 0000000..9dd6069
--- /dev/null
+++ b/tests/CPU/TransferRegisters.cpp
@@ -0,0 +1,147 @@
+//
+// Created by anonymus-raccoon on 2/28/20.
+//
+
+#include
+#include
+#include
+#include "../tests.hpp"
+#include "../../sources/SNES.hpp"
+using namespace ComSquare;
+
+Test(TAX, 16bitsTo16Bits)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = false;
+ pair.second.cpu->_registers.p.m = false;
+ pair.second.cpu->_registers.x = 0xABCD;
+ pair.second.cpu->_registers.a = 0xFEDC;
+ pair.second.cpu->TAX();
+ cr_assert_eq(pair.second.cpu->_registers.x, 0xFEDC, "The flags should be 0xFEDC but it was %x", pair.second.cpu->_registers.x);
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should not be set.");
+}
+
+Test(TAX, 16bitsTo8Bits)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = true;
+ pair.second.cpu->_registers.p.m = false;
+ pair.second.cpu->_registers.x = 0xFEDC;
+ pair.second.cpu->_registers.a = 0xAB00;
+ pair.second.cpu->TAX();
+ cr_assert_eq(pair.second.cpu->_registers.x, 0xFE00, "The flags should be 0xFE00 but it was %x", pair.second.cpu->_registers.x);
+ 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.z, true, "The zero flag should be set.");
+}
+
+Test(TAX, 8bitsTo16Bits)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = false;
+ pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.x = 0xFEDC;
+ pair.second.cpu->_registers.a = 0xAB;
+ pair.second.cpu->TAX();
+ cr_assert_eq(pair.second.cpu->_registers.x, 0x00AB, "The flags should be 0x00AB but it was %x", pair.second.cpu->_registers.x);
+ 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.z, false, "The zero flag should not be set.");
+}
+
+Test(TAX, 8bitsTo8Bits)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = true;
+ pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.x = 0xFE;
+ pair.second.cpu->_registers.a = 0xAB;
+ pair.second.cpu->TAX();
+ cr_assert_eq(pair.second.cpu->_registers.x, 0xAB, "The flags should be 0xAB but it was %x", pair.second.cpu->_registers.x);
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+
+Test(TAY, 16bitsTo16Bits)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = false;
+ pair.second.cpu->_registers.p.m = false;
+ pair.second.cpu->_registers.y = 0xABCD;
+ pair.second.cpu->_registers.a = 0xFEDC;
+ pair.second.cpu->TAY();
+ cr_assert_eq(pair.second.cpu->_registers.y, 0xFEDC, "The y register should be 0xFEDC but it was %x", pair.second.cpu->_registers.y);
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should not be set.");
+}
+
+Test(TAY, 16bitsTo8Bits)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = true;
+ pair.second.cpu->_registers.p.m = false;
+ pair.second.cpu->_registers.y = 0xFEDC;
+ pair.second.cpu->_registers.a = 0xAB00;
+ pair.second.cpu->TAY();
+ cr_assert_eq(pair.second.cpu->_registers.y, 0xFE00, "The y register should be 0xFE00 but it was %x", pair.second.cpu->_registers.y);
+ 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.z, true, "The zero flag should be set.");
+}
+
+Test(TAY, 8bitsTo16Bits)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = false;
+ pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.y = 0xFEDC;
+ pair.second.cpu->_registers.a = 0xAB;
+ pair.second.cpu->TAY();
+ cr_assert_eq(pair.second.cpu->_registers.y, 0x00AB, "The y register should be 0x00AB but it was %x", pair.second.cpu->_registers.y);
+ 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.z, false, "The zero flag should not be set.");
+}
+
+Test(TAY, 8bitsTo8Bits)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = true;
+ pair.second.cpu->_registers.p.m = true;
+ pair.second.cpu->_registers.y = 0xFE;
+ pair.second.cpu->_registers.a = 0xAB;
+ pair.second.cpu->TAY();
+ cr_assert_eq(pair.second.cpu->_registers.y, 0xAB, "The y register should be 0xAB but it was %x", pair.second.cpu->_registers.y);
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TXS, 16bitsIndex)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = false;
+ pair.second.cpu->_registers.x = 0xABCD;
+ pair.second.cpu->TXS();
+ cr_assert_eq(pair.second.cpu->_registers.s, 0xABCD, "The stack pointer should be 0xABCD but it was %x", pair.second.cpu->_registers.s);
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TXS, 8bitsIndex)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cpu->_registers.p.x_b = true;
+ pair.second.cpu->_registers.x = 0xABCD;
+ pair.second.cpu->TXS();
+ cr_assert_eq(pair.second.cpu->_registers.s, 0x00CD, "The stack pointer should be 0x00CD but it was %x", pair.second.cpu->_registers.s);
+ cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
\ No newline at end of file
From 258194dba7e5c2a0b4f61013392a799aee8b03f5 Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 28 Feb 2020 15:52:46 +0100
Subject: [PATCH 11/16] Solving bugs with the immediate addressing mode
---
sources/CPU/CPU.cpp | 28 ++++---
sources/CPU/CPU.hpp | 6 +-
.../CPU/Instructions/InternalInstruction.cpp | 16 ++--
sources/Debugger/CPUDebug.cpp | 75 +++++++++++++------
sources/Debugger/CPUDebug.hpp | 10 ++-
tests/CPU/testAddressingMode.cpp | 6 +-
tests/CPU/testInternal.cpp | 30 +++-----
7 files changed, 103 insertions(+), 68 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index beb5fec..bdf0dd1 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -205,7 +205,7 @@ namespace ComSquare::CPU
case Instructions::RTI: this->RTI(); return 6 + !this->_isEmulationMode;
- case Instructions::ADC_IM: this->ADC(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
+ case Instructions::ADC_IM: this->ADC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
case Instructions::ADC_ABS: this->ADC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::ADC_ABSl: this->ADC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
case Instructions::ADC_DP: this->ADC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
@@ -249,7 +249,7 @@ namespace ComSquare::CPU
case Instructions::STZ_ABSX: this->STX(this->_getAbsoluteIndexedByXAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
case Instructions::STZ_DPX: this->STX(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
- case Instructions::LDA_IM: this->LDA(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
+ case Instructions::LDA_IM: this->LDA(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
case Instructions::LDA_ABS: this->LDA(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::LDA_ABSl: this->LDA(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
case Instructions::LDA_DP: this->LDA(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
@@ -265,21 +265,21 @@ namespace ComSquare::CPU
case Instructions::LDA_SR: this->LDA(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m;
case Instructions::LDA_SRYi: this->LDA(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m;
- case Instructions::LDX_IM: this->LDX(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
+ case Instructions::LDX_IM: this->LDX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m;
case Instructions::LDX_ABS: this->LDX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::LDX_DP: this->LDX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
case Instructions::LDX_ABSY: this->LDX(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
case Instructions::LDX_DPY: this->LDX(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
- case Instructions::LDY_IM: this->LDY(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
+ case Instructions::LDY_IM: this->LDY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m;
case Instructions::LDY_ABS: this->LDY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::LDY_DP: this->LDY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
case Instructions::LDY_ABSY: this->LDY(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary;
case Instructions::LDY_DPY: this->LDY(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0;
- case Instructions::SEP: this->SEP(this->_getImmediateAddr()); return 3;
+ case Instructions::SEP: this->SEP(this->_bus->read(this->_registers.pc++)); return 3;
- case Instructions::REP: this->REP(this->_getImmediateAddr()); return 3;
+ case Instructions::REP: this->REP(this->_bus->read(this->_registers.pc++)); return 3;
case Instructions::PHA: this->PHA(); return 3 + !this->_registers.p.m;
case Instructions::PHB: this->PHB(); return 3;
@@ -299,7 +299,7 @@ namespace ComSquare::CPU
case Instructions::JSR_ABS: this->JSR(this->_getAbsoluteAddr()); return 6;
case Instructions::JSR_ABSXi: this->JSR(this->_getAbsoluteIndirectIndexedByXAddr()); return 8;
- case Instructions::JSL: this->JSR(this->_getAbsoluteLongAddr()); return 8;
+ case Instructions::JSL: this->JSL(this->_getAbsoluteLongAddr()); return 8;
case Instructions::CLC: this->CLC(); return 2;
case Instructions::CLI: this->CLI(); return 2;
@@ -310,7 +310,7 @@ namespace ComSquare::CPU
case Instructions::SED: this->SED(); return 2;
case Instructions::SEI: this->SEI(); return 2;
- case Instructions::AND_IM: this->AND(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
+ case Instructions::AND_IM: this->AND(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
case Instructions::AND_ABS: this->AND(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::AND_ABSl: this->AND(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
case Instructions::AND_DP: this->AND(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
@@ -328,7 +328,7 @@ namespace ComSquare::CPU
case Instructions::XCE: this->XCE(); return 2;
- case Instructions::SBC_IM: this->SBC(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
+ case Instructions::SBC_IM: this->SBC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
case Instructions::SBC_ABS: this->SBC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::SBC_ABSl: this->SBC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
case Instructions::SBC_DP: this->SBC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
@@ -378,7 +378,7 @@ namespace ComSquare::CPU
/// Addressing modes
////////////////////////////////////////////////////////////////////
- uint24_t CPU::_getImmediateAddr()
+ uint24_t CPU::_getImmediateAddrForA()
{
uint24_t effective = this->_registers.pac++;
if (!this->_registers.p.m)
@@ -386,6 +386,14 @@ namespace ComSquare::CPU
return effective;
}
+ uint24_t CPU::_getImmediateAddrForX()
+ {
+ uint24_t effective = this->_registers.pac++;
+ if (!this->_registers.p.x_b)
+ this->_registers.pac++;
+ return effective;
+ }
+
uint24_t CPU::_getDirectAddr()
{
uint8_t addr = this->_bus->read(this->_registers.pac++);
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index cec7a62..ac0fecb 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -350,8 +350,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. (This functions returns the 24bit space address of the value).
- uint24_t _getImmediateAddr();
+ //! @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).
+ uint24_t _getImmediateAddrForX();
//! @brief The destination is formed by adding the direct page register with the 8-bit address to form an effective address. (This functions returns the 24bit space address of the value).
uint24_t _getDirectAddr();
//! @brief The effective address is formed by DBR:<16-bit exp>. (This functions returns the 24bit space address of the value).
diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp
index b1ed4bc..6d13a76 100644
--- a/sources/CPU/Instructions/InternalInstruction.cpp
+++ b/sources/CPU/Instructions/InternalInstruction.cpp
@@ -41,32 +41,32 @@ namespace ComSquare::CPU
this->_registers.p.v = false;
}
- void CPU::SEP(uint24_t valueAddr)
+ void CPU::SEP(uint24_t value)
{
- this->_registers.p.flags |= this->_bus->read(valueAddr);
+ this->_registers.p.flags |= value;
}
- void CPU::REP(uint24_t valueAddr)
+ void CPU::REP(uint24_t value)
{
- this->_registers.p.flags &= ~this->_bus->read(valueAddr);
+ this->_registers.p.flags &= ~value;
if (this->_isEmulationMode) {
this->_registers.p.x_b = true;
this->_registers.p.m = true;
}
}
- void CPU::JSR(uint24_t valueAddr)
+ void CPU::JSR(uint24_t value)
{
this->_push(--this->_registers.pc);
- this->_registers.pc = this->_bus->read(valueAddr) + (this->_bus->read(valueAddr + 1) << 8u);
+ this->_registers.pc = value;
}
- void CPU::JSL(uint24_t valueAddr)
+ void CPU::JSL(uint24_t value)
{
this->_registers.pac--;
this->_push(this->_registers.pbr);
this->_push(this->_registers.pc);
- this->_registers.pc = this->_bus->read(valueAddr) + (this->_bus->read(valueAddr + 1) << 8u);
+ this->_registers.pac = value;
}
void CPU::PHA()
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index cc88cae..251b510 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -84,7 +84,7 @@ namespace ComSquare::Debugger
this->_ui.directBankLineEdit->setText(Utility::to_hex(this->_registers.dbr).c_str());
this->_ui.directPageLineEdit->setText(Utility::to_hex(this->_registers.d).c_str());
this->_ui.stackPointerLineEdit->setText(Utility::to_hex(this->_registers.s).c_str());
- if (this->_registers.p.x_b) {
+ if (!this->_registers.p.x_b) {
this->_ui.xIndexLineEdit->setText(Utility::to_hex(this->_registers.x).c_str());
this->_ui.yIndexLineEdit->setText(Utility::to_hex(this->_registers.y).c_str());
} else {
@@ -117,7 +117,7 @@ namespace ComSquare::Debugger
this->_ui.logger->clear();
}
- std::string CPUDebug::_getImmediateValue(uint24_t pc)
+ std::string CPUDebug::_getImmediateValueForA(uint24_t pc)
{
unsigned value = this->_bus->read(pc);
@@ -128,6 +128,24 @@ namespace ComSquare::Debugger
return ss.str();
}
+ std::string CPUDebug::_getImmediateValueForX(uint24_t pc)
+ {
+ unsigned value = this->_bus->read(pc);
+
+ if (!this->_registers.p.x_b)
+ value += this->_bus->read(pc + 1) << 8u;
+ std::stringstream ss;
+ ss << "#$" << std::hex << value;
+ return ss.str();
+ }
+
+ std::string CPUDebug::_getImmediateValue8Bits(uint24_t pc)
+ {
+ std::stringstream ss;
+ ss << "#$" << std::hex << static_cast(this->_bus->read(pc));
+ return ss.str();
+ }
+
std::string CPUDebug::_getDirectValue(uint24_t pc)
{
std::stringstream ss;
@@ -142,6 +160,17 @@ namespace ComSquare::Debugger
return ss.str();
}
+ std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc)
+ {
+ unsigned value = this->_bus->read(pc++);
+ value += this->_bus->read(pc++) << 8u;
+ value += this->_bus->read(pc) << 16u;
+
+ std::stringstream ss;
+ ss << "$" << std::hex << value;
+ return ss.str();
+ }
+
std::string CPUDebug::_getInstructionString(uint24_t pc)
{
uint8_t opcode = this->_bus->read(pc++);
@@ -153,9 +182,9 @@ namespace ComSquare::Debugger
case Instructions::RTI: return "RTI";
- case Instructions::ADC_IM: return "ADC " + this->_getImmediateValue(pc);
+ case Instructions::ADC_IM: return "ADC " + this->_getImmediateValueForA(pc);
case Instructions::ADC_ABS: return "ADC " + this->_getAbsoluteValue(pc);
- case Instructions::ADC_ABSl: return "ADC";
+ case Instructions::ADC_ABSl: return "ADC " + this->_getAbsoluteLongValue(pc);
case Instructions::ADC_DP: return "ADC " + this->_getDirectValue(pc);
case Instructions::ADC_DPi: return "ADC";
case Instructions::ADC_DPil: return "ADC";
@@ -170,7 +199,7 @@ namespace ComSquare::Debugger
case Instructions::ADC_SRYi: return "ADC";
case Instructions::STA_ABS: return "STA " + this->_getAbsoluteValue(pc);
- case Instructions::STA_ABSl: return "STA";
+ case Instructions::STA_ABSl: return "STA " + this->_getAbsoluteLongValue(pc);
case Instructions::STA_DP: return "STA " + this->_getDirectValue(pc);
case Instructions::STA_DPi: return "STA";
case Instructions::STA_DPil: return "STA";
@@ -188,18 +217,18 @@ namespace ComSquare::Debugger
case Instructions::STX_DP: return "STX " + this->_getDirectValue(pc);
case Instructions::STX_DPY: return "STX";
- case Instructions::STY_ABS: return "STX " + this->_getAbsoluteValue(pc);
- case Instructions::STY_DP: return "STX " + this->_getDirectValue(pc);
- case Instructions::STY_DPX: return "STX";
+ 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::STZ_ABS: return "STX " + this->_getAbsoluteValue(pc);
- case Instructions::STZ_DP: return "STX " + this->_getDirectValue(pc);
- case Instructions::STZ_ABSX: return "STX";
- case Instructions::STZ_DPX: return "STX";
+ 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::LDA_IM: return "LDA " + this->_getImmediateValue(pc);
+ case Instructions::LDA_IM: return "LDA " + this->_getImmediateValueForA(pc);
case Instructions::LDA_ABS: return "LDA " + this->_getAbsoluteValue(pc);
- case Instructions::LDA_ABSl: return "LDA";
+ case Instructions::LDA_ABSl: return "LDA " + this->_getAbsoluteLongValue(pc);
case Instructions::LDA_DP: return "LDA " + this->_getDirectValue(pc);
case Instructions::LDA_DPi: return "LDA";
case Instructions::LDA_DPil: return "LDA";
@@ -213,21 +242,21 @@ namespace ComSquare::Debugger
case Instructions::LDA_SR: return "LDA";
case Instructions::LDA_SRYi: return "LDA";
- case Instructions::LDX_IM: return "LDX " + this->_getImmediateValue(pc);
+ case Instructions::LDX_IM: return "LDX " + this->_getImmediateValueForX(pc);
case Instructions::LDX_ABS: return "LDX " + this->_getAbsoluteValue(pc);
case Instructions::LDX_DP: return "LDX " + this->_getDirectValue(pc);
case Instructions::LDX_ABSY: return "LDX";
case Instructions::LDX_DPY: return "LDX";
- case Instructions::LDY_IM: return "LDY " + this->_getImmediateValue(pc);
+ case Instructions::LDY_IM: return "LDY " + this->_getImmediateValueForX(pc);
case Instructions::LDY_ABS: return "LDY " + this->_getAbsoluteValue(pc);
case Instructions::LDY_DP: return "LDY " + this->_getDirectValue(pc);
case Instructions::LDY_ABSY: return "LDY";
case Instructions::LDY_DPY: return "LDY";
- case Instructions::SEP: return "SEP " + this->_getImmediateValue(pc);
+ case Instructions::SEP: return "SEP " + this->_getImmediateValue8Bits(pc);
- case Instructions::REP: return "REP " + this->_getImmediateValue(pc);
+ case Instructions::REP: return "REP " + this->_getImmediateValue8Bits(pc);
case Instructions::PHA: return "PHA";
case Instructions::PHB: return "PHB";
@@ -247,7 +276,7 @@ namespace ComSquare::Debugger
case Instructions::JSR_ABS: return "JSR " + this->_getAbsoluteValue(pc);
case Instructions::JSR_ABSXi: return "JSR";
- case Instructions::JSL: return "JSR";
+ case Instructions::JSL: return "JSL " + this->_getAbsoluteLongValue(pc);
case Instructions::CLC: return "CLC";
case Instructions::CLI: return "CLI";
@@ -258,9 +287,9 @@ namespace ComSquare::Debugger
case Instructions::SED: return "SED";
case Instructions::SEI: return "SEI";
- case Instructions::AND_IM: return "AND " + this->_getImmediateValue(pc);
+ case Instructions::AND_IM: return "AND " + this->_getImmediateValueForA(pc);
case Instructions::AND_ABS: return "AND " + this->_getAbsoluteValue(pc);
- case Instructions::AND_ABSl: return "AND";
+ case Instructions::AND_ABSl: return "AND " + this->_getAbsoluteLongValue(pc);
case Instructions::AND_DP: return "AND " + this->_getDirectValue(pc);
case Instructions::AND_DPi: return "AND";
case Instructions::AND_DPil: return "AND";
@@ -276,9 +305,9 @@ namespace ComSquare::Debugger
case Instructions::XCE: return "XCE";
- case Instructions::SBC_IM: return "SBC " + this->_getImmediateValue(pc);
+ case Instructions::SBC_IM: return "SBC " + this->_getImmediateValueForA(pc);
case Instructions::SBC_ABS: return "SBC " + this->_getAbsoluteValue(pc);
- case Instructions::SBC_ABSl: return "SBC";
+ case Instructions::SBC_ABSl: return "SBC " + this->_getAbsoluteLongValue(pc);
case Instructions::SBC_DP: return "SBC " + this->_getDirectValue(pc);
case Instructions::SBC_DPi: return "SBC";
case Instructions::SBC_DPil: return "SBC";
diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp
index 88d9c95..5928c94 100644
--- a/sources/Debugger/CPUDebug.hpp
+++ b/sources/Debugger/CPUDebug.hpp
@@ -32,12 +32,18 @@ namespace ComSquare::Debugger
//! @brief Update the register's panel (accumulator, stack pointer...)
void _updateRegistersPanel();
- //! @brief Return a printable string corresponding to the value of an immediate addressing mode.
- std::string _getImmediateValue(uint24_t pc);
+ //! @brief Return a printable string corresponding to the value of an immediate addressing mode for a.
+ std::string _getImmediateValueForA(uint24_t pc);
+ //! @brief Return a printable string corresponding to the value of an immediate addressing mode for x.
+ std::string _getImmediateValueForX(uint24_t pc);
+ //! @brief Return a printable string corresponding to the value of a 8bits immediate addressing mode (used only with SEP and REP).
+ std::string _getImmediateValue8Bits(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct addressing mode.
std::string _getDirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of an absolute addressing mode.
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);
public slots:
//! @brief Pause/Resume the CPU.
diff --git a/tests/CPU/testAddressingMode.cpp b/tests/CPU/testAddressingMode.cpp
index 9fa9ecb..0c7cf4f 100644
--- a/tests/CPU/testAddressingMode.cpp
+++ b/tests/CPU/testAddressingMode.cpp
@@ -22,7 +22,7 @@ Test(AddrMode, Immediate)
pair.second.cpu->_registers.pac = 0x000015;
pair.second.cpu->_isEmulationMode = true;
pair.second.cpu->_registers.p.m = false;
- cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x000015, "Got %x, Expected 0x000015");
+ cr_assert_eq(pair.second.cpu->_getImmediateAddrForA(), 0x000015, "Got %x, Expected 0x000015");
cr_assert_eq(pair.second.cpu->_registers.pac, 0x000017);
}
@@ -32,7 +32,7 @@ Test(AddrMode, ImmediateMemoryFlag)
pair.second.cpu->_isEmulationMode = true;
pair.second.cpu->_registers.pac = 0x000015;
pair.second.cpu->_registers.p.m = false;
- cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x000015, "Got %x, Expected 0x000015");
+ cr_assert_eq(pair.second.cpu->_getImmediateAddrForA(), 0x000015, "Got %x, Expected 0x000015");
cr_assert_eq(pair.second.cpu->_registers.pac, 0x000017);
}
@@ -41,7 +41,7 @@ Test(AddrMode, ImmediateBankChange)
auto pair = Init();
pair.second.cpu->_registers.pac = 0x00FFFF;
pair.second.cpu->_registers.p.m = true;
- cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x00FFFF);
+ cr_assert_eq(pair.second.cpu->_getImmediateAddrForA(), 0x00FFFF);
cr_assert_eq(pair.second.cpu->_registers.pac, 0x010000);
}
diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp
index 87bce8e..cd2c124 100644
--- a/tests/CPU/testInternal.cpp
+++ b/tests/CPU/testInternal.cpp
@@ -13,8 +13,7 @@ using namespace ComSquare;
Test(SEP, setall)
{
auto pair = Init();
- pair.second.wram->_data[0] = 0xFF;
- pair.second.cpu->SEP(0x0);
+ pair.second.cpu->SEP(0xFF);
auto data = pair.second.cpu->_registers.p.flags;
cr_assert_eq(data, 0xFF, "The flag should be 0xFF but it was %x", data);
}
@@ -22,9 +21,8 @@ Test(SEP, setall)
Test(SEP, setsome)
{
auto pair = Init();
- pair.second.wram->_data[0] = 0b10110101;
pair.second.cpu->_registers.p.flags = 0b01000000;
- pair.second.cpu->SEP(0x0);
+ pair.second.cpu->SEP(0b10110101);
auto data = pair.second.cpu->_registers.p.flags;
cr_assert_eq(data, 0b11110101, "The flag should be 245 but it was %i", data);
}
@@ -33,8 +31,7 @@ Test(REP, resetall)
{
auto pair = Init();
pair.second.cpu->_isEmulationMode = false;
- pair.second.wram->_data[0] = 0xFF;
- pair.second.cpu->REP(0x0);
+ pair.second.cpu->REP(0xFF);
auto data = pair.second.cpu->_registers.p.flags;
cr_assert_eq(data, 0x00, "The flag should be 0x00 but it was %x", data);
}
@@ -43,9 +40,8 @@ Test(REP, resetsome)
{
auto pair = Init();
pair.second.cpu->_isEmulationMode = false;
- pair.second.wram->_data[0] = 0b01000000;
pair.second.cpu->_registers.p.flags = 0b01000000;
- pair.second.cpu->REP(0x0);
+ pair.second.cpu->REP(0b01000000);
auto data = pair.second.cpu->_registers.p.flags;
cr_assert_eq(data, 0x0, "The flag should be 0 but it was %x", data);
}
@@ -54,8 +50,7 @@ Test(REP, resetallEmulation)
{
auto pair = Init();
pair.second.cpu->_isEmulationMode = true;
- pair.second.wram->_data[0] = 0xFF;
- pair.second.cpu->REP(0x0);
+ pair.second.cpu->REP(0xFF);
auto data = pair.second.cpu->_registers.p.flags;
cr_assert_eq(data, 0b00110000, "The flag should be 0b00110000 but it was %x", data);
}
@@ -64,9 +59,8 @@ Test(REP, resetsomeEmulation)
{
auto pair = Init();
pair.second.cpu->_isEmulationMode = true;
- pair.second.wram->_data[0] = 0b01000001;
pair.second.cpu->_registers.p.flags = 0b01000101;
- pair.second.cpu->REP(0x0);
+ pair.second.cpu->REP(0b01000001);
auto data = pair.second.cpu->_registers.p.flags;
cr_assert_eq(data, 0b00110100, "The flag should be 0b00110100 but it was %x", data);
}
@@ -76,9 +70,7 @@ Test(JSR, jump)
auto pair = Init();
pair.second.cpu->_registers.pc = 0xABCD;
pair.second.cpu->_registers.s = 0x0123;
- pair.second.wram->_data[0] = 0xFF;
- pair.second.wram->_data[1] = 0xAB;
- pair.second.cpu->JSR(0x0);
+ pair.second.cpu->JSR(0xABFF);
auto pc = pair.second.cpu->_registers.pc;
cr_assert_eq(pc, 0xABFF, "The PC should be 0xABFF but it was %x", pc);
cr_assert_eq(pair.second.cpu->_registers.s, 0x0121, "The stack pointer should be 0x0121 but it was %x", pair.second.cpu->_registers.s);
@@ -92,11 +84,9 @@ Test(JSL, jump)
pair.second.cpu->_registers.pbr = 0xFF;
pair.second.cpu->_registers.pc = 0xABCD;
pair.second.cpu->_registers.s = 0x0123;
- pair.second.wram->_data[0] = 0xFF;
- pair.second.wram->_data[1] = 0xAB;
- pair.second.cpu->JSL(0x0);
- auto pc = pair.second.cpu->_registers.pc;
- cr_assert_eq(pc, 0xABFF, "The PC should be 0xABFF but it was %x", pc);
+ pair.second.cpu->JSL(0xCDABFF);
+ auto pac = pair.second.cpu->_registers.pac;
+ cr_assert_eq(pac, 0xCDABFF, "The PC should be 0xCDABFF but it was %x", pac);
cr_assert_eq(pair.second.cpu->_registers.s, 0x0120, "The stack pointer should be 0x0120 but it was %x", pair.second.cpu->_registers.s);
auto pushed = pair.second.cpu->_pop16() + (pair.second.cpu->_pop() << 16u);
cr_assert_eq(pushed, 0xFFABCC, "The value pushed to the stack should be 0xFFABCD but it was %x", pushed);
From 7b34473e63ab399ab443ba033078c9c55f33ec81 Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 28 Feb 2020 16:41:57 +0100
Subject: [PATCH 12/16] Adding inx and iny and improving the debugger
---
sources/CPU/CPU.cpp | 3 ++
sources/CPU/CPU.hpp | 9 +++-
.../CPU/Instructions/InternalInstruction.cpp | 24 +++++++++
sources/Debugger/CPUDebug.cpp | 26 ++++++---
sources/Debugger/CPUDebug.hpp | 2 +
tests/CPU/testInternal.cpp | 54 +++++++++++++++++++
6 files changed, 110 insertions(+), 8 deletions(-)
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
From 68b82c9cdafb7fa5cb3ee413d2843e4b8b3064a8 Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 28 Feb 2020 17:23:27 +0100
Subject: [PATCH 13/16] 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
From d1561f1be37d6066b1bffc8cfaf6b8c2e9c417c6 Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 28 Feb 2020 19:20:59 +0100
Subject: [PATCH 14/16] Adding branch instructions
---
sources/CPU/CPU.cpp | 13 +-
sources/CPU/CPU.hpp | 33 ++-
.../CPU/Instructions/InternalInstruction.cpp | 71 +++++
sources/Debugger/CPUDebug.cpp | 21 ++
sources/Debugger/CPUDebug.hpp | 2 +
tests/CPU/testInternal.cpp | 279 ++++++++++++++++++
6 files changed, 417 insertions(+), 2 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 36ef7fb..ca1a0b3 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -328,7 +328,7 @@ namespace ComSquare::CPU
case Instructions::XCE: this->XCE(); return 2;
- case Instructions::SBC_IM: this->SBC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
+ case Instructions::SBC_IM: this->SBC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m;
case Instructions::SBC_ABS: this->SBC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m;
case Instructions::SBC_ABSl: this->SBC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m;
case Instructions::SBC_DP: this->SBC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0;
@@ -359,6 +359,17 @@ namespace ComSquare::CPU
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;
+ case Instructions::BCC: return this->BCC(this->_registers.pc++) + 2 + this->_isEmulationMode;
+ case Instructions::BCS: return this->BCS(this->_registers.pc++) + 2 + this->_isEmulationMode;
+ case Instructions::BEQ: return this->BEQ(this->_registers.pc++) + 2 + this->_isEmulationMode;
+ case Instructions::BNE: return this->BNE(this->_registers.pc++) + 2 + this->_isEmulationMode;
+ case Instructions::BMI: return this->BMI(this->_registers.pc++) + 2 + this->_isEmulationMode;
+ case Instructions::BPL: return this->BPL(this->_registers.pc++) + 2 + this->_isEmulationMode;
+ case Instructions::BVC: return this->BVC(this->_registers.pc++) + 2 + this->_isEmulationMode;
+ case Instructions::BVS: return this->BVS(this->_registers.pc++) + 2 + this->_isEmulationMode;
+ case Instructions::BRA: this->BRA(this->_registers.pc++); return 3 + this->_isEmulationMode;
+ case Instructions::BRL: this->BRL(this->_registers.pc); this->_registers.pc += 2; return 4;
+
default:
throw InvalidOpcode("CPU", opcode);
}
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index ecbadff..ab2d913 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -341,7 +341,18 @@ namespace ComSquare::CPU
CPY_IM = 0xC0,
CPY_ABS = 0xCC,
- CPY_DP = 0xC4
+ CPY_DP = 0xC4,
+
+ BCC = 0x90,
+ BCS = 0xB0,
+ BEQ = 0xF0,
+ BNE = 0xD0,
+ BMI = 0x30,
+ BPL = 0x10,
+ BVC = 0x50,
+ BVS = 0x70,
+ BRA = 0x80,
+ BRL = 0x82
};
//! @brief The main CPU
@@ -509,6 +520,26 @@ namespace ComSquare::CPU
void CPX(uint24_t valueAddr);
//! @brief Compare the Y register with the memory
void CPY(uint24_t valueAddr);
+ //! @brief Branch if carry clear
+ bool BCC(uint24_t valueAddr);
+ //! @brief Branch if carry set
+ bool BCS(uint24_t valueAddr);
+ //! @brief Branch if equal
+ bool BEQ(uint24_t valueAddr);
+ //! @brief Branch if not equal
+ bool BNE(uint24_t valueAddr);
+ //! @brief Branch if minus
+ bool BMI(uint24_t valueAddr);
+ //! @brief Branch if plus
+ bool BPL(uint24_t valueAddr);
+ //! @brief Branch if Overflow Clear
+ bool BVC(uint24_t valueAddr);
+ //! @brief Branch if Overflow Set
+ bool BVS(uint24_t valueAddr);
+ //! @brief Branch always
+ bool BRA(uint24_t valueAddr);
+ //! @brief Branch always long
+ bool BRL(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 890ad93..abc1d6b 100644
--- a/sources/CPU/Instructions/InternalInstruction.cpp
+++ b/sources/CPU/Instructions/InternalInstruction.cpp
@@ -226,4 +226,75 @@ namespace ComSquare::CPU
this->_registers.p.n = y & 0x8000u;
}
}
+
+ bool CPU::BCC(uint24_t valueAddr)
+ {
+ if (!this->_registers.p.c)
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return !this->_registers.p.c;
+ }
+
+ bool CPU::BCS(uint24_t valueAddr)
+ {
+ if (this->_registers.p.c)
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return this->_registers.p.c;
+ }
+
+ bool CPU::BEQ(uint24_t valueAddr)
+ {
+ if (this->_registers.p.z)
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return this->_registers.p.z;
+ }
+
+ bool CPU::BNE(uint24_t valueAddr)
+ {
+ if (!this->_registers.p.z)
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return !this->_registers.p.z;
+ }
+
+ bool CPU::BMI(uint24_t valueAddr)
+ {
+ if (this->_registers.p.n)
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return this->_registers.p.n;
+ }
+
+ bool CPU::BPL(uint24_t valueAddr)
+ {
+ if (!this->_registers.p.n)
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return !this->_registers.p.n;
+ }
+
+ bool CPU::BRA(uint24_t valueAddr)
+ {
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return true;
+ }
+
+ bool CPU::BRL(uint24_t valueAddr)
+ {
+ unsigned value = this->_bus->read(valueAddr);
+ value += this->_bus->read(valueAddr + 1) << 8u;
+
+ this->_registers.pac += static_cast(value);
+ return true;
+ }
+
+ bool CPU::BVC(uint24_t valueAddr)
+ {
+ if (!this->_registers.p.v)
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return !this->_registers.p.v;
+ }
+
+ bool CPU::BVS(uint24_t valueAddr)
+ {
+ if (this->_registers.p.v)
+ this->_registers.pac += static_cast(this->_bus->read(valueAddr));
+ return this->_registers.p.v;
+ }
}
\ No newline at end of file
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index e924a14..613e0df 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -146,6 +146,16 @@ namespace ComSquare::Debugger
return ss.str();
}
+ std::string CPUDebug::_getImmediateValue16Bits(uint24_t pc)
+ {
+ unsigned value = this->_bus->read(pc);
+ value += this->_bus->read(pc + 1) << 8u;
+
+ std::stringstream ss;
+ ss << "#$" << std::hex << value;
+ return ss.str();
+ }
+
std::string CPUDebug::_getDirectValue(uint24_t pc)
{
std::stringstream ss;
@@ -345,6 +355,17 @@ namespace ComSquare::Debugger
case Instructions::CPY_ABS: return "CPY " + this->_getAbsoluteValue(pc);
case Instructions::CPY_DP: return "CPY";
+ case Instructions::BCC: return "BCC " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BCS: return "BCS " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BEQ: return "BEQ " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BNE: return "BNE " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BMI: return "BMI " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BPL: return "BPL " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BVC: return "BVC " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BVS: return "BVS " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BRA: return "BRA " + this->_getImmediateValue8Bits(pc);
+ case Instructions::BRL: return "BRL " + this->_getImmediateValue16Bits(pc);
+
default: return "Unknown";
}
}
diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp
index 6489a71..e40f361 100644
--- a/sources/Debugger/CPUDebug.hpp
+++ b/sources/Debugger/CPUDebug.hpp
@@ -38,6 +38,8 @@ namespace ComSquare::Debugger
std::string _getImmediateValueForX(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a 8bits immediate addressing mode (used only with SEP and REP).
std::string _getImmediateValue8Bits(uint24_t pc);
+ //! @brief Return a printable string corresponding to the value of a 16bits immediate addressing mode.
+ std::string _getImmediateValue16Bits(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct addressing mode.
std::string _getDirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of an absolute addressing mode.
diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp
index 061ba62..b704172 100644
--- a/tests/CPU/testInternal.cpp
+++ b/tests/CPU/testInternal.cpp
@@ -604,4 +604,283 @@ Test(CPY, negative)
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(BCC, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.c = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BCC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BCC, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.c = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BCC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BCC, noJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.c = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x90;
+ pair.second.cpu->BCC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BCS, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.c = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BCS(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BCS, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.c = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BCS(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BCS, noJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.c = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x90;
+ pair.second.cpu->BCS(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BEQ, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.z = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BEQ(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BEQ, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.z = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BEQ(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BEQ, noJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.z = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x90;
+ pair.second.cpu->BEQ(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BNE, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.z = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BNE(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BNE, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.z = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BNE(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BNE, noJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.z = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x90;
+ pair.second.cpu->BNE(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BMI, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.n = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BMI(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BMI, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.n = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BMI(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BMI, noJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.n = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x90;
+ pair.second.cpu->BMI(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BPL, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.n = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BPL(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BPL, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.n = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BPL(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BPL, noJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.n = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x90;
+ pair.second.cpu->BPL(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BRA, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BRA(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BRA, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BRA(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BRL, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.pc = 0x8080;
+ pair.second.wram->_data[0] = 0x00;
+ pair.second.wram->_data[1] = 0x10;
+ pair.second.cpu->BRL(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x9080, "The program counter should be equal to 0x9080 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BRL, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.pc = 0x8080;
+ pair.second.wram->_data[0] = 0x00;
+ pair.second.wram->_data[1] = 0xF0;
+ pair.second.cpu->BRL(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x7080, "The program counter should be equal to 0x7080 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BVC, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.v = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BVC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BVC, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.v = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BVC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BVC, noJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.v = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x90;
+ pair.second.cpu->BVC(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+
+Test(BVS, basic)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.v = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x50;
+ pair.second.cpu->BVS(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0xD0, "The program counter should be equal to 0xD0 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BVS, negativeJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.v = true;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0xF0;
+ pair.second.cpu->BVS(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x70, "The program counter should be equal to 0x70 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(BVS, noJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.p.v = false;
+ pair.second.cpu->_registers.pc = 0x80;
+ pair.second.wram->_data[0] = 0x90;
+ pair.second.cpu->BVS(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
\ No newline at end of file
From c15ec0a9cb57ec578f60aa44a9cbc4067dbea16c Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 28 Feb 2020 20:25:34 +0100
Subject: [PATCH 15/16] Starting the jump
---
sources/CPU/CPU.cpp | 7 +++++++
sources/CPU/CPU.hpp | 13 +++++++++++-
.../CPU/Instructions/InternalInstruction.cpp | 17 +++++++++++++++
sources/Debugger/CPUDebug.cpp | 7 +++++++
sources/PPU/PPU.cpp | 5 -----
tests/CPU/testInternal.cpp | 21 +++++++++++++++++++
6 files changed, 64 insertions(+), 6 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index ca1a0b3..e7f0903 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -370,6 +370,13 @@ namespace ComSquare::CPU
case Instructions::BRA: this->BRA(this->_registers.pc++); return 3 + this->_isEmulationMode;
case Instructions::BRL: this->BRL(this->_registers.pc); this->_registers.pc += 2; return 4;
+ case Instructions::JMP_ABS: this->JMP(this->_getAbsoluteAddr()); return 3;
+ case Instructions::JMP_ABSi: this->JMP(this->_getAbsoluteIndirectAddr()); return 3;
+ case Instructions::JMP_ABSXi: this->JMP(this->_getAbsoluteIndexedByXAddr()); return 3;
+
+ case Instructions::JML_ABSl: this->JML(this->_getAbsoluteLongAddr()); return 3;
+ //case Instructions::JML_ABSil: this->JML(this->_getAbsoluteLong()); return 3;
+
default:
throw InvalidOpcode("CPU", opcode);
}
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index ab2d913..b3cc6cf 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -352,7 +352,14 @@ namespace ComSquare::CPU
BVC = 0x50,
BVS = 0x70,
BRA = 0x80,
- BRL = 0x82
+ BRL = 0x82,
+
+ JMP_ABS = 0x4C,
+ JMP_ABSi = 0x6C,
+ JMP_ABSXi = 0x7C,
+
+ JML_ABSl = 0x5C,
+ JML_ABSil = 0xDC
};
//! @brief The main CPU
@@ -540,6 +547,10 @@ namespace ComSquare::CPU
bool BRA(uint24_t valueAddr);
//! @brief Branch always long
bool BRL(uint24_t valueAddr);
+ //! @brief Jump.
+ void JMP(uint24_t valueAddr);
+ //! @brief Long jump.
+ void JML(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 abc1d6b..16b426b 100644
--- a/sources/CPU/Instructions/InternalInstruction.cpp
+++ b/sources/CPU/Instructions/InternalInstruction.cpp
@@ -297,4 +297,21 @@ namespace ComSquare::CPU
this->_registers.pac += static_cast(this->_bus->read(valueAddr));
return this->_registers.p.v;
}
+
+ void CPU::JMP(uint24_t valueAddr)
+ {
+ unsigned value = this->_bus->read(valueAddr);
+ value += this->_bus->read(valueAddr + 1) << 8u;
+
+ this->_registers.pc = value;
+ }
+
+ void CPU::JML(uint24_t valueAddr)
+ {
+ unsigned value = this->_bus->read(valueAddr);
+ value += this->_bus->read(valueAddr + 1) << 8u;
+ value += this->_bus->read(valueAddr + 2) << 16u;
+
+ this->_registers.pac = value;
+ }
}
\ No newline at end of file
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 613e0df..bb80fe6 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -366,6 +366,13 @@ namespace ComSquare::Debugger
case Instructions::BRA: return "BRA " + this->_getImmediateValue8Bits(pc);
case Instructions::BRL: return "BRL " + this->_getImmediateValue16Bits(pc);
+ case Instructions::JMP_ABS: return "JMP " + this->_getAbsoluteValue(pc);
+ case Instructions::JMP_ABSi: return "JMP "; //+ this->_getAbsoluteIndire(pc);
+ case Instructions::JMP_ABSXi: return "JMP "; //+ this->_getAbsoluteValue(pc);
+
+ case Instructions::JML_ABSl: return "JML";
+ case Instructions::JML_ABSil: return "JML";
+
default: return "Unknown";
}
}
diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp
index 1a212dc..d029ca0 100644
--- a/sources/PPU/PPU.cpp
+++ b/sources/PPU/PPU.cpp
@@ -206,11 +206,6 @@ namespace ComSquare::PPU
void PPU::update(unsigned cycles)
{
(void)cycles;
- this->_bus->write(0x2121, 0);
- for (uint16_t value = 0; value <= 256; value++) {
- this->_bus->write(0x2122, 0b11100000);
- this->_bus->write(0x2122, 0b00000011);
- }
uint16_t tmp;
uint8_t red;
uint8_t green;
diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp
index b704172..e4b7bf6 100644
--- a/tests/CPU/testInternal.cpp
+++ b/tests/CPU/testInternal.cpp
@@ -883,4 +883,25 @@ Test(BVS, noJump)
pair.second.wram->_data[0] = 0x90;
pair.second.cpu->BVS(0x0);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x80, "The program counter should be equal to 0x80 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(JMP, simpleJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.pc = 0x8000;
+ pair.second.wram->_data[0] = 0x00;
+ pair.second.wram->_data[1] = 0x10;
+ pair.second.cpu->JMP(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x1000, "The program counter should be equal to 0x9000 but it was 0x%x.", pair.second.cpu->_registers.pc);
+}
+
+Test(JML, simpleJump)
+{
+ auto pair = Init();
+ pair.second.cpu->_registers.pc = 0x8000;
+ pair.second.wram->_data[0] = 0x00;
+ pair.second.wram->_data[1] = 0xAB;
+ pair.second.wram->_data[2] = 0x10;
+ pair.second.cpu->JML(0x0);
+ cr_assert_eq(pair.second.cpu->_registers.pac, 0x10AB00, "The program counter should be equal to 0x10AB00 but it was 0x%x.", pair.second.cpu->_registers.pac);
}
\ No newline at end of file
From 92950dd84490dea74cd1b5a0553675ae19cb6c5f Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 13 Mar 2020 15:33:38 +0100
Subject: [PATCH 16/16] Solving a bug with the jump instruction
---
sources/CPU/CPU.cpp | 9 +++++----
sources/CPU/Instructions/InternalInstruction.cpp | 11 ++---------
sources/Memory/IMemory.hpp | 3 +++
sources/Memory/MemoryBus.hpp | 2 +-
tests/CPU/testInternal.cpp | 9 ++-------
5 files changed, 13 insertions(+), 21 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index e7f0903..ffc2647 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -197,6 +197,7 @@ namespace ComSquare::CPU
unsigned CPU::_executeInstruction(uint8_t opcode)
{
this->_hasIndexCrossedPageBoundary = false;
+ uint24_t addr;
switch (opcode) {
case Instructions::BRK: this->BRK(); return 7 + !this->_isEmulationMode;
@@ -370,11 +371,11 @@ namespace ComSquare::CPU
case Instructions::BRA: this->BRA(this->_registers.pc++); return 3 + this->_isEmulationMode;
case Instructions::BRL: this->BRL(this->_registers.pc); this->_registers.pc += 2; return 4;
- case Instructions::JMP_ABS: this->JMP(this->_getAbsoluteAddr()); return 3;
- case Instructions::JMP_ABSi: this->JMP(this->_getAbsoluteIndirectAddr()); return 3;
- case Instructions::JMP_ABSXi: this->JMP(this->_getAbsoluteIndexedByXAddr()); return 3;
+ case Instructions::JMP_ABS: addr = this->_getAbsoluteAddr(); this->JMP(addr); return 3;
+ case Instructions::JMP_ABSi: addr = this->_getAbsoluteIndirectAddr(); this->JMP(addr); return 3;
+ case Instructions::JMP_ABSXi: addr = this->_getAbsoluteIndexedByXAddr(); this->JMP(addr); return 3;
- case Instructions::JML_ABSl: this->JML(this->_getAbsoluteLongAddr()); return 3;
+ case Instructions::JML_ABSl: addr = this->_getAbsoluteLongAddr(); this->JML(addr); return 3;
//case Instructions::JML_ABSil: this->JML(this->_getAbsoluteLong()); return 3;
default:
diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp
index 16b426b..6c16c0c 100644
--- a/sources/CPU/Instructions/InternalInstruction.cpp
+++ b/sources/CPU/Instructions/InternalInstruction.cpp
@@ -298,20 +298,13 @@ namespace ComSquare::CPU
return this->_registers.p.v;
}
- void CPU::JMP(uint24_t valueAddr)
+ void CPU::JMP(uint24_t value)
{
- unsigned value = this->_bus->read(valueAddr);
- value += this->_bus->read(valueAddr + 1) << 8u;
-
this->_registers.pc = value;
}
- void CPU::JML(uint24_t valueAddr)
+ void CPU::JML(uint24_t value)
{
- unsigned value = this->_bus->read(valueAddr);
- value += this->_bus->read(valueAddr + 1) << 8u;
- value += this->_bus->read(valueAddr + 2) << 16u;
-
this->_registers.pac = value;
}
}
\ No newline at end of file
diff --git a/sources/Memory/IMemory.hpp b/sources/Memory/IMemory.hpp
index 6f7d33b..78aa385 100644
--- a/sources/Memory/IMemory.hpp
+++ b/sources/Memory/IMemory.hpp
@@ -49,6 +49,9 @@ namespace ComSquare::Memory
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
virtual std::shared_ptr getMirrored();
+ // TODO add destructors everywhere
+ // TODO rename this as an abstract.
+ virtual ~IMemory() = default;
};
};
diff --git a/sources/Memory/MemoryBus.hpp b/sources/Memory/MemoryBus.hpp
index 1bd4844..3274807 100644
--- a/sources/Memory/MemoryBus.hpp
+++ b/sources/Memory/MemoryBus.hpp
@@ -28,7 +28,7 @@ namespace ComSquare
//! @brief WRam, CPU, PPU & APU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring.
//! @param console All the components.
//! @param i Base address for the mirrors.
- inline void _mirrorComponents(SNES &console, unsigned i);
+ void _mirrorComponents(SNES &console, unsigned i);
public:
MemoryBus() = default;
diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp
index e4b7bf6..888caf4 100644
--- a/tests/CPU/testInternal.cpp
+++ b/tests/CPU/testInternal.cpp
@@ -889,9 +889,7 @@ Test(JMP, simpleJump)
{
auto pair = Init();
pair.second.cpu->_registers.pc = 0x8000;
- pair.second.wram->_data[0] = 0x00;
- pair.second.wram->_data[1] = 0x10;
- pair.second.cpu->JMP(0x0);
+ pair.second.cpu->JMP(0x1000);
cr_assert_eq(pair.second.cpu->_registers.pc, 0x1000, "The program counter should be equal to 0x9000 but it was 0x%x.", pair.second.cpu->_registers.pc);
}
@@ -899,9 +897,6 @@ Test(JML, simpleJump)
{
auto pair = Init();
pair.second.cpu->_registers.pc = 0x8000;
- pair.second.wram->_data[0] = 0x00;
- pair.second.wram->_data[1] = 0xAB;
- pair.second.wram->_data[2] = 0x10;
- pair.second.cpu->JML(0x0);
+ pair.second.cpu->JML(0x10AB00);
cr_assert_eq(pair.second.cpu->_registers.pac, 0x10AB00, "The program counter should be equal to 0x10AB00 but it was 0x%x.", pair.second.cpu->_registers.pac);
}
\ No newline at end of file