Adding the BIT instruction

This commit is contained in:
Anonymus Raccoon
2020-04-28 23:12:43 +02:00
parent 26ea447f24
commit abe445d202
3 changed files with 79 additions and 5 deletions
+7 -5
View File
@@ -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
@@ -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;
}
}
+44
View File
@@ -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.");
}