Implement Compare Instructions
This commit is contained in:
365
src/cpu.cpp
365
src/cpu.cpp
@@ -53,9 +53,79 @@ void CPU::WriteWord(const uint32_t address, const uint16_t value) const {
|
|||||||
bus->Write(address + 1, (value >> 8) & 0xFF); // High byte
|
bus->Write(address + 1, (value >> 8) & 0xFF); // High byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to update flags after compare operation
|
||||||
|
void CPU::UpdateCompareFlags8(const uint8_t reg_value, const uint8_t compare_value) {
|
||||||
|
const uint16_t result = reg_value - compare_value;
|
||||||
|
|
||||||
|
// Set/clear flags
|
||||||
|
if (result & 0x100) {
|
||||||
|
P &= ~FLAG_C;
|
||||||
|
} else {
|
||||||
|
P |= FLAG_C;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result & 0xFF) == 0) {
|
||||||
|
P |= FLAG_Z;
|
||||||
|
} else {
|
||||||
|
P &= ~FLAG_Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result & 0x80) {
|
||||||
|
P |= FLAG_N;
|
||||||
|
} else {
|
||||||
|
P &= ~FLAG_N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::UpdateCompareFlags16(const uint16_t reg_value, const uint16_t compare_value) {
|
||||||
|
const uint32_t result = reg_value - compare_value;
|
||||||
|
|
||||||
|
// Set/clear flags
|
||||||
|
if (result & 0x10000) {
|
||||||
|
P &= ~FLAG_C;
|
||||||
|
} else {
|
||||||
|
P |= FLAG_C;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result & 0xFFFF) == 0) {
|
||||||
|
P |= FLAG_Z;
|
||||||
|
} else {
|
||||||
|
P &= ~FLAG_Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result & 0x8000) {
|
||||||
|
P |= FLAG_N;
|
||||||
|
} else {
|
||||||
|
P &= ~FLAG_N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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++)) {
|
||||||
|
// CMP - Compare Accumulator
|
||||||
|
case 0xC9: CMP_Immediate(); break; // CMP #$nn or #$nnnn
|
||||||
|
case 0xCD: CMP_Absolute(); break; // CMP $nnnn
|
||||||
|
case 0xDD: CMP_AbsoluteX(); break; // CMP $nnnn,X
|
||||||
|
case 0xD9: CMP_AbsoluteY(); break; // CMP $nnnn,Y
|
||||||
|
case 0xC5: CMP_DirectPage(); break; // CMP $nn
|
||||||
|
case 0xD5: CMP_DirectPageX(); break; // CMP $nn,X
|
||||||
|
case 0xD2: CMP_IndirectDirectPage(); break; // CMP ($nn)
|
||||||
|
case 0xD1: CMP_IndirectDirectPageY(); break; // CMP ($nn),Y
|
||||||
|
case 0xC1: CMP_DirectPageIndirectX(); break; // CMP ($nn,X)
|
||||||
|
case 0xCF: CMP_Long(); break; // CMP $nnnnnn
|
||||||
|
case 0xDF: CMP_LongX(); break; // CMP $nnnnnn,X
|
||||||
|
|
||||||
|
// CPX - Compare X Register
|
||||||
|
case 0xE0: CPX_Immediate(); break; // CPX #$nn or #$nnnn
|
||||||
|
case 0xEC: CPX_Absolute(); break; // CPX $nnnn
|
||||||
|
case 0xE4: CPX_DirectPage(); break; // CPX $nn
|
||||||
|
|
||||||
|
// CPY - Compare Y Register
|
||||||
|
case 0xC0: CPY_Immediate(); break; // CPY #$nn or #$nnnn
|
||||||
|
case 0xCC: CPY_Absolute(); break; // CPY $nnnn
|
||||||
|
case 0xC4: CPY_DirectPage(); break; // CPY $nn
|
||||||
|
|
||||||
// DEC - Decrement Memory
|
// DEC - Decrement Memory
|
||||||
case 0x3A: DEC_Accumulator(); break; // DEC A
|
case 0x3A: DEC_Accumulator(); break; // DEC A
|
||||||
case 0xCE: DEC_Absolute(); break; // DEC $nnnn
|
case 0xCE: DEC_Absolute(); break; // DEC $nnnn
|
||||||
@@ -1048,4 +1118,299 @@ void CPU::DEY() {
|
|||||||
UpdateNZ16(Y);
|
UpdateNZ16(Y);
|
||||||
}
|
}
|
||||||
cycles += 2;
|
cycles += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CMP - Compare Accumulator
|
||||||
|
void CPU::CMP_Immediate() {
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(PC + 1);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
PC += 2;
|
||||||
|
cycles += 2;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(PC + 1);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
PC += 3;
|
||||||
|
cycles += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_Absolute() {
|
||||||
|
const uint32_t address = ReadWord(PC + 1) | (DB << 16);
|
||||||
|
PC += 3;
|
||||||
|
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 4;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_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
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 4;
|
||||||
|
// Add extra cycle if page boundary crossed
|
||||||
|
if ((base & 0xFF00) != (address & 0xFF00)) cycles++;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 5;
|
||||||
|
// Add extra cycle if page boundary crossed
|
||||||
|
if ((base & 0xFF00) != (address & 0xFF00)) cycles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_AbsoluteY() {
|
||||||
|
const uint32_t base = ReadWord(PC + 1) | (DB << 16);
|
||||||
|
const uint32_t address = base + Y;
|
||||||
|
PC += 3;
|
||||||
|
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 4;
|
||||||
|
// Add extra cycle if page boundary crossed
|
||||||
|
if ((base & 0xFF00) != (address & 0xFF00)) cycles++;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 5;
|
||||||
|
// Add extra cycle if page boundary crossed
|
||||||
|
if ((base & 0xFF00) != (address & 0xFF00)) cycles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_DirectPage() {
|
||||||
|
const uint8_t offset = ReadByte(PC + 1);
|
||||||
|
const uint32_t address = (D + offset) & 0xFFFF;
|
||||||
|
PC += 2;
|
||||||
|
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 3;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 4;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_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
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 4;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 5;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_IndirectDirectPage() {
|
||||||
|
const uint8_t offset = ReadByte(PC + 1);
|
||||||
|
const uint32_t pointer = (D + offset) & 0xFFFF;
|
||||||
|
const uint32_t address = ReadWord(pointer) | (DB << 16);
|
||||||
|
PC += 2;
|
||||||
|
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 5;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 6;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_IndirectDirectPageY() {
|
||||||
|
const uint8_t offset = ReadByte(PC + 1);
|
||||||
|
const uint32_t pointer = (D + offset) & 0xFFFF;
|
||||||
|
const uint32_t base = ReadWord(pointer) | (DB << 16);
|
||||||
|
const uint32_t address = base + Y;
|
||||||
|
PC += 2;
|
||||||
|
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 5;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
// Add extra cycle if page boundary crossed
|
||||||
|
if ((base & 0xFF00) != (address & 0xFF00)) cycles++;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 6;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
// Add extra cycle if page boundary crossed
|
||||||
|
if ((base & 0xFF00) != (address & 0xFF00)) cycles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_DirectPageIndirectX() {
|
||||||
|
const uint8_t offset = ReadByte(PC + 1);
|
||||||
|
const uint32_t pointer = (D + offset + X) & 0xFFFF;
|
||||||
|
const uint32_t address = ReadWord(pointer) | (DB << 16);
|
||||||
|
PC += 2;
|
||||||
|
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 6;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 7;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_Long() {
|
||||||
|
const uint32_t address = ReadByte(PC + 1) | (ReadByte(PC + 2) << 8) | (ReadByte(PC + 3) << 16);
|
||||||
|
PC += 4;
|
||||||
|
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 5;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CMP_LongX() {
|
||||||
|
const uint32_t base = ReadByte(PC + 1) | (ReadByte(PC + 2) << 8) | (ReadByte(PC + 3) << 16);
|
||||||
|
const uint32_t address = base + X;
|
||||||
|
PC += 4;
|
||||||
|
|
||||||
|
if (P & FLAG_M) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(A & 0xFF, operand);
|
||||||
|
cycles += 6;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(A, operand);
|
||||||
|
cycles += 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPX - Compare X Register
|
||||||
|
void CPU::CPX_Immediate() {
|
||||||
|
if (P & FLAG_X) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(PC + 1);
|
||||||
|
UpdateCompareFlags8(X & 0xFF, operand);
|
||||||
|
PC += 2;
|
||||||
|
cycles += 2;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(PC + 1);
|
||||||
|
UpdateCompareFlags16(X, operand);
|
||||||
|
PC += 3;
|
||||||
|
cycles += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CPX_Absolute() {
|
||||||
|
const uint32_t address = ReadWord(PC + 1) | (DB << 16);
|
||||||
|
PC += 3;
|
||||||
|
|
||||||
|
if (P & FLAG_X) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(X & 0xFF, operand);
|
||||||
|
cycles += 4;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(X, operand);
|
||||||
|
cycles += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CPX_DirectPage() {
|
||||||
|
const uint8_t offset = ReadByte(PC + 1);
|
||||||
|
const int32_t address = (D + offset) & 0xFFFF;
|
||||||
|
PC += 2;
|
||||||
|
|
||||||
|
if (P & FLAG_X) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(X & 0xFF, operand);
|
||||||
|
cycles += 3;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(X, operand);
|
||||||
|
cycles += 4;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPY - Compare Y Register
|
||||||
|
void CPU::CPY_Immediate() {
|
||||||
|
if (P & FLAG_X) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(PC + 1);
|
||||||
|
UpdateCompareFlags8(Y & 0xFF, operand);
|
||||||
|
PC += 2;
|
||||||
|
cycles += 2;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(PC + 1);
|
||||||
|
UpdateCompareFlags16(Y, operand);
|
||||||
|
PC += 3;
|
||||||
|
cycles += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CPY_Absolute() {
|
||||||
|
const uint32_t address = ReadWord(PC + 1) | (DB << 16);
|
||||||
|
PC += 3;
|
||||||
|
|
||||||
|
if (P & FLAG_X) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(Y & 0xFF, operand);
|
||||||
|
cycles += 4;
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(Y, operand);
|
||||||
|
cycles += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::CPY_DirectPage() {
|
||||||
|
const uint8_t offset = ReadByte(PC + 1);
|
||||||
|
const uint32_t address = (D + offset) & 0xFFFF;
|
||||||
|
PC += 2;
|
||||||
|
|
||||||
|
if (P & FLAG_X) { // 8-bit mode
|
||||||
|
const uint8_t operand = ReadByte(address);
|
||||||
|
UpdateCompareFlags8(Y & 0xFF, operand);
|
||||||
|
cycles += 3;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
} else { // 16-bit mode
|
||||||
|
const uint16_t operand = ReadWord(address);
|
||||||
|
UpdateCompareFlags16(Y, operand);
|
||||||
|
cycles += 4;
|
||||||
|
if (D & 0xFF) cycles++; // Extra cycle if D register low byte != 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
23
src/cpu.h
23
src/cpu.h
@@ -57,9 +57,32 @@ public:
|
|||||||
void WriteByte(uint32_t address, uint8_t value) const;
|
void WriteByte(uint32_t address, uint8_t value) const;
|
||||||
void WriteWord(uint32_t address, uint16_t value) const;
|
void WriteWord(uint32_t address, uint16_t value) const;
|
||||||
|
|
||||||
|
// Helper methods for compare operations
|
||||||
|
void UpdateCompareFlags8(uint8_t reg_value, uint8_t compare_value);
|
||||||
|
void UpdateCompareFlags16(uint16_t reg_value, uint16_t compare_value);
|
||||||
|
|
||||||
// Instruction implementations
|
// Instruction implementations
|
||||||
// TODO: Implement remaining instructions
|
// TODO: Implement remaining instructions
|
||||||
|
void CMP_Immediate();
|
||||||
|
void CMP_Absolute();
|
||||||
|
void CMP_AbsoluteX();
|
||||||
|
void CMP_AbsoluteY();
|
||||||
|
void CMP_DirectPage();
|
||||||
|
void CMP_DirectPageX();
|
||||||
|
void CMP_IndirectDirectPage();
|
||||||
|
void CMP_IndirectDirectPageY();
|
||||||
|
void CMP_DirectPageIndirectX();
|
||||||
|
void CMP_Long();
|
||||||
|
void CMP_LongX();
|
||||||
|
|
||||||
|
void CPX_Immediate();
|
||||||
|
void CPX_Absolute();
|
||||||
|
void CPX_DirectPage();
|
||||||
|
|
||||||
|
void CPY_Immediate();
|
||||||
|
void CPY_Absolute();
|
||||||
|
void CPY_DirectPage();
|
||||||
|
|
||||||
void JMP();
|
void JMP();
|
||||||
|
|
||||||
static void NOP();
|
static void NOP();
|
||||||
|
|||||||
Reference in New Issue
Block a user