From abe445d202ed19f5d3a6ded9babb2b0af36c9df8 Mon Sep 17 00:00:00 2001 From: Anonymus Raccoon Date: Tue, 28 Apr 2020 23:12:43 +0200 Subject: [PATCH] Adding the BIT instruction --- sources/CPU/CPU.hpp | 12 ++--- sources/CPU/Instructions/BitsInstructions.cpp | 28 ++++++++++++ tests/CPU/testBits.cpp | 44 +++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 2d72b91..1bbe317 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -419,6 +419,8 @@ namespace ComSquare::CPU int TSB(uint24_t, AddressingMode); //! @brief Exchange the B and A Accumulators int XBA(uint24_t, AddressingMode); + //! @brief Test Memory Bits against Accumulator + int BIT(uint24_t, AddressingMode); //! @brief All the instructions of the CPU. //! @info Instructions are indexed by their opcode @@ -459,7 +461,7 @@ namespace ComSquare::CPU {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 21 {&CPU::JSL, 8, "jsl", AddressingMode::AbsoluteLong, 4}, // 22 {&CPU::AND, 4, "and", AddressingMode::StackRelative, 2}, // 23 - {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 24 + {&CPU::BIT, 3, "bit", AddressingMode::DirectPage, 2}, // 24 {&CPU::AND, 3, "and", AddressingMode::DirectPage, 2}, // 25 {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 26 {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectLong, 2}, // 27 @@ -467,7 +469,7 @@ namespace ComSquare::CPU {&CPU::AND, 2, "and", AddressingMode::ImmediateForA, 2}, // 29 {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2A {&CPU::PLD, 5, "pld", AddressingMode::Implied, 1}, // 2B - {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 2C + {&CPU::BIT, 4, "bit", AddressingMode::Absolute, 3}, // 2C {&CPU::AND, 4, "and", AddressingMode::Absolute, 3}, // 2D {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2E {&CPU::AND, 5, "and", AddressingMode::AbsoluteLong, 4}, // 2F @@ -475,7 +477,7 @@ namespace ComSquare::CPU {&CPU::AND, 5, "and", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 31 {&CPU::AND, 5, "and", AddressingMode::DirectPageIndirect, 2}, // 32 {&CPU::AND, 7, "and", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 33 - {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 34 + {&CPU::BIT, 4, "bit", AddressingMode::DirectPageIndexedByX, 2}, // 34 {&CPU::AND, 4, "and", AddressingMode::DirectPageIndexedByX, 2}, // 35 {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 36 {&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 37 @@ -483,7 +485,7 @@ namespace ComSquare::CPU {&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByY, 3}, // 39 {&CPU::DEC, 2, "dec", AddressingMode::Implied, 1}, // 3A {&CPU::TSC, 2, "tsc", AddressingMode::Implied, 1}, // 3B - {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C + {&CPU::BIT, 4, "bit", AddressingMode::AbsoluteIndexedByX, 3}, // 3C {&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByX, 3}, // 3D {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 3E {&CPU::AND, 5, "and", AddressingMode::AbsoluteIndexedByXLong, 4}, // 3F @@ -560,7 +562,7 @@ namespace ComSquare::CPU {&CPU::STX, 3, "stx", AddressingMode::DirectPage, 2}, // 86 {&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::BIT, 2, "bit", AddressingMode::ImmediateForA, 2}, // 89 {&CPU::TXA, 2, "txa", AddressingMode::Implied, 2}, // 8A {&CPU::PHB, 3, "phb", AddressingMode::Implied, 1}, // 8B {&CPU::STY, 4, "sty", AddressingMode::Absolute, 3}, // 8C diff --git a/sources/CPU/Instructions/BitsInstructions.cpp b/sources/CPU/Instructions/BitsInstructions.cpp index 737bdc9..41848f6 100644 --- a/sources/CPU/Instructions/BitsInstructions.cpp +++ b/sources/CPU/Instructions/BitsInstructions.cpp @@ -27,4 +27,32 @@ namespace ComSquare::CPU cycles += this->_registers.dl != 0; return cycles; } + + int CPU::BIT(uint24_t valueAddr, AddressingMode mode) + { + unsigned negativeMask = this->_registers.p.m ? 0x80u : 0x8000u; + unsigned value = this->_bus->read(valueAddr); + if (!this->_registers.p.m) + value += this->_bus->read(valueAddr + 1) << 8u; + + if (mode != ImmediateForA) { + this->_registers.p.n = value & negativeMask; + this->_registers.p.v = value & (negativeMask >> 1u); + } + this->_registers.p.z = (value & this->_registers.a) == 0; + + int cycles = !this->_registers.p.m; + switch (mode) { + case DirectPage: + case DirectPageIndexedByX: + cycles += this->_registers.dl != 0; + break; + case AbsoluteIndexedByX: + cycles += this->_hasIndexCrossedPageBoundary; + break; + default: + break; + } + return cycles; + } } \ No newline at end of file diff --git a/tests/CPU/testBits.cpp b/tests/CPU/testBits.cpp index 5c4b334..9e8e5dd 100644 --- a/tests/CPU/testBits.cpp +++ b/tests/CPU/testBits.cpp @@ -71,3 +71,47 @@ Test(TSB, nativeTest) cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); } +Test(BIT, immediate) +{ + Init() + snes.wram->_data[0] = 0xFF; + snes.wram->_data[1] = 0x00; + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x8008; + snes.cpu->_registers.p.v = false; + snes.cpu->_registers.p.n = false; + snes.cpu->BIT(0x0, ComSquare::CPU::AddressingMode::ImmediateForA); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); +} + +Test(BIT, immediateZero) +{ + Init() + snes.wram->_data[0] = 0x00; + snes.wram->_data[1] = 0xFF; + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x0008; + snes.cpu->_registers.p.v = true; + snes.cpu->_registers.p.n = true; + snes.cpu->BIT(0x0, ComSquare::CPU::AddressingMode::ImmediateForA); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.v, true, "The overflow flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); +} + +Test(BIT, other) +{ + Init() + snes.wram->_data[0] = 0x00; + snes.wram->_data[1] = 0xFF; + snes.cpu->_registers.p.m = false; + snes.cpu->_registers.a = 0x8008; + snes.cpu->_registers.p.v = false; + snes.cpu->_registers.p.n = false; + snes.cpu->BIT(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.v, true, "The overflow flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); +} \ No newline at end of file