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