Implement Increment and Decrement Instructions

This commit is contained in:
2025-07-22 08:31:44 -04:00
parent 3a28cf09ea
commit 605b3b7c82
2 changed files with 311 additions and 36 deletions

View File

@@ -56,7 +56,30 @@ void CPU::WriteWord(const uint32_t address, const uint16_t value) const {
void CPU::ExecuteInstruction() { void CPU::ExecuteInstruction() {
// TODO: Actual Opcode decoding // TODO: Actual Opcode decoding
switch (const uint8_t opcode = bus->Read(PC++)) { switch (const uint8_t opcode = bus->Read(PC++)) {
case 0xEA: NOP(); break; // DEC - Decrement Memory
case 0x3A: DEC_Accumulator(); break; // DEC A
case 0xCE: DEC_Absolute(); break; // DEC $nnnn
case 0xDE: DEC_AbsoluteX(); break; // DEC $nnnn,X
case 0xC6: DEC_DirectPage(); break; // DEC $nn
case 0xD6: DEC_DirectPageX(); break; // DEC $nn,X
// Single Register Decrement
case 0xCA: DEX(); break; // DEX - Decrement X Register
case 0x88: DEY(); break; // DEY - Decrement Y Register
// INC - Increment Memory
case 0x1A: INC_Accumulator(); break; // INC A
case 0xEE: INC_Absolute(); break; // INC $nnnn
case 0xFE: INC_AbsoluteX(); break; // INC $nnnn,X
case 0xE6: INC_DirectPage(); break; // INC $nn
case 0xF6: INC_DirectPageX(); break; // INC $nn,X
// Single Register Increment
case 0xE8: INX(); break; // INX - Increment X Register
case 0xC8: INY(); break; // INY - Increment Y Register
// No Operation
case 0xEA: NOP(); break; //NOP
// LDA - Load Accumulator // LDA - Load Accumulator
case 0xA9: LDA_Immediate(); break; // LDA #$nn or #$nnnn case 0xA9: LDA_Immediate(); break; // LDA #$nn or #$nnnn
@@ -71,7 +94,7 @@ void CPU::ExecuteInstruction() {
case 0xAF: LDA_Long(); break; // LDA $nnnnnn case 0xAF: LDA_Long(); break; // LDA $nnnnnn
case 0xBF: LDA_LongX(); break; // LDA $nnnnnn,X case 0xBF: LDA_LongX(); break; // LDA $nnnnnn,X
// LDX - Load X Register // LDX - Load X Register
case 0xA2: LDX_Immediate(); break; // LDX #$nn or LDX #$nnnn case 0xA2: LDX_Immediate(); break; // LDX #$nn or LDX #$nnnn
case 0xAE: LDX_Absolute(); break; // LDX $nnnn case 0xAE: LDX_Absolute(); break; // LDX $nnnn
case 0xBE: LDX_AbsoluteY(); break; // LDX $nnnn,Y case 0xBE: LDX_AbsoluteY(); break; // LDX $nnnn,Y
@@ -543,7 +566,7 @@ void CPU::LDY_DirectPageX() {
//Store operations implementation //Store operations implementation
void CPU::STA_Absolute() { void CPU::STA_Absolute() {
uint32_t address = ReadWord(PC + 1) | (DB << 16); const uint32_t address = ReadWord(PC + 1) | (DB << 16);
PC += 3; PC += 3;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -556,8 +579,8 @@ void CPU::STA_Absolute() {
} }
void CPU::STA_AbsoluteX() { void CPU::STA_AbsoluteX() {
uint32_t base = ReadWord(PC + 1) | (DB << 16); const uint32_t base = ReadWord(PC + 1) | (DB << 16);
uint32_t address = base + X; const uint32_t address = base + X;
PC += 3; PC += 3;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -570,8 +593,8 @@ void CPU::STA_AbsoluteX() {
} }
void CPU::STA_AbsoluteY() { void CPU::STA_AbsoluteY() {
uint32_t base = ReadWord(PC + 1) | (DB << 16); const uint32_t base = ReadWord(PC + 1) | (DB << 16);
uint32_t address = base + Y; const uint32_t address = base + Y;
PC += 3; PC += 3;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -584,8 +607,8 @@ void CPU::STA_AbsoluteY() {
} }
void CPU::STA_DirectPage() { void CPU::STA_DirectPage() {
uint8_t offset = ReadByte(PC + 1); const uint8_t offset = ReadByte(PC + 1);
uint32_t address = (D + offset) & 0xFFFF; const uint32_t address = (D + offset) & 0xFFFF;
PC += 2; PC += 2;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -600,8 +623,8 @@ void CPU::STA_DirectPage() {
} }
void CPU::STA_DirectPageX() { void CPU::STA_DirectPageX() {
uint8_t offset = ReadByte(PC + 1); const uint8_t offset = ReadByte(PC + 1);
uint32_t address = (D + offset + X) & 0xFFFF; const uint32_t address = (D + offset + X) & 0xFFFF;
PC += 2; PC += 2;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -616,9 +639,9 @@ void CPU::STA_DirectPageX() {
} }
void CPU::STA_IndirectDirectPage() { void CPU::STA_IndirectDirectPage() {
uint8_t offset = ReadByte(PC + 1); const uint8_t offset = ReadByte(PC + 1);
uint32_t pointer = (D + offset) & 0xFFFF; const uint32_t pointer = (D + offset) & 0xFFFF;
uint32_t address = ReadWord(pointer) | (DB << 16); const uint32_t address = ReadWord(pointer) | (DB << 16);
PC += 2; PC += 2;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -633,10 +656,10 @@ void CPU::STA_IndirectDirectPage() {
} }
void CPU::STA_IndirectDirectPageY() { void CPU::STA_IndirectDirectPageY() {
uint8_t offset = ReadByte(PC + 1); const uint8_t offset = ReadByte(PC + 1);
uint32_t pointer = (D + offset) & 0xFFFF; const uint32_t pointer = (D + offset) & 0xFFFF;
uint32_t base = ReadWord(pointer) | (DB << 16); const uint32_t base = ReadWord(pointer) | (DB << 16);
uint32_t address = base + Y; const uint32_t address = base + Y;
PC += 2; PC += 2;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -651,9 +674,9 @@ void CPU::STA_IndirectDirectPageY() {
} }
void CPU::STA_DirectPageIndirectX() { void CPU::STA_DirectPageIndirectX() {
uint8_t offset = ReadByte(PC + 1); const uint8_t offset = ReadByte(PC + 1);
uint32_t pointer = (D + offset + X) & 0xFFFF; const uint32_t pointer = (D + offset + X) & 0xFFFF;
uint32_t address = ReadWord(pointer) | (DB << 16); const uint32_t address = ReadWord(pointer) | (DB << 16);
PC += 2; PC += 2;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -668,7 +691,7 @@ void CPU::STA_DirectPageIndirectX() {
} }
void CPU::STA_Long() { void CPU::STA_Long() {
uint32_t address = ReadByte(PC + 1) | (ReadByte(PC + 2) << 8) | (ReadByte(PC + 3) << 16); const uint32_t address = ReadByte(PC + 1) | (ReadByte(PC + 2) << 8) | (ReadByte(PC + 3) << 16);
PC += 4; PC += 4;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -681,8 +704,8 @@ void CPU::STA_Long() {
} }
void CPU::STA_LongX() { void CPU::STA_LongX() {
uint32_t base = ReadByte(PC + 1) | (ReadByte(PC + 2) << 8) | (ReadByte(PC + 3) << 16); const uint32_t base = ReadByte(PC + 1) | (ReadByte(PC + 2) << 8) | (ReadByte(PC + 3) << 16);
uint32_t address = base + X; const uint32_t address = base + X;
PC += 4; PC += 4;
if (P & FLAG_M) { // 8-bit mode if (P & FLAG_M) { // 8-bit mode
@@ -696,7 +719,7 @@ void CPU::STA_LongX() {
// STX - Store X Register // STX - Store X Register
void CPU::STX_Absolute() { void CPU::STX_Absolute() {
uint32_t address = ReadWord(PC + 1) | (DB << 16); const uint32_t address = ReadWord(PC + 1) | (DB << 16);
PC += 3; PC += 3;
if (P & FLAG_X) { // 8-bit mode if (P & FLAG_X) { // 8-bit mode
@@ -709,8 +732,8 @@ void CPU::STX_Absolute() {
} }
void CPU::STX_DirectPage() { void CPU::STX_DirectPage() {
uint8_t offset = ReadByte(PC + 1); const uint8_t offset = ReadByte(PC + 1);
uint32_t address = (D + offset) & 0xFFFF; const uint32_t address = (D + offset) & 0xFFFF;
PC += 2; PC += 2;
if (P & FLAG_X) { // 8-bit mode if (P & FLAG_X) { // 8-bit mode
@@ -755,8 +778,8 @@ void CPU::STY_Absolute() {
} }
void CPU::STY_DirectPage() { void CPU::STY_DirectPage() {
uint8_t offset = ReadByte(PC + 1); const uint8_t offset = ReadByte(PC + 1);
uint32_t address = (D + offset) & 0xFFFF; const uint32_t address = (D + offset) & 0xFFFF;
PC += 2; PC += 2;
if (P & FLAG_X) { // 8-bit mode if (P & FLAG_X) { // 8-bit mode
@@ -771,8 +794,8 @@ void CPU::STY_DirectPage() {
} }
void CPU::STY_DirectPageX() { void CPU::STY_DirectPageX() {
uint8_t offset = ReadByte(PC + 1); const uint8_t offset = ReadByte(PC + 1);
uint32_t address = (D + offset + X) & 0xFFFF; const uint32_t address = (D + offset + X) & 0xFFFF;
PC += 2; PC += 2;
if (P & FLAG_X) { // 8-bit mode if (P & FLAG_X) { // 8-bit mode
@@ -784,4 +807,245 @@ void CPU::STY_DirectPageX() {
cycles += 5; cycles += 5;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0 if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
} }
}
// INC - Increment Memory
// Important to note: PC doesn't increment in accumulator mode I think
void CPU::INC_Accumulator() {
if (P & FLAG_M) { // 8-bit mode
A = (A & 0xFF00) | ((A + 1) & 0xFF);
UpdateNZ8(A & 0xFF);
cycles += 2;
} else { // 16-bit mode
A = (A + 1) & 0xFFFF;
UpdateNZ16(A);
cycles += 2;
}
}
void CPU::INC_Absolute() {
const uint32_t address = ReadWord(PC + 1) | (DB << 16);
PC += 3;
if (P & FLAG_M) { // 8-bit mode
uint8_t value = ReadByte(address);
value = (value + 1) & 0xFF;
WriteByte(address, value);
UpdateNZ8(value);
cycles += 6;
} else { // 16-bit mode
uint16_t value = ReadWord(address);
value = (value + 1) & 0xFFFF;
WriteWord(address, value);
UpdateNZ16(value);
cycles += 8;
}
}
void CPU::INC_AbsoluteX() {
const uint32_t base = ReadWord(PC + 1) | (DB << 16);
const uint32_t address = base + X;
PC += 3;
if (P & FLAG_M) { // 8-bit mode
uint8_t value = ReadByte(address);
value = (value + 1) & 0xFF;
WriteByte(address, value);
UpdateNZ8(value);
cycles += 7;
} else { // 16-bit mode
uint16_t value = ReadWord(address);
value = (value + 1) & 0xFFFF;
WriteWord(address, value);
UpdateNZ16(value);
cycles += 9;
}
}
void CPU::INC_DirectPage() {
const uint8_t offset = ReadByte(PC + 1);
const uint32_t address = (D + offset) & 0xFFFF;
PC += 2;
if (P & FLAG_M) { // 8-bit mode
uint8_t value = ReadByte(address);
value = (value + 1) & 0xFF;
WriteByte(address, value);
UpdateNZ8(value);
cycles += 5;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
} else { // 16-bit mode
uint16_t value = ReadWord(address);
value = (value + 1) & 0xFFFF;
WriteWord(address, value);
UpdateNZ16(value);
cycles += 7;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
}
}
void CPU::INC_DirectPageX() {
const uint8_t offset = ReadByte(PC + 1);
const uint32_t address = (D + offset + X) & 0xFFFF;
PC += 2;
if (P & FLAG_M) { // 8-bit mode
uint8_t value = ReadByte(address);
value = (value + 1) & 0xFF;
WriteByte(address, value);
UpdateNZ8(value);
cycles += 6;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
} else { // 16-bit mode
uint16_t value = ReadWord(address);
value = (value + 1) & 0xFFFF;
WriteWord(address, value);
UpdateNZ16(value);
cycles += 8;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
}
}
// DEC - Decrement Memory
void CPU::DEC_Accumulator() {
if (P & FLAG_M) { // 8-bit mode
A = (A & 0xFF00) | ((A - 1) & 0xFF);
UpdateNZ8(A & 0xFF);
cycles += 2;
} else { // 16-bit mode
A = (A - 1) & 0xFFFF;
UpdateNZ16(A);
cycles += 2;
}
}
void CPU::DEC_Absolute() {
const uint32_t address = ReadWord(PC + 1) | (DB << 16);
PC += 3;
if (P & FLAG_M) { // 8-bit mode
uint8_t value = ReadByte(address);
value = (value - 1) & 0xFF;
WriteByte(address, value);
UpdateNZ8(value);
cycles += 6;
} else { // 16-bit mode
uint16_t value = ReadWord(address);
value = (value - 1) & 0xFFFF;
WriteWord(address, value);
UpdateNZ16(value);
cycles += 8;
}
}
void CPU::DEC_AbsoluteX() {
const uint32_t base = ReadWord(PC + 1) | (DB << 16);
const uint32_t address = base + X;
PC += 3;
if (P & FLAG_M) { // 8-bit mode
uint8_t value = ReadByte(address);
value = (value - 1) & 0xFF;
WriteByte(address, value);
UpdateNZ8(value);
cycles += 7;
} else { // 16-bit mode
uint16_t value = ReadWord(address);
value = (value - 1) & 0xFFFF;
WriteWord(address, value);
UpdateNZ16(value);
cycles += 9;
}
}
void CPU::DEC_DirectPage() {
const uint8_t offset = ReadByte(PC + 1);
const uint32_t address = (D + offset) & 0xFFFF;
PC += 2;
if (P & FLAG_M) { // 8-bit mode
uint8_t value = ReadByte(address);
value = (value - 1) & 0xFF;
WriteByte(address, value);
UpdateNZ8(value);
cycles += 5;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
} else { // 16-bit mode
uint16_t value = ReadWord(address);
value = (value - 1) & 0xFFFF;
WriteWord(address, value);
UpdateNZ16(value);
cycles += 7;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
}
}
void CPU::DEC_DirectPageX() {
const uint8_t offset = ReadByte(PC + 1);
const uint32_t address = (D + offset + X) & 0xFFFF;
PC += 2;
if (P & FLAG_M) { // 8-bit mode
uint8_t value = ReadByte(address);
value = (value - 1) & 0xFF;
WriteByte(address, value);
UpdateNZ8(value);
cycles += 6;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
} else { // 16-bit mode
uint16_t value = ReadWord(address);
value = (value - 1) & 0xFFFF;
WriteWord(address, value);
UpdateNZ16(value);
cycles += 8;
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
}
}
// INX - Increment X Register
void CPU::INX() {
if (P & FLAG_X) { // 8-bit mode
X = (X & 0xFF00) | ((X + 1) & 0xFF);
UpdateNZ8(X & 0xFF);
} else { // 16-bit mode
X = (X + 1) & 0xFFFF;
UpdateNZ16(X);
}
cycles += 2;
}
// INY - Increment Y Register
void CPU::INY() {
if (P & FLAG_X) { // 8-bit mode
Y = (Y & 0xFF00) | ((Y + 1) & 0xFF);
UpdateNZ8(Y & 0xFF);
} else { // 16-bit mode
Y = (Y + 1) & 0xFFFF;
UpdateNZ16(Y);
}
cycles += 2;
}
// DEX - Decrement X Register
void CPU::DEX() {
if (P & FLAG_X) { // 8-bit mode
X = (X & 0xFF00) | ((X - 1) & 0xFF);
UpdateNZ8(X & 0xFF);
} else { // 16-bit mode
X = (X - 1) & 0xFFFF;
UpdateNZ16(X);
}
cycles += 2;
}
// DEY - Decrement Y Register
void CPU::DEY() {
if (P & FLAG_X) { // 8-bit mode
Y = (Y & 0xFF00) | ((Y - 1) & 0xFF);
UpdateNZ8(Y & 0xFF);
} else { // 16-bit mode
Y = (Y - 1) & 0xFFFF;
UpdateNZ16(Y);
}
cycles += 2;
} }

View File

@@ -47,7 +47,7 @@ public:
[[nodiscard]] uint64_t GetCycles() const { return cycles; } [[nodiscard]] uint64_t GetCycles() const { return cycles; }
// Addressing mode helpers // Addressing mode helpers
uint32_t GetEffectiveAddress(uint8_t mode); //uint32_t GetEffectiveAddress(uint8_t mode);
uint8_t ReadByte(uint32_t address); uint8_t ReadByte(uint32_t address);
uint16_t ReadWord(uint32_t address); uint16_t ReadWord(uint32_t address);
void UpdateNZ8(uint8_t value); void UpdateNZ8(uint8_t value);
@@ -88,7 +88,6 @@ public:
void LDY_DirectPage(); void LDY_DirectPage();
void LDY_DirectPageX(); void LDY_DirectPageX();
// STA - Store Accumulator operations
void STA_Absolute(); void STA_Absolute();
void STA_AbsoluteX(); void STA_AbsoluteX();
void STA_AbsoluteY(); void STA_AbsoluteY();
@@ -100,18 +99,30 @@ public:
void STA_Long(); void STA_Long();
void STA_LongX(); void STA_LongX();
// STX - Store X Register operations
void STX_Absolute(); void STX_Absolute();
void STX_DirectPage(); void STX_DirectPage();
void STX_DirectPageY(); void STX_DirectPageY();
// STY - Store Y Register operations
void STY_Absolute(); void STY_Absolute();
void STY_DirectPage(); void STY_DirectPage();
void STY_DirectPageX(); void STY_DirectPageX();
void INC_Accumulator();
void INC_Absolute();
void INC_AbsoluteX();
void INC_DirectPage();
void INC_DirectPageX();
void STA(); void DEC_Accumulator();
void DEC_Absolute();
void DEC_AbsoluteX();
void DEC_DirectPage();
void DEC_DirectPageX();
void INX();
void INY();
void DEX();
void DEY();
}; };
#endif //CPU_H #endif //CPU_H