From 522303c785f3482f5a81423b48c8be7e4a0df39c Mon Sep 17 00:00:00 2001 From: PalindromicBreadLoaf Date: Tue, 22 Jul 2025 08:15:02 -0400 Subject: [PATCH] Implement Store Instructions --- src/cpu.cpp | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/cpu.h | 28 +++++ 2 files changed, 310 insertions(+), 10 deletions(-) diff --git a/src/cpu.cpp b/src/cpu.cpp index 183541f..9029c91 100644 --- a/src/cpu.cpp +++ b/src/cpu.cpp @@ -22,33 +22,40 @@ void CPU::Step() { } // CPU Helper Methods -uint8_t CPU::ReadByte(uint32_t address) { +uint8_t CPU::ReadByte(const uint32_t address) { cycles++; return bus->Read(address); } -uint16_t CPU::ReadWord(uint32_t address) { +uint16_t CPU::ReadWord(const uint32_t address) { uint8_t low = ReadByte(address); uint8_t high = ReadByte(address + 1); return (high << 8) | low; } -void CPU::UpdateNZ8(uint8_t value) { +void CPU::UpdateNZ8(const uint8_t value) { P = (P & ~FLAG_N) | (value & 0x80); // Set N flag if bit 7 is set P = (P & ~FLAG_Z) | (value == 0 ? FLAG_Z : 0); // Set Z flag if value is zero } -void CPU::UpdateNZ16(uint16_t value) { +void CPU::UpdateNZ16(const uint16_t value) { P = (P & ~FLAG_N) | ((value & 0x8000) ? FLAG_N : 0); // Set N flag if bit 15 is set P = (P & ~FLAG_Z) | (value == 0 ? FLAG_Z : 0); // Set Z flag if value is zero } +// Helper method to write bytes/words to memory +void CPU::WriteByte(const uint32_t address, const uint8_t value) const { + bus->Write(address, value); +} + +void CPU::WriteWord(const uint32_t address, const uint16_t value) const { + bus->Write(address, value & 0xFF); // Low byte + bus->Write(address + 1, (value >> 8) & 0xFF); // High byte +} void CPU::ExecuteInstruction() { - uint8_t opcode = bus->Read(PC++); - // TODO: Actual Opcode decoding - switch (opcode) { + switch (const uint8_t opcode = bus->Read(PC++)) { case 0xEA: NOP(); break; // LDA - Load Accumulator @@ -71,19 +78,39 @@ void CPU::ExecuteInstruction() { case 0xA6: LDX_DirectPage(); break; // LDX $nn case 0xB6: LDX_DirectPageY(); break; // LDX $nn,Y - // LDY - Load Y Register + // LDY - Load Y Register case 0xA0: LDY_Immediate(); break; // LDY #$nn or LDY #$nnnn case 0xAC: LDY_Absolute(); break; // LDY $nnnn case 0xBC: LDY_AbsoluteX(); break; // LDY $nnnn,X case 0xA4: LDY_DirectPage(); break; // LDY $nn case 0xB4: LDY_DirectPageX(); break; // LDY $nn,X + //SDA - Store Accumulator + case 0x8D: STA_Absolute(); break; + case 0x9D: STA_AbsoluteX(); break; + case 0x99: STA_AbsoluteY(); break; + case 0x85: STA_DirectPage(); break; + case 0x95: STA_DirectPageX(); break; + case 0x92: STA_IndirectDirectPage(); break; + case 0x91: STA_IndirectDirectPageY(); break; + case 0x81: STA_DirectPageIndirectX(); break; + case 0x8F: STA_Long(); break; + case 0x9F: STA_LongX(); break; + + //SDX - Store X Register + case 0x8E: STX_Absolute(); break; + case 0x86: STX_DirectPage(); break; + case 0x96: STX_DirectPageY(); break; + + // SDY - Store Y Register + case 0x8C: STY_Absolute(); break; + case 0x84: STY_DirectPage(); break; + case 0x94: STY_DirectPageX(); break; + default: std::cout << "Unknown opcode: 0x" << std::hex << static_cast(opcode) << std::endl; break; } - - cycles++; } void CPU::NOP() { @@ -512,4 +539,249 @@ void CPU::LDY_DirectPageX() { // Extra cycle if D register is not page-aligned if (D & 0xFF) cycles++; +} + +//Store operations implementation +void CPU::STA_Absolute() { + uint32_t address = ReadWord(PC + 1) | (DB << 16); + PC += 3; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 4; + } else { // 16-bit mode + WriteWord(address, A); + cycles += 5; + } +} + +void CPU::STA_AbsoluteX() { + uint32_t base = ReadWord(PC + 1) | (DB << 16); + uint32_t address = base + X; + PC += 3; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 5; + } else { // 16-bit mode + WriteWord(address, A); + cycles += 6; + } +} + +void CPU::STA_AbsoluteY() { + uint32_t base = ReadWord(PC + 1) | (DB << 16); + uint32_t address = base + Y; + PC += 3; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 5; + } else { // 16-bit mode + WriteWord(address, A); + cycles += 6; + } +} + +void CPU::STA_DirectPage() { + uint8_t offset = ReadByte(PC + 1); + uint32_t address = (D + offset) & 0xFFFF; + PC += 2; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 3; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, A); + cycles += 4; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } +} + +void CPU::STA_DirectPageX() { + uint8_t offset = ReadByte(PC + 1); + uint32_t address = (D + offset + X) & 0xFFFF; + PC += 2; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 4; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, A); + cycles += 5; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } +} + +void CPU::STA_IndirectDirectPage() { + uint8_t offset = ReadByte(PC + 1); + uint32_t pointer = (D + offset) & 0xFFFF; + uint32_t address = ReadWord(pointer) | (DB << 16); + PC += 2; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 5; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, A); + cycles += 6; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } +} + +void CPU::STA_IndirectDirectPageY() { + uint8_t offset = ReadByte(PC + 1); + uint32_t pointer = (D + offset) & 0xFFFF; + uint32_t base = ReadWord(pointer) | (DB << 16); + uint32_t address = base + Y; + PC += 2; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 6; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, A); + cycles += 7; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } +} + +void CPU::STA_DirectPageIndirectX() { + uint8_t offset = ReadByte(PC + 1); + uint32_t pointer = (D + offset + X) & 0xFFFF; + uint32_t address = ReadWord(pointer) | (DB << 16); + PC += 2; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 6; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, A); + cycles += 7; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } +} + +void CPU::STA_Long() { + uint32_t address = ReadByte(PC + 1) | (ReadByte(PC + 2) << 8) | (ReadByte(PC + 3) << 16); + PC += 4; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 5; + } else { // 16-bit mode + WriteWord(address, A); + cycles += 6; + } +} + +void CPU::STA_LongX() { + uint32_t base = ReadByte(PC + 1) | (ReadByte(PC + 2) << 8) | (ReadByte(PC + 3) << 16); + uint32_t address = base + X; + PC += 4; + + if (P & FLAG_M) { // 8-bit mode + WriteByte(address, A & 0xFF); + cycles += 6; + } else { // 16-bit mode + WriteWord(address, A); + cycles += 7; + } +} + +// STX - Store X Register +void CPU::STX_Absolute() { + uint32_t address = ReadWord(PC + 1) | (DB << 16); + PC += 3; + + if (P & FLAG_X) { // 8-bit mode + WriteByte(address, X & 0xFF); + cycles += 4; + } else { // 16-bit mode + WriteWord(address, X); + cycles += 5; + } +} + +void CPU::STX_DirectPage() { + uint8_t offset = ReadByte(PC + 1); + uint32_t address = (D + offset) & 0xFFFF; + PC += 2; + + if (P & FLAG_X) { // 8-bit mode + WriteByte(address, X & 0xFF); + cycles += 3; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, X); + cycles += 4; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } +} + +void CPU::STX_DirectPageY() { + uint8_t offset = ReadByte(PC + 1); + uint32_t address = (D + offset + Y) & 0xFFFF; + PC += 2; + + if (P & FLAG_X) { // 8-bit mode + WriteByte(address, X & 0xFF); + cycles += 4; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, X); + cycles += 5; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } +} + +// STY - Store Y Register +void CPU::STY_Absolute() { + uint32_t address = ReadWord(PC + 1) | (DB << 16); + PC += 3; + + if (P & FLAG_X) { // 8-bit mode + WriteByte(address, Y & 0xFF); + cycles += 4; + } else { // 16-bit mode + WriteWord(address, Y); + cycles += 5; + } +} + +void CPU::STY_DirectPage() { + uint8_t offset = ReadByte(PC + 1); + uint32_t address = (D + offset) & 0xFFFF; + PC += 2; + + if (P & FLAG_X) { // 8-bit mode + WriteByte(address, Y & 0xFF); + cycles += 3; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, Y); + cycles += 4; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } +} + +void CPU::STY_DirectPageX() { + uint8_t offset = ReadByte(PC + 1); + uint32_t address = (D + offset + X) & 0xFFFF; + PC += 2; + + if (P & FLAG_X) { // 8-bit mode + WriteByte(address, Y & 0xFF); + cycles += 4; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } else { // 16-bit mode + WriteWord(address, Y); + cycles += 5; + if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 + } } \ No newline at end of file diff --git a/src/cpu.h b/src/cpu.h index b8633c2..0c7b347 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -53,6 +53,11 @@ public: void UpdateNZ8(uint8_t value); void UpdateNZ16(uint16_t value); + // Memory write helpers + void WriteByte(uint32_t address, uint8_t value) const; + void WriteWord(uint32_t address, uint16_t value) const; + + // Instruction implementations // TODO: Implement remaining instructions void JMP(); @@ -83,6 +88,29 @@ public: void LDY_DirectPage(); void LDY_DirectPageX(); + // STA - Store Accumulator operations + void STA_Absolute(); + void STA_AbsoluteX(); + void STA_AbsoluteY(); + void STA_DirectPage(); + void STA_DirectPageX(); + void STA_IndirectDirectPage(); + void STA_IndirectDirectPageY(); + void STA_DirectPageIndirectX(); + void STA_Long(); + void STA_LongX(); + + // STX - Store X Register operations + void STX_Absolute(); + void STX_DirectPage(); + void STX_DirectPageY(); + + // STY - Store Y Register operations + void STY_Absolute(); + void STY_DirectPage(); + void STY_DirectPageX(); + + void STA(); };