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