From f35427f28ac32d3ef0c81b848a357e711b6936cb Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Tue, 7 Apr 2020 22:40:53 +0200
Subject: [PATCH] Adding most of the transfer instructions
---
sources/CPU/CPU.hpp | 28 +-
.../CPU/Instructions/TransferRegisters.cpp | 76 ++++++
tests/CPU/TransferRegisters.cpp | 241 +++++++++++++++++-
3 files changed, 337 insertions(+), 8 deletions(-)
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 9a61baa..f928561 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -397,6 +397,20 @@ namespace ComSquare::CPU
int DEC(uint24_t, AddressingMode);
//! @brief XOR, Exclusive OR accumulator with memory.
int EOR(uint24_t, AddressingMode);
+ //! @brief Transfer 16 bit A to DP
+ int TCD(uint24_t, AddressingMode);
+ //! @brief Transfer 16 bit A to SP
+ int TCS(uint24_t, AddressingMode);
+ //! @brief Transfer DP to 16 bit A
+ int TDC(uint24_t, AddressingMode);
+ //! @brief Transfer DP to 16 bit A
+ int TSC(uint24_t, AddressingMode);
+ //! @brief Transfer SP to X
+ int TSX(uint24_t, AddressingMode);
+ //! @brief Transfer X to A
+ int TXA(uint24_t, AddressingMode);
+ //! @brief Transfer Y to A
+ int TYA(uint24_t, AddressingMode);
//! @brief All the instructions of the CPU.
//! @info Instructions are indexed by their opcode
@@ -428,7 +442,7 @@ namespace ComSquare::CPU
{&CPU::CLC, 2, "clc", AddressingMode::Implied, 1}, // 18
{&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByY, 3}, // 19
{&CPU::INC, 2, "inc", AddressingMode::Implied, 1}, // 1A
- {&CPU::BRK, 7, "tcs #-#", AddressingMode::Implied, 2}, // 1B
+ {&CPU::TCS, 2, "tcs", AddressingMode::Implied, 1}, // 1B
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C
{&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByX, 3}, // 1D
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 1E
@@ -460,7 +474,7 @@ namespace ComSquare::CPU
{&CPU::SEC, 2, "sec", AddressingMode::Implied, 1}, // 38
{&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByY, 3}, // 39
{&CPU::DEC, 2, "dec", AddressingMode::Implied, 1}, // 3A
- {&CPU::BRK, 7, "tsc #-#", AddressingMode::Implied, 2}, // 3B
+ {&CPU::TSC, 2, "tsc", AddressingMode::Implied, 1}, // 3B
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C
{&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByX, 3}, // 3D
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 3E
@@ -492,7 +506,7 @@ namespace ComSquare::CPU
{&CPU::CLI, 2, "cli", AddressingMode::Implied, 1}, // 58
{&CPU::EOR, 4, "eor", AddressingMode::AbsoluteIndexedByY, 3}, // 59
{&CPU::PHY, 3, "phy", AddressingMode::Implied, 1}, // 5A
- {&CPU::BRK, 7, "tcd #-#", AddressingMode::Implied, 2}, // 5B
+ {&CPU::TCD, 2, "tcd", AddressingMode::Implied, 1}, // 5B
{&CPU::JML, 4, "jml", AddressingMode::Implied, 4}, // 5C
{&CPU::EOR, 4, "eor", AddressingMode::AbsoluteIndexedByX, 3}, // 5D
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 5E
@@ -524,7 +538,7 @@ namespace ComSquare::CPU
{&CPU::SEI, 2, "sei", AddressingMode::Implied, 1}, // 78
{&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByY, 2}, // 79
{&CPU::PLY, 4, "ply", AddressingMode::Implied, 1}, // 7A
- {&CPU::BRK, 7, "tdc #-#", AddressingMode::Implied, 2}, // 7B
+ {&CPU::TDC, 2, "tdc", AddressingMode::Implied, 1}, // 7B
{&CPU::JMP, 6, "jmp", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // 7C
{&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByX, 3}, // 7D
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 7E
@@ -539,7 +553,7 @@ namespace ComSquare::CPU
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectLong, 2}, // 87
{&CPU::DEY, 2, "dey", AddressingMode::Implied, 1}, // 88
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 89
- {&CPU::BRK, 7, "txa #-#", AddressingMode::Implied, 2}, // 8A
+ {&CPU::TXA, 2, "txa", AddressingMode::Implied, 2}, // 8A
{&CPU::PHB, 3, "phb", AddressingMode::Implied, 1}, // 8B
{&CPU::STY, 4, "sty", AddressingMode::Absolute, 3}, // 8C
{&CPU::STA, 4, "sta", AddressingMode::Absolute, 3}, // 8D
@@ -553,7 +567,7 @@ namespace ComSquare::CPU
{&CPU::STA, 4, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 95
{&CPU::STX, 4, "stx", AddressingMode::DirectPageIndexedByY, 2}, // 96
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 97
- {&CPU::BRK, 7, "tya #-#", AddressingMode::Implied, 2}, // 98
+ {&CPU::TYA, 2, "tya", AddressingMode::Implied, 1}, // 98
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByY, 3}, // 99
{&CPU::TXS, 2, "txs", AddressingMode::Implied, 1}, // 9A
{&CPU::BRK, 7, "txy #-#", AddressingMode::Implied, 2}, // 9B
@@ -587,7 +601,7 @@ namespace ComSquare::CPU
{&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // B7
{&CPU::CLV, 7, "clv", AddressingMode::Implied, 1}, // B8
{&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByY, 3}, // B9
- {&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // BA
+ {&CPU::TSX, 2, "tsx", AddressingMode::Implied, 1}, // BA
{&CPU::BRK, 7, "tyx #-#", AddressingMode::Implied, 2}, // BB
{&CPU::LDY, 4, "ldy", AddressingMode::AbsoluteIndexedByX, 3}, // BC
{&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByX, 3}, // BD
diff --git a/sources/CPU/Instructions/TransferRegisters.cpp b/sources/CPU/Instructions/TransferRegisters.cpp
index 4905071..6135ce3 100644
--- a/sources/CPU/Instructions/TransferRegisters.cpp
+++ b/sources/CPU/Instructions/TransferRegisters.cpp
@@ -48,4 +48,80 @@ namespace ComSquare::CPU
}
return 0;
}
+
+ int CPU::TCD(uint24_t, AddressingMode)
+ {
+ this->_registers.d = this->_registers.a;
+ this->_registers.p.n = this->_registers.d & 0x8000u;
+ this->_registers.p.z = this->_registers.d == 0;
+ return 0;
+ }
+
+ int CPU::TCS(uint24_t, AddressingMode)
+ {
+ this->_registers.s = this->_registers.a;
+ if (this->_isEmulationMode)
+ this->_registers.sh = 1;
+ return 0;
+ }
+
+ int CPU::TDC(uint24_t, AddressingMode)
+ {
+ this->_registers.a = this->_registers.d;
+ this->_registers.p.n = this->_registers.a & 0x8000u;
+ this->_registers.p.z = this->_registers.a == 0;
+ return 0;
+ }
+
+ int CPU::TSC(uint24_t, AddressingMode)
+ {
+ this->_registers.a = this->_registers.s;
+ this->_registers.p.n = this->_registers.a & 0x8000u;
+ this->_registers.p.z = this->_registers.a == 0;
+ return 0;
+ }
+
+ int CPU::TSX(uint24_t, AddressingMode)
+ {
+ unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u;
+
+ this->_registers.x = this->_registers.s;
+ if (this->_registers.p.x_b)
+ this->_registers.xh = 0;
+ this->_registers.p.n = this->_registers.x & negativeFlag;
+ this->_registers.p.z = this->_registers.x == 0;
+ return 0;
+ }
+
+ int CPU::TXA(uint24_t, AddressingMode)
+ {
+ unsigned negativeFlag = this->_registers.p.m ? 0x80u : 0x8000u;
+
+ if (this->_registers.p.m)
+ this->_registers.al = this->_registers.xl;
+ else {
+ this->_registers.a = this->_registers.x;
+ if (this->_registers.p.x_b)
+ this->_registers.ah = 0;
+ }
+ this->_registers.p.n = this->_registers.a & negativeFlag;
+ this->_registers.p.z = this->_registers.a == 0;
+ return 0;
+ }
+
+ int CPU::TYA(uint24_t, AddressingMode)
+ {
+ unsigned negativeFlag = this->_registers.p.m ? 0x80u : 0x8000u;
+
+ if (this->_registers.p.m)
+ this->_registers.al = this->_registers.yl;
+ else {
+ this->_registers.a = this->_registers.y;
+ if (this->_registers.p.x_b)
+ this->_registers.ah = 0;
+ }
+ this->_registers.p.n = this->_registers.a & negativeFlag;
+ this->_registers.p.z = this->_registers.a == 0;
+ return 0;
+ }
}
\ No newline at end of file
diff --git a/tests/CPU/TransferRegisters.cpp b/tests/CPU/TransferRegisters.cpp
index c840e2a..07cabcc 100644
--- a/tests/CPU/TransferRegisters.cpp
+++ b/tests/CPU/TransferRegisters.cpp
@@ -144,4 +144,243 @@ Test(TXS, 8bitsIndex)
cr_assert_eq(snes.cpu->_registers.s, 0x00CD, "The stack pointer should be 0x00CD but it was %x", snes.cpu->_registers.s);
cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
-}
\ No newline at end of file
+}
+
+Test(TCD, emulationMode)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.d = 0x5656;
+ snes.cpu->_registers.a = 0xABCD;
+ snes.cpu->TCD(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.d, 0xABCD, "The direct page should be 0xABCD but it was %x", snes.cpu->_registers.d);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TCD, zero)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.d = 0x5656;
+ snes.cpu->_registers.a = 0x0;
+ snes.cpu->TCD(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.d, 0, "The direct page should be 0x0 but it was %x", snes.cpu->_registers.d);
+ cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
+}
+
+Test(TCS, emulationMode)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = false;
+ snes.cpu->_registers.s = 0x0156;
+ snes.cpu->_registers.a = 0xABCD;
+ snes.cpu->TCS(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.s, 0x01CD, "The stack pointer should be 0x01CD but it was %x", snes.cpu->_registers.s);
+}
+
+Test(TCS, native)
+{
+ Init()
+ snes.cpu->_isEmulationMode = false;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.s = 0x0156;
+ snes.cpu->_registers.a = 0xABCD;
+ snes.cpu->TCS(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.s, 0xABCD, "The stack pointer should be 0xABCD but it was %x", snes.cpu->_registers.s);
+}
+
+Test(TDC, emulationMode)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.d = 0xABCD;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TDC(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0xABCD, "The accumulator should be 0xABCD but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TDC, zero)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.d = 0x0;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TDC(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator should be 0x0 but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
+}
+
+Test(TSC, emulationMode)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.s = 0xABCD;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TSC(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0xABCD, "The accumulator should be 0xABCD but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TSC, zero)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.s = 0x0;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TSC(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0, "The accumulator should be 0x0 but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.");
+}
+
+Test(TSX, emulationMode)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.x_b = true;
+ snes.cpu->_registers.s = 0xABCD;
+ snes.cpu->_registers.x = 0x5656;
+ snes.cpu->TSX(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.x, 0x00CD, "The x index should be 0x00CD but it was %x", snes.cpu->_registers.x);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TSX, native)
+{
+ Init()
+ snes.cpu->_isEmulationMode = false;
+ snes.cpu->_registers.p.x_b = false;
+ snes.cpu->_registers.s = 0x8F00;
+ snes.cpu->_registers.x = 0x5656;
+ snes.cpu->TSX(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.x, 0x8F00, "The x index should be 0x8F00 but it was %x", snes.cpu->_registers.x);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TXA, double8bits)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.p.x_b = true;
+ snes.cpu->_registers.x = 0xABCD;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TXA, index8bits)
+{
+ Init()
+ snes.cpu->_isEmulationMode = false;
+ snes.cpu->_registers.p.m = false;
+ snes.cpu->_registers.p.x_b = true;
+ snes.cpu->_registers.x = 0x0BCD;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0x00CD, "The accumulator should be 0x00CD but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TXA, accumulator8bits)
+{
+ Init()
+ snes.cpu->_isEmulationMode = false;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.p.x_b = false;
+ snes.cpu->_registers.x = 0x0BCD;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TXA, double16bits)
+{
+ Init()
+ snes.cpu->_isEmulationMode = false;
+ snes.cpu->_registers.p.m = false;
+ snes.cpu->_registers.p.x_b = false;
+ snes.cpu->_registers.x = 0xAB0D;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TXA(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0xAB0D, "The accumulator should be 0xAB0D but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+
+Test(TYA, double8bits)
+{
+ Init()
+ snes.cpu->_isEmulationMode = true;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.p.x_b = true;
+ snes.cpu->_registers.y = 0xABCD;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TYA, index8bits)
+{
+ Init()
+ snes.cpu->_isEmulationMode = false;
+ snes.cpu->_registers.p.m = false;
+ snes.cpu->_registers.p.x_b = true;
+ snes.cpu->_registers.y = 0x0BCD;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0x00CD, "The accumulator should be 0x00CD but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TYA, accumulator8bits)
+{
+ Init()
+ snes.cpu->_isEmulationMode = false;
+ snes.cpu->_registers.p.m = true;
+ snes.cpu->_registers.p.x_b = false;
+ snes.cpu->_registers.y = 0x0BCD;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0x56CD, "The accumulator should be 0x56CD but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}
+
+Test(TYA, double16bits)
+{
+ Init()
+ snes.cpu->_isEmulationMode = false;
+ snes.cpu->_registers.p.m = false;
+ snes.cpu->_registers.p.x_b = false;
+ snes.cpu->_registers.y = 0xAB0D;
+ snes.cpu->_registers.a = 0x5656;
+ snes.cpu->TYA(0x0, ComSquare::CPU::AddressingMode::Implied);
+ cr_assert_eq(snes.cpu->_registers.a, 0xAB0D, "The accumulator should be 0xAB0D but it was %x", snes.cpu->_registers.a);
+ cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.");
+ cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set.");
+}