From 34d30ed47cc93f86bfedfa3c0d382a23d406fed3 Mon Sep 17 00:00:00 2001 From: PalindromicBreadLoaf Date: Wed, 23 Jul 2025 11:45:40 -0400 Subject: [PATCH] Implement BIT Instructions --- src/cpu.cpp | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cpu.h | 12 ++++ 2 files changed, 167 insertions(+) diff --git a/src/cpu.cpp b/src/cpu.cpp index dd91c6a..1d1f282 100644 --- a/src/cpu.cpp +++ b/src/cpu.cpp @@ -220,6 +220,69 @@ void CPU::UpdateASLFlags16(const uint16_t original_value, const uint16_t result) UpdateNZ16(result); } +// Helper function to update flags after BIT operation (non-immediate modes) +void CPU::UpdateBITFlags8(uint8_t memory_value, uint8_t acc_value) { + // Z flag: set if (A & memory) == 0 + if (const uint8_t result = acc_value & memory_value; result == 0) { + P |= FLAG_Z; + } else { + P &= ~FLAG_Z; + } + + // N flag: copy bit 7 of memory + if (memory_value & 0x80) { + P |= FLAG_N; + } else { + P &= ~FLAG_N; + } + + // V flag: copy bit 6 of memory + if (memory_value & 0x40) { + P |= FLAG_V; + } else { + P &= ~FLAG_V; + } +} + +void CPU::UpdateBITFlags16(const uint16_t memory_value, const uint16_t acc_value) { + if (const uint16_t result = acc_value & memory_value; result == 0) { + P |= FLAG_Z; + } else { + P &= ~FLAG_Z; + } + + // N flag: copy bit 15 of memory + if (memory_value & 0x8000) { + P |= FLAG_N; + } else { + P &= ~FLAG_N; + } + + // V flag: copy bit 14 of memory + if (memory_value & 0x4000) { + P |= FLAG_V; + } else { + P &= ~FLAG_V; + } +} + +// Helper function for immediate mode BIT +void CPU::UpdateBITImmediateFlags8(const uint8_t memory_value, const uint8_t acc_value) { + if (const uint8_t result = acc_value & memory_value; result == 0) { + P |= FLAG_Z; + } else { + P &= ~FLAG_Z; + } +} + +void CPU::UpdateBITImmediateFlags16(const uint16_t memory_value, const uint16_t acc_value) { + if (const uint16_t result = acc_value & memory_value; result == 0) { + P |= FLAG_Z; + } else { + P &= ~FLAG_Z; + } +} + void CPU::ExecuteInstruction() { // TODO: Actual Opcode decoding switch (const uint8_t opcode = bus->Read(PC++)) { @@ -272,6 +335,13 @@ void CPU::ExecuteInstruction() { case 0x30: BMI_Relative(); break; // BMI $nn case 0x10: BPL_Relative(); break; // BPL $nn + // BIT - Test Bits Instructions + case 0x89: BIT_Immediate(); break; // BIT #$nn or #$nnnn + case 0x2C: BIT_Absolute(); break; // BIT $nnnn + case 0x3C: BIT_AbsoluteX(); break; // BIT $nnnn,X + case 0x24: BIT_DirectPage(); break; // BIT $nn + case 0x34: BIT_DirectPageX(); break; // BIT $nn,X + // CMP - Compare Accumulator case 0xC9: CMP_Immediate(); break; // CMP #$nn or #$nnnn case 0xCD: CMP_Absolute(); break; // CMP $nnnn @@ -2570,4 +2640,89 @@ void CPU::ASL_DirectPageX() { cycles += 8; if (D & 0xFF) cycles++; } +} + +void CPU::BIT_Immediate() { + if (P & FLAG_M) { // 8-bit mode + const uint8_t operand = ReadByte(PC++); + UpdateBITImmediateFlags8(operand, A & 0xFF); + cycles += 2; + } else { // 16-bit mode + const uint16_t operand = ReadWord(PC); + PC += 2; + UpdateBITImmediateFlags16(operand, A); + cycles += 3; + } +} + +void CPU::BIT_Absolute() { + const uint16_t address = ReadWord(PC); + PC += 2; + const uint32_t full_address = (DB << 16) | address; + + if (P & FLAG_M) { // 8-bit mode + const uint8_t operand = ReadByte(full_address); + UpdateBITFlags8(operand, A & 0xFF); + cycles += 4; + } else { // 16-bit mode + const uint16_t operand = ReadWord(full_address); + UpdateBITFlags16(operand, A); + cycles += 5; + } +} + +void CPU::BIT_AbsoluteX() { + const uint16_t base_address = ReadWord(PC); + PC += 2; + const uint32_t full_address = (DB << 16) | (base_address + X); + + if (P & FLAG_M) { // 8-bit mode + const uint8_t operand = ReadByte(full_address); + UpdateBITFlags8(operand, A & 0xFF); + cycles += 4; + if ((base_address & 0xFF00) != ((base_address + X) & 0xFF00)) { + cycles++; + } + } else { // 16-bit mode + const uint16_t operand = ReadWord(full_address); + UpdateBITFlags16(operand, A); + cycles += 5; + if ((base_address & 0xFF00) != ((base_address + X) & 0xFF00)) { + cycles++; + } + } +} + +void CPU::BIT_DirectPage() { + const uint8_t offset = ReadByte(PC++); + const uint32_t address = D + offset; + + if (P & FLAG_M) { // 8-bit mode + const uint8_t operand = ReadByte(address); + UpdateBITFlags8(operand, A & 0xFF); + cycles += 3; + if (D & 0xFF) cycles++; + } else { // 16-bit mode + const uint16_t operand = ReadWord(address); + UpdateBITFlags16(operand, A); + cycles += 4; + if (D & 0xFF) cycles++; + } +} + +void CPU::BIT_DirectPageX() { + const uint8_t offset = ReadByte(PC++); + const uint32_t address = D + offset + X; + + if (P & FLAG_M) { // 8-bit mode + const uint8_t operand = ReadByte(address); + UpdateBITFlags8(operand, A & 0xFF); + cycles += 4; + if (D & 0xFF) cycles++; + } else { // 16-bit mode + const uint16_t operand = ReadWord(address); + UpdateBITFlags16(operand, A); + cycles += 5; + if (D & 0xFF) cycles++; + } } \ No newline at end of file diff --git a/src/cpu.h b/src/cpu.h index cbb2729..4655073 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -79,6 +79,12 @@ public: void UpdateASLFlags8(uint8_t original_value, uint8_t result); void UpdateASLFlags16(uint16_t original_value, uint16_t result); + // Helper methods for BIT + void UpdateBITFlags8(uint8_t memory_value, uint8_t acc_value); + void UpdateBITFlags16(uint16_t memory_value, uint16_t acc_value); + void UpdateBITImmediateFlags8(uint8_t memory_value, uint8_t acc_value); + void UpdateBITImmediateFlags16(uint16_t memory_value, uint16_t acc_value); + // Instruction implementations // TODO: Implement remaining instructions void CMP_Immediate(); @@ -232,6 +238,12 @@ public: void ASL_AbsoluteX(); void ASL_DirectPage(); void ASL_DirectPageX(); + + void BIT_Immediate(); + void BIT_Absolute(); + void BIT_AbsoluteX(); + void BIT_DirectPage(); + void BIT_DirectPageX(); }; #endif //CPU_H