From fc82e99d9f6a73815914be9930dcf6d173203da8 Mon Sep 17 00:00:00 2001 From: PalindromicBreadLoaf Date: Thu, 24 Jul 2025 08:24:41 -0400 Subject: [PATCH] Implement ROR/ROL Instructions --- src/cpu.cpp | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cpu.h | 18 ++++ 2 files changed, 286 insertions(+) diff --git a/src/cpu.cpp b/src/cpu.cpp index f9e3970..0f1db53 100644 --- a/src/cpu.cpp +++ b/src/cpu.cpp @@ -303,6 +303,71 @@ void CPU::UpdateLSRFlags16(const uint16_t original_value, const uint16_t result) UpdateNZ16(result); } +// ROL/ROR helper methods +uint8_t CPU::ROL8(uint8_t value) { + const bool old_carry = (P & FLAG_C) != 0; + const bool new_carry = (value & 0x80) != 0; + + value = (value << 1) | (old_carry ? 1 : 0); + + if (new_carry) { + P |= FLAG_C; + } else { + P &= ~FLAG_C; + } + + UpdateNZ8(value); + return value; +} + +uint16_t CPU::ROL16(uint16_t value) { + const bool old_carry = (P & FLAG_C) != 0; + const bool new_carry = (value & 0x8000) != 0; + + value = (value << 1) | (old_carry ? 1 : 0); + + if (new_carry) { + P |= FLAG_C; + } else { + P &= ~FLAG_C; + } + + UpdateNZ16(value); + return value; +} + +uint8_t CPU::ROR8(uint8_t value) { + const bool old_carry = (P & FLAG_C) != 0; + const bool new_carry = (value & 0x01) != 0; + + value = (value >> 1) | (old_carry ? 0x80 : 0); + + if (new_carry) { + P |= FLAG_C; + } else { + P &= ~FLAG_C; + } + + UpdateNZ8(value); + return value; +} + +uint16_t CPU::ROR16(uint16_t value) { + const bool old_carry = (P & FLAG_C) != 0; + const bool new_carry = (value & 0x0001) != 0; + + value = (value >> 1) | (old_carry ? 0x8000 : 0); + + if (new_carry) { + P |= FLAG_C; + } else { + P &= ~FLAG_C; + } + + UpdateNZ16(value); + return value; +} + void CPU::ExecuteInstruction() { // TODO: Actual Opcode decoding switch (const uint8_t opcode = bus->Read(PC++)) { @@ -535,6 +600,20 @@ void CPU::ExecuteInstruction() { case 0x60: RTS(); break; // RTS case 0x6B: RTL(); break; // RTL + // ROL - Rotate Left + case 0x2A: ROL_Accumulator(); break; // ROL A + case 0x2E: ROL_Absolute(); break; // ROL $nnnn + case 0x3E: ROL_AbsoluteX(); break; // ROL $nnnn,X + case 0x26: ROL_DirectPage(); break; // ROL $nn + case 0x36: ROL_DirectPageX(); break; // ROL $nn,X + + // ROR - Rotate Right + case 0x6A: ROR_Accumulator(); break; // ROR A + case 0x6E: ROR_Absolute(); break; // ROR $nnnn + case 0x7E: ROR_AbsoluteX(); break; // ROR $nnnn,X + case 0x66: ROR_DirectPage(); break; // ROR $nn + case 0x76: ROR_DirectPageX(); break; // ROR $nn,X + //SDA - Store Accumulator case 0x8D: STA_Absolute(); break; // STA $nnnn case 0x9D: STA_AbsoluteX(); break; // STA $nnnn,X @@ -3831,4 +3910,193 @@ void CPU::MVP() { DB = dest_bank; cycles += 7; +} + +void CPU::ROL_Accumulator() { + if (P & FLAG_M) { + // 8-bit mode + uint8_t low_byte = A & 0xFF; + low_byte = ROL8(low_byte); + A = (A & 0xFF00) | low_byte; + } else { + // 16-bit mode + A = ROL16(A); + } + cycles += 2; +} + +void CPU::ROL_Absolute() { + const uint16_t address = ReadWord(PC); + PC += 2; + + if (P & FLAG_M) { + // 8-bit mode + uint8_t value = ReadByte((DB << 16) | address); + value = ROL8(value); + WriteByte((DB << 16) | address, value); + cycles += 6; + } else { + // 16-bit mode + uint16_t value = ReadWord((DB << 16) | address); + value = ROL16(value); + WriteWord((DB << 16) | address, value); + cycles += 7; + } +} + +void CPU::ROL_AbsoluteX() { + const uint16_t base_address = ReadWord(PC); + PC += 2; + const uint32_t address = (DB << 16) | (base_address + X); + + if (P & FLAG_M) { + // 8-bit mode + uint8_t value = ReadByte(address); + value = ROL8(value); + WriteByte(address, value); + cycles += 7; + } else { + // 16-bit mode + uint16_t value = ReadWord(address); + value = ROL16(value); + WriteWord(address, value); + cycles += 8; + } +} + +void CPU::ROL_DirectPage() { + const uint8_t offset = ReadByte(PC++); + const uint32_t address = D + offset; + + if (P & FLAG_M) { + // 8-bit mode + uint8_t value = ReadByte(address); + value = ROL8(value); + WriteByte(address, value); + cycles += 5; + } else { + // 16-bit mode + uint16_t value = ReadWord(address); + value = ROL16(value); + WriteWord(address, value); + cycles += 6; + } + + // Add extra cycle if D register low byte is non-zero + if (D & 0xFF) cycles++; +} + +void CPU::ROL_DirectPageX() { + const uint8_t offset = ReadByte(PC++); + const uint32_t address = D + offset + (P & FLAG_X ? (X & 0xFF) : X); + + if (P & FLAG_M) { + // 8-bit mode + uint8_t value = ReadByte(address); + value = ROL8(value); + WriteByte(address, value); + cycles += 6; + } else { + // 16-bit mode + uint16_t value = ReadWord(address); + value = ROL16(value); + WriteWord(address, value); + cycles += 7; + } + + if (D & 0xFF) cycles++; +} + +void CPU::ROR_Accumulator() { + if (P & FLAG_M) { + // 8-bit mode + uint8_t low_byte = A & 0xFF; + low_byte = ROR8(low_byte); + A = (A & 0xFF00) | low_byte; + } else { + // 16-bit mode + A = ROR16(A); + } + cycles += 2; +} + +void CPU::ROR_Absolute() { + const uint16_t address = ReadWord(PC); + PC += 2; + + if (P & FLAG_M) { + // 8-bit mode + uint8_t value = ReadByte((DB << 16) | address); + value = ROR8(value); + WriteByte((DB << 16) | address, value); + cycles += 6; + } else { + // 16-bit mode + uint16_t value = ReadWord((DB << 16) | address); + value = ROR16(value); + WriteWord((DB << 16) | address, value); + cycles += 7; + } +} + +void CPU::ROR_AbsoluteX() { + const uint16_t base_address = ReadWord(PC); + PC += 2; + const uint32_t address = (DB << 16) | (base_address + X); + + if (P & FLAG_M) { + // 8-bit mode + uint8_t value = ReadByte(address); + value = ROR8(value); + WriteByte(address, value); + cycles += 7; + } else { + // 16-bit mode + uint16_t value = ReadWord(address); + value = ROR16(value); + WriteWord(address, value); + cycles += 8; + } +} + +void CPU::ROR_DirectPage() { + const uint8_t offset = ReadByte(PC++); + const uint32_t address = D + offset; + + if (P & FLAG_M) { + // 8-bit mode + uint8_t value = ReadByte(address); + value = ROR8(value); + WriteByte(address, value); + cycles += 5; + } else { + // 16-bit mode + uint16_t value = ReadWord(address); + value = ROR16(value); + WriteWord(address, value); + cycles += 6; + } + + if (D & 0xFF) cycles++; +} + +void CPU::ROR_DirectPageX() { + const uint8_t offset = ReadByte(PC++); + const uint32_t address = D + offset + (P & FLAG_X ? (X & 0xFF) : X); + + if (P & FLAG_M) { + // 8-bit mode + uint8_t value = ReadByte(address); + value = ROR8(value); + WriteByte(address, value); + cycles += 6; + } else { + // 16-bit mode + uint16_t value = ReadWord(address); + value = ROR16(value); + WriteWord(address, value); + cycles += 7; + } + + if (D & 0xFF) cycles++; } \ No newline at end of file diff --git a/src/cpu.h b/src/cpu.h index efe6e53..411b715 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -78,6 +78,12 @@ class CPU { void UpdateLSRFlags8(uint8_t original_value, uint8_t result); void UpdateLSRFlags16(uint16_t original_value, uint16_t result); + //Helper Methods for Rotate Right/Left + uint8_t ROL8(uint8_t value); + uint16_t ROL16(uint16_t value); + uint8_t ROR8(uint8_t value); + uint16_t ROR16(uint16_t value); + public: explicit CPU(Bus* memory_bus) : bus(memory_bus) { Reset(); @@ -309,6 +315,18 @@ public: void MVN(); void MVP(); + + void ROL_Accumulator(); + void ROL_Absolute(); + void ROL_AbsoluteX(); + void ROL_DirectPage(); + void ROL_DirectPageX(); + + void ROR_Accumulator(); + void ROR_Absolute(); + void ROR_AbsoluteX(); + void ROR_DirectPage(); + void ROR_DirectPageX(); }; #endif //CPU_H