diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index b87704e..1c6be7d 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -417,6 +417,8 @@ namespace ComSquare::CPU int TYX(uint24_t, AddressingMode); //! @brief Test and Set Memory Bits Against Accumulator int TSB(uint24_t, AddressingMode); + //! @brief Test and Reset Memory Bits Against Accumulator + int TRB(uint24_t, AddressingMode); //! @brief Exchange the B and A Accumulators int XBA(uint24_t, AddressingMode); //! @brief Test Memory Bits against Accumulator @@ -453,7 +455,7 @@ namespace ComSquare::CPU {&CPU::ORA, 5, "ora", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 11 {&CPU::ORA, 5, "ora", AddressingMode::DirectPageIndirect, 2}, // 12 {&CPU::ORA, 7, "ora", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 13 - {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 14 + {&CPU::TRB, 5, "trb", AddressingMode::DirectPage, 2}, // 14 {&CPU::ORA, 4, "ora", AddressingMode::DirectPageIndexedByX, 2}, // 15 {&CPU::ASL, 6, "asl", AddressingMode::DirectPageIndexedByX, 2}, // 16 {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 17 @@ -461,7 +463,7 @@ namespace ComSquare::CPU {&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByY, 3}, // 19 {&CPU::INC, 2, "inc", AddressingMode::Implied, 1}, // 1A {&CPU::TCS, 2, "tcs", AddressingMode::Implied, 1}, // 1B - {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C + {&CPU::TRB, 6, "trb", AddressingMode::Absolute, 3}, // 1C {&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByX, 3}, // 1D {&CPU::ASL, 7, "asl", AddressingMode::AbsoluteIndexedByX, 3}, // 1E {&CPU::ORA, 5, "ora", AddressingMode::AbsoluteIndexedByXLong, 4}, // 1F diff --git a/sources/CPU/Instructions/BitsInstructions.cpp b/sources/CPU/Instructions/BitsInstructions.cpp index 81205b7..2332114 100644 --- a/sources/CPU/Instructions/BitsInstructions.cpp +++ b/sources/CPU/Instructions/BitsInstructions.cpp @@ -28,6 +28,27 @@ namespace ComSquare::CPU return cycles; } + int CPU::TRB(uint24_t valueAddr, AddressingMode mode) + { + uint16_t value = this->_bus->read(valueAddr); + if (!this->_registers.p.m) + value += this->_bus->read(valueAddr + 1) << 8u; + + uint16_t newValue = value & ~this->_registers.a; + this->_bus->write(valueAddr, newValue); + if (!this->_registers.p.m) + this->_bus->write(valueAddr + 1, newValue >> 8u); + + this->_registers.p.z = (value & this->_registers.a) == 0; + + int cycles = 0; + if (!this->_registers.p.m) + cycles += 2; + if (mode == DirectPage) + cycles += this->_registers.dl != 0; + return cycles; + } + int CPU::BIT(uint24_t valueAddr, AddressingMode mode) { unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; diff --git a/tests/CPU/testBits.cpp b/tests/CPU/testBits.cpp index b8ef723..a4bd5de 100644 --- a/tests/CPU/testBits.cpp +++ b/tests/CPU/testBits.cpp @@ -297,4 +297,39 @@ Test(ROR, accumulator) cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set."); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); +} + +Test(TRB, emulationTest) +{ + Init() + snes.wram->_data[0] = 0xFF; + snes.cpu->_registers.a = 0b00110111; + snes.cpu->_registers.p.m = true; + snes.cpu->TRB(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.wram->_data[0], 0b11001000, "The data in ram should be 0b11001000 but it was %x", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); +} + +Test(TRB, nativeTest) +{ + Init() + snes.wram->_data[0] = 0xF0; + snes.wram->_data[1] = 0x0F; + snes.cpu->_registers.a = 0x0F0F; + snes.cpu->_registers.p.m = false; + snes.cpu->TRB(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.wram->_data[0], 0xF0, "The first data in ram should be 0xF0 but it was %x", snes.wram->_data[0]); + cr_assert_eq(snes.wram->_data[1], 0x00, "The second data in ram should be 0x00 but it was %x", snes.wram->_data[1]); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); +} + +Test(TRB, zero) +{ + Init() + snes.wram->_data[0] = 0xFF; + snes.cpu->_registers.a = 0b0; + snes.cpu->_registers.p.m = true; + snes.cpu->TRB(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.wram->_data[0], 0xFF, "The data in ram should be 0xFF but it was %x", snes.wram->_data[0]); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); } \ No newline at end of file