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