Added ASL, BCS, BIT, BMI, BPL, BRA

BRK, BVC, BVS, CPX, CPY, DEX, DEY
INX, INY, LDX, LDY, LSR, ORA, PEA, PEI
PER ROL, ROR, RTL, RTS, STA, STX, STY
TRB, TSB, XBA,
This commit is contained in:
scawful
2023-08-20 00:27:05 -04:00
parent 536136d8c9
commit 905f81d60e
3 changed files with 922 additions and 172 deletions

View File

@@ -86,12 +86,11 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
ADC(FetchByteDirectPage(PC));
break;
case 0x67: // ADC DP Indirect Long
operand = memory.ReadByte(DirectPageIndirectLong());
operand = memory.ReadWord(DirectPageIndirectLong());
ADC(operand);
break;
case 0x69: // ADC Immediate
operand = memory.ReadByte(Immediate());
ADC(operand);
ADC(Immediate());
break;
case 0x6D: // ADC Absolute
operand = memory.ReadWord(Absolute());
@@ -118,15 +117,14 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
ADC(operand);
break;
case 0x77: // ADC DP Indirect Long Indexed, Y
operand = memory.ReadByte(DirectPageIndirectLongIndexedY());
ADC(operand);
ADC(DirectPageIndirectLongIndexedY());
break;
case 0x79: // ADC Absolute Indexed, Y
operand = memory.ReadByte(AbsoluteIndexedY());
operand = memory.ReadWord(AbsoluteIndexedY());
ADC(operand);
break;
case 0x7D: // ADC Absolute Indexed, X
operand = memory.ReadByte(AbsoluteIndexedX());
operand = memory.ReadWord(AbsoluteIndexedX());
ADC(operand);
break;
case 0x7F: // ADC Absolute Long Indexed, X
@@ -151,7 +149,7 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
AND(operand);
break;
case 0x29: // AND Immediate
AND(Immediate());
AND(Immediate(), true);
break;
case 0x2D: // AND Absolute
AND(Absolute());
@@ -190,19 +188,23 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
break;
case 0x06: // ASL Direct Page
// ASL();
ASL(DirectPage());
break;
case 0x0A: // ASL Accumulator
// ASL();
A <<= 1;
A &= 0xFE;
SetCarryFlag(A & 0x80);
SetNegativeFlag(A);
SetZeroFlag(!A);
break;
case 0x0E: // ASL Absolute
// ASL();
ASL(Absolute());
break;
case 0x16: // ASL DP Indexed, X
// ASL();
ASL(DirectPageIndexedX());
break;
case 0x1E: // ASL Absolute Indexed, X
// ASL();
ASL(AbsoluteIndexedX());
break;
case 0x90: // BCC Branch if carry clear
@@ -211,7 +213,7 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
break;
case 0xB0: // BCS Branch if carry set
// BCS();
BCS(memory.ReadByte(PC));
break;
case 0xF0: // BEQ Branch if equal (zero set)
@@ -220,39 +222,39 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
break;
case 0x24: // BIT Direct Page
// BIT();
BIT(DirectPage());
break;
case 0x2C: // BIT Absolute
// BIT();
BIT(Absolute());
break;
case 0x34: // BIT DP Indexed, X
// BIT();
BIT(DirectPageIndexedX());
break;
case 0x3C: // BIT Absolute Indexed, X
// BIT();
BIT(AbsoluteIndexedX());
break;
case 0x89: // BIT Immediate
// BIT();
BIT(Immediate());
break;
case 0x30: // BMI Branch if minus (negative set)
// BMI();
BMI(ReadByte(PC));
break;
case 0xD0: // BNE Branch if not equal (zero clear)
// BNE();
BNE(ReadByte(PC));
break;
case 0x10: // BPL Branch if plus (negative clear)
// BPL();
BPL(ReadByte(PC));
break;
case 0x80: // BRA Branch always
// BRA();
BRA(ReadByte(PC));
break;
case 0x00: // BRK Break
// BRK();
BRK();
break;
case 0x82: // BRL Branch always long
@@ -334,20 +336,20 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
break;
case 0xE0: // CPX Immediate
CPX(Immediate());
CPX(Immediate(), true);
break;
case 0xE4: // CPX Direct Page
// CPX();
CPX(DirectPage());
break;
case 0xEC: // CPX Absolute
CPX(Absolute());
break;
case 0xC0: // CPY Immediate
CPY(Immediate());
CPY(Immediate(), true);
break;
case 0xC4: // CPY Direct Page
// CPY();
CPY(DirectPage());
break;
case 0xCC: // CPY Absolute
CPY(Absolute());
@@ -424,19 +426,19 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
break;
case 0x1A: // INC Accumulator
// INC();
INC(A);
break;
case 0xE6: // INC Direct Page
// INC();
INC(DirectPage());
break;
case 0xEE: // INC Absolute
// INC();
INC(Absolute());
break;
case 0xF6: // INC DP Indexed, X
// INC();
INC(DirectPageIndexedX());
break;
case 0xFE: // INC Absolute Indexed, X
// INC();
INC(AbsoluteIndexedX());
break;
case 0xE8: // INX Increment X register
@@ -457,10 +459,10 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
JMP(AbsoluteIndirect());
break;
case 0x7C: // JMP Absolute Indexed Indirect, X
// JMP();
JMP(AbsoluteIndexedIndirect());
break;
case 0xDC: // JMP Absolute Indirect Long
// JMP();
JMP(AbsoluteIndirectLong());
break;
case 0x20: // JSR Absolute
@@ -472,53 +474,53 @@ void CPU::ExecuteInstruction(uint8_t opcode) {
break;
case 0xFC: // JSR Absolute Indexed Indirect, X
// JSR();
JSR(AbsoluteIndexedIndirect());
break;
case 0xA1: // LDA DP Indexed Indirect, X
// LDA();
LDA(DirectPageIndexedIndirectX());
break;
case 0xA3: // LDA Stack Relative
// LDA();
LDA(StackRelative());
break;
case 0xA5: // LDA Direct Page
// LDA();
LDA(DirectPage());
break;
case 0xA7: // LDA DP Indirect Long
// LDA();
LDA(DirectPageIndirectLong());
break;
case 0xA9: // LDA Immediate
LDA();
LDA(PC + 1, true);
break;
case 0xAD: // LDA Absolute
// LDA();
LDA(Absolute());
break;
case 0xAF: // LDA Absolute Long
// LDA();
LDA(AbsoluteLong());
break;
case 0xB1: // LDA DP Indirect Indexed, Y
// LDA();
LDA(DirectPageIndirectIndexedY());
break;
case 0xB2: // LDA DP Indirect
// LDA();
LDA(DirectPageIndirect());
break;
case 0xB3: // LDA SR Indirect Indexed, Y
// LDA();
LDA(StackRelativeIndirectIndexedY());
break;
case 0xB5: // LDA DP Indexed, X
// LDA();
LDA(DirectPageIndexedX());
break;
case 0xB7: // LDA DP Indirect Long Indexed, Y
// LDA();
LDA(DirectPageIndirectLongIndexedY());
break;
case 0xB9: // LDA Absolute Indexed, Y
// LDA();
LDA(DirectPageIndirectLongIndexedY());
break;
case 0xBD: // LDA Absolute Indexed, X
// LDA();
LDA(DirectPageIndirectLongIndexedY());
break;
case 0xBF: // LDA Absolute Long Indexed, X
// LDA();
LDA(DirectPageIndirectLongIndexedY());
break;
case 0xA2: // LDX Immediate
@@ -995,15 +997,15 @@ void CPU::ADC(uint8_t operand) {
}
}
void CPU::AND(uint16_t address) {
uint8_t operand;
void CPU::AND(uint16_t value, bool isImmediate) {
uint16_t operand;
if (E == 0) { // 16-bit mode
uint16_t operand16 = memory.ReadWord(address);
A &= operand16;
operand = isImmediate ? value : memory.ReadWord(value);
A &= operand;
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000);
} else { // 8-bit mode
operand = memory.ReadByte(address);
operand = isImmediate ? value : memory.ReadByte(value);
A &= operand;
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80);
@@ -1018,6 +1020,39 @@ void CPU::ANDAbsoluteLong(uint32_t address) {
SetNegativeFlag(A & 0x80000000);
}
void CPU::SBC(uint16_t value, bool isImmediate) {
uint16_t operand;
if (!GetAccumulatorSize()) { // 16-bit mode
operand = isImmediate ? value : memory.ReadWord(value);
uint32_t result = A - operand - (GetCarryFlag() ? 0 : 1);
SetCarryFlag(!(result > 0xFFFF)); // Update the carry flag
// Update the overflow flag
bool overflow = ((A ^ operand) & (A ^ result) & 0x8000) != 0;
SetOverflowFlag(overflow);
// Update the accumulator
A = result & 0xFFFF;
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000);
} else { // 8-bit mode
operand = isImmediate ? value : memory.ReadByte(value);
uint16_t result = A - operand - (GetCarryFlag() ? 0 : 1);
SetCarryFlag(!(result > 0xFF)); // Update the carry flag
// Update the overflow flag
bool overflow = ((A ^ operand) & (A ^ result) & 0x80) != 0;
SetOverflowFlag(overflow);
// Update the accumulator
A = result & 0xFF;
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80);
}
}
} // namespace emu
} // namespace app
} // namespace yaze

View File

@@ -196,7 +196,7 @@ class CPU : public Memory {
// register in bank zero.
//
// LDA [dp]
uint16_t DirectPageIndirectLong() {
uint32_t DirectPageIndirectLong() {
uint8_t dp = FetchByte();
uint16_t effective_address = D + dp;
return memory.ReadWordLong(effective_address);
@@ -227,8 +227,8 @@ class CPU : public Memory {
// LDA (dp), Y
uint16_t DirectPageIndirectLongIndexedY() {
uint8_t dp = FetchByte();
uint16_t effective_address = D + dp;
return memory.ReadWordLong(effective_address) + Y;
uint16_t effective_address = D + dp + Y;
return memory.ReadWordLong(effective_address);
}
// 8-bit data: Data Operand Byte
@@ -237,7 +237,13 @@ class CPU : public Memory {
// Data Low: First Operand Byte
//
// LDA #const
uint16_t Immediate() { return PC++; }
uint16_t Immediate() {
if (GetAccumulatorSize()) {
return FetchByte();
} else {
return FetchWord();
}
}
uint16_t StackRelative() {
uint8_t sr = FetchByte();
@@ -246,7 +252,7 @@ class CPU : public Memory {
uint16_t StackRelativeIndirectIndexedY() {
uint8_t sr = FetchByte();
return memory.ReadWord(SP() + sr) + Y;
return memory.ReadWord(SP() + sr + Y);
}
// ==========================================================================
@@ -254,10 +260,8 @@ class CPU : public Memory {
uint8_t A = 0; // Accumulator
uint8_t B = 0; // Accumulator (High)
uint8_t X = 0; // X index register
uint8_t X2 = 0; // X index register (High)
uint8_t Y = 0; // Y index register
uint8_t Y2 = 0; // Y index register (High)
uint16_t X = 0; // X index register
uint16_t Y = 0; // Y index register
uint16_t D = 0; // Direct Page register
uint16_t DB = 0; // Data Bank register
uint8_t PB = 0; // Program Bank register
@@ -280,6 +284,8 @@ class CPU : public Memory {
// Setting flags in the status register
int GetAccumulatorSize() const { return status & 0x20; }
int GetIndexSize() const { return status & 0x10; }
void SetAccumulatorSize(bool set) { SetFlag(0x20, set); }
void SetIndexSize(bool set) { SetFlag(0x10, set); }
// Set individual flags
void SetNegativeFlag(bool set) { SetFlag(0x80, set); }
@@ -301,16 +307,24 @@ class CPU : public Memory {
// ==========================================================================
// Instructions
/// ``` Unimplemented
// ADC: Add with carry
void ADC(uint8_t operand);
void ANDAbsoluteLong(uint32_t address);
// AND: Logical AND
void AND(uint16_t address);
void AND(uint16_t address, bool isImmediate = false);
// ASL: Arithmetic shift left ```
// ASL: Arithmetic shift left
void ASL(uint16_t address) {
uint8_t value = memory.ReadByte(address);
SetCarryFlag(!(value & 0x80)); // Set carry flag if bit 7 is set
value <<= 1; // Shift left
value &= 0xFE; // Clear bit 0
memory.WriteByte(address, value);
SetNegativeFlag(!value);
SetZeroFlag(value);
}
// BCC: Branch if carry clear
void BCC(int8_t offset) {
@@ -319,7 +333,12 @@ class CPU : public Memory {
}
}
// BCS: Branch if carry set ```
// BCS: Branch if carry set
void BCS(int8_t offset) {
if (GetCarryFlag()) { // If the carry flag is set
PC += offset; // Add the offset to the program counter
}
}
// BEQ: Branch if equal (zero set)
void BEQ(int8_t offset) {
@@ -328,20 +347,65 @@ class CPU : public Memory {
}
}
// BIT: Bit test ```
// BMI: Branch if minus (negative set) ```
// BNE: Branch if not equal (zero clear) ```
// BPL: Branch if plus (negative clear) ```
// BRA: Branch always ```
// BRK: Break ```
// BIT: Bit test
void BIT(uint16_t address) {
uint8_t value = memory.ReadByte(address);
SetNegativeFlag(value & 0x80);
SetOverflowFlag(value & 0x40);
SetZeroFlag((A & value) == 0);
}
// BMI: Branch if minus (negative set)
void BMI(int8_t offset) {
if (GetNegativeFlag()) { // If the negative flag is set
PC += offset; // Add the offset to the program counter
}
}
// BNE: Branch if not equal (zero clear)
void BNE(int8_t offset) {
if (!GetZeroFlag()) { // If the zero flag is clear
PC += offset; // Add the offset to the program counter
}
}
// BPL: Branch if plus (negative clear)
void BPL(int8_t offset) {
if (!GetNegativeFlag()) { // If the negative flag is clear
PC += offset; // Add the offset to the program counter
}
}
// BRA: Branch always
void BRA(int8_t offset) { PC += offset; }
// BRK: Break
void BRK() {
PC += 2; // Increment the program counter by 2
memory.PushWord(PC);
memory.PushByte(status);
SetInterruptFlag(true);
PC = memory.ReadWord(0xFFFE);
}
// BRL: Branch always long
void BRL(int16_t offset) {
PC += offset; // Add the offset to the program counter
}
// BVC: Branch if overflow clear ```
// BVS: Branch if overflow set ```
// BVC: Branch if overflow clear
void BVC(int8_t offset) {
if (!GetOverflowFlag()) { // If the overflow flag is clear
PC += offset; // Add the offset to the program counter
}
}
// BVS: Branch if overflow set
void BVS(int8_t offset) {
if (GetOverflowFlag()) { // If the overflow flag is set
PC += offset; // Add the offset to the program counter
}
}
// CLC: Clear carry flag
void CLC() { status &= ~0x01; }
@@ -359,16 +423,21 @@ class CPU : public Memory {
// COP: Coprocessor ```
// CPX: Compare X register
void CPX(uint16_t address) {
uint16_t memory_value =
E ? memory.ReadByte(address) : memory.ReadWord(address);
// CPX: Compare X register
void CPX(uint16_t value, bool isImmediate = false) {
uint16_t memory_value = isImmediate
? value
: (GetIndexSize() ? memory.ReadByte(value)
: memory.ReadWord(value));
compare(X, memory_value);
}
// CPY: Compare Y register
void CPY(uint16_t address) {
uint16_t memory_value =
E ? memory.ReadByte(address) : memory.ReadWord(address);
void CPY(uint16_t value, bool isImmediate = false) {
uint16_t memory_value = isImmediate
? value
: (GetIndexSize() ? memory.ReadByte(value)
: memory.ReadWord(value));
compare(Y, memory_value);
}
@@ -376,56 +445,73 @@ class CPU : public Memory {
// DEX: Decrement X register
void DEX() {
X--;
SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80);
if (GetIndexSize()) { // 8-bit
X = static_cast<uint8_t>(X - 1);
SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80);
} else { // 16-bit
X = static_cast<uint16_t>(X - 1);
SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x8000);
}
}
// DEY: Decrement Y register
void DEY() {
Y--;
SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x80);
if (GetIndexSize()) { // 8-bit
Y = static_cast<uint8_t>(Y - 1);
SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x80);
} else { // 16-bit
Y = static_cast<uint16_t>(Y - 1);
SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x8000);
}
}
// EOR: Exclusive OR ```
// INC: Increment
// TODO: Check if this is correct
void INC(uint16_t address) {
if (GetAccumulatorSize()) {
uint8_t value = ReadByte(address);
uint8_t value = memory.ReadByte(address);
value++;
if (value == static_cast<uint8_t>(0x100)) {
value = 0x00; // Wrap around in 8-bit mode
}
WriteByte(address, value);
memory.WriteByte(address, value);
SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0);
} else {
uint16_t value = ReadWord(address);
uint16_t value = memory.ReadWord(address);
value++;
if (value == static_cast<uint16_t>(0x10000)) {
value = 0x0000; // Wrap around in 16-bit mode
}
WriteByte(address, value);
SetNegativeFlag(value & 0x80);
memory.WriteWord(address, value);
SetNegativeFlag(value & 0x8000);
SetZeroFlag(value == 0);
}
}
// INX: Increment X register
void INX() {
X++;
SetNegativeFlag(X & 0x80);
SetZeroFlag(X == 0);
if (GetIndexSize()) { // 8-bit
X = static_cast<uint8_t>(X + 1);
SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80);
} else { // 16-bit
X = static_cast<uint16_t>(X + 1);
SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x8000);
}
}
// INY: Increment Y register
void INY() {
Y++;
SetNegativeFlag(Y & 0x80);
SetZeroFlag(Y == 0);
if (GetIndexSize()) { // 8-bit
Y = static_cast<uint8_t>(Y + 1);
SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x80);
} else { // 16-bit
Y = static_cast<uint16_t>(Y + 1);
SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x8000);
}
}
// JMP: Jump
@@ -457,16 +543,54 @@ class CPU : public Memory {
}
// LDA: Load accumulator
void LDA() {
A = memory[PC];
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80);
PC++;
void LDA(uint16_t address, bool isImmediate = false) {
if (GetAccumulatorSize()) {
A = isImmediate ? address : memory.ReadByte(address);
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80);
} else {
A = isImmediate ? address : memory.ReadWord(address);
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000);
}
}
// LDX: Load X register
void LDX(uint16_t address, bool isImmediate = false) {
if (GetIndexSize()) {
X = isImmediate ? address : memory.ReadByte(address);
SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x80);
} else {
X = isImmediate ? address : memory.ReadWord(address);
SetZeroFlag(X == 0);
SetNegativeFlag(X & 0x8000);
}
}
// LDY: Load Y register
void LDY(uint16_t address, bool isImmediate = false) {
if (GetIndexSize()) {
Y = isImmediate ? address : memory.ReadByte(address);
SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x80);
} else {
Y = isImmediate ? address : memory.ReadWord(address);
SetZeroFlag(Y == 0);
SetNegativeFlag(Y & 0x8000);
}
}
// LSR: Logical shift right
void LSR(uint16_t address) {
uint8_t value = memory.ReadByte(address);
SetCarryFlag(value & 0x01);
value >>= 1;
memory.WriteByte(address, value);
SetNegativeFlag(false);
SetZeroFlag(value == 0);
}
// LDX: Load X register ```
// LDY: Load Y register ```
// LSR: Logical shift right ```
// MVN: Move negative ```
// MVP: Move positive ```
@@ -475,10 +599,36 @@ class CPU : public Memory {
// Do nothing
}
// ORA: Logical OR ```
// PEA: Push effective address ```
// PEI: Push effective indirect address ```
// PER: Push effective PC-relative address ```
// ORA: Logical OR
void ORA(uint16_t address, bool isImmediate = false) {
if (GetAccumulatorSize()) {
A |= isImmediate ? address : memory.ReadByte(address);
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80);
} else {
A |= isImmediate ? address : memory.ReadWord(address);
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x8000);
}
}
// PEA: Push effective address
void PEA() {
uint16_t address = FetchWord();
memory.PushWord(address);
}
// PEI: Push effective indirect address
void PEI() {
uint16_t address = FetchWord();
memory.PushWord(memory.ReadWord(address));
}
// PER: Push effective PC-relative address
void PER() {
uint16_t address = FetchWord();
memory.PushWord(PC + address);
}
// PHA: Push Accumulator on Stack
void PHA() { memory.PushByte(A); }
@@ -546,12 +696,47 @@ class CPU : public Memory {
status &= ~byte;
}
// ROL: Rotate left ```
// ROR: Rotate right ```
// RTI: Return from interrupt ```
// RTL: Return from subroutine long ```
// RTS: Return from subroutine ```
// SBC: Subtract with carry ```
// ROL: Rotate left
void ROL(uint16_t address) {
uint8_t value = memory.ReadByte(address);
uint8_t carry = GetCarryFlag() ? 0x01 : 0x00;
SetCarryFlag(value & 0x80);
value <<= 1;
value |= carry;
memory.WriteByte(address, value);
SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0);
}
// ROR: Rotate right
void ROR(uint16_t address) {
uint8_t value = memory.ReadByte(address);
uint8_t carry = GetCarryFlag() ? 0x80 : 0x00;
SetCarryFlag(value & 0x01);
value >>= 1;
value |= carry;
memory.WriteByte(address, value);
SetNegativeFlag(value & 0x80);
SetZeroFlag(value == 0);
}
// RTI: Return from interrupt
void RTI() {
status = memory.PopByte();
PC = memory.PopWord();
}
// RTL: Return from subroutine long
void RTL() {
PC = memory.PopWord();
PB = memory.PopByte();
}
// RTS: Return from subroutine
void RTS() { PC = memory.PopWord() + 1; }
// SBC: Subtract with carry
void SBC(uint16_t operand, bool isImmediate = false);
// SEC: Set carry flag
void SEC() { status |= 0x01; }
@@ -569,11 +754,43 @@ class CPU : public Memory {
status |= byte;
}
// STA: Store accumulator ```
// STA: Store accumulator
void STA(uint16_t address) {
if (GetAccumulatorSize()) {
memory.WriteByte(address, static_cast<uint8_t>(A));
} else {
memory.WriteWord(address, A);
}
}
// STP: Stop the clock ```
// STX: Store X register ```
// STY: Store Y register ```
// STZ: Store zero ```
// STX: Store X register
void STX(uint16_t address) {
if (GetIndexSize()) {
memory.WriteByte(address, static_cast<uint8_t>(X));
} else {
memory.WriteWord(address, X);
}
}
// STY: Store Y register
void STY(uint16_t address) {
if (GetIndexSize()) {
memory.WriteByte(address, static_cast<uint8_t>(Y));
} else {
memory.WriteWord(address, Y);
}
}
// STZ: Store zero
void STZ(uint16_t address) {
if (GetAccumulatorSize()) {
memory.WriteByte(address, 0x00);
} else {
memory.WriteWord(address, 0x0000);
}
}
// TAX: Transfer accumulator to X
void TAX() {
@@ -606,8 +823,21 @@ class CPU : public Memory {
SetNegativeFlag(A & 0x80);
}
// TRB: Test and reset bits ```
// TSB: Test and set bits ```
// TRB: Test and reset bits
void TRB(uint16_t address) {
uint8_t value = memory.ReadByte(address);
SetZeroFlag((A & value) == 0);
value &= ~A;
memory.WriteByte(address, value);
}
// TSB: Test and set bits
void TSB(uint16_t address) {
uint8_t value = memory.ReadByte(address);
SetZeroFlag((A & value) == 0);
value |= A;
memory.WriteByte(address, value);
}
// TSC: Transfer stack pointer to accumulator
void TSC() {
@@ -655,7 +885,15 @@ class CPU : public Memory {
}
// WAI: Wait for interrupt ```
// XBA: Exchange B and A accumulator ```
// XBA: Exchange B and A accumulator
void XBA() {
uint8_t temp = A;
A = B;
B = temp;
SetZeroFlag(A == 0);
SetNegativeFlag(A & 0x80);
}
// XCE: Exchange Carry and Emulation Flags
void XCE() {
@@ -667,10 +905,20 @@ class CPU : public Memory {
private:
void compare(uint16_t register_value, uint16_t memory_value) {
uint16_t result = register_value - memory_value;
SetNegativeFlag(result & (E ? 0x8000 : 0x80)); // Negative flag
SetZeroFlag(result == 0); // Zero flag
SetCarryFlag(register_value >= 0); // Carry flag
uint16_t result;
if (GetIndexSize()) {
// 8-bit mode
uint8_t result8 = static_cast<uint8_t>(register_value) -
static_cast<uint8_t>(memory_value);
result = result8;
SetNegativeFlag(result & 0x80); // Negative flag for 8-bit
} else {
// 16-bit mode
result = register_value - memory_value;
SetNegativeFlag(result & 0x8000); // Negative flag for 16-bit
}
SetZeroFlag(result == 0); // Zero flag
SetCarryFlag(register_value >= memory_value); // Carry flag
}
// Helper function to set or clear a specific flag bit

View File

@@ -41,6 +41,16 @@ class MockMemory : public Memory {
std::copy(data.begin(), data.end(), memory_.begin());
}
void SetMemoryContents(const std::vector<uint16_t>& data) {
memory_.resize(64000);
int i = 0;
for (const auto& each : data) {
memory_[i] = each & 0xFF;
memory_[i + 1] = (each >> 8) & 0xFF;
i += 2;
}
}
void InsertMemory(const uint64_t address, const std::vector<uint8_t>& data) {
int i = 0;
for (const auto& each : data) {
@@ -158,7 +168,8 @@ TEST_F(CPUTest, CheckMemoryContents) {
TEST_F(CPUTest, ADC_Immediate_TwoPositiveNumbers) {
cpu.A = 0x01;
std::vector<uint8_t> data = {0x69, 0x01};
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x01};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x01));
@@ -169,6 +180,7 @@ TEST_F(CPUTest, ADC_Immediate_TwoPositiveNumbers) {
TEST_F(CPUTest, ADC_Immediate_PositiveAndNegativeNumbers) {
cpu.A = 10;
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x69, static_cast<uint8_t>(-20)};
mock_memory.SetMemoryContents(data);
@@ -258,7 +270,7 @@ TEST_F(CPUTest, ADC_DirectPageIndexedIndirectX) {
TEST_F(CPUTest, ADC_CheckCarryFlag) {
cpu.A = 0xFF;
cpu.status = 0;
cpu.status = 0xFF; // 8-bit mode
std::vector<uint8_t> data = {0x15, 0x01}; // Operand at address 0x15
mock_memory.SetMemoryContents(data);
@@ -270,18 +282,94 @@ TEST_F(CPUTest, ADC_CheckCarryFlag) {
EXPECT_TRUE(cpu.GetCarryFlag());
}
TEST_F(CPUTest, ADC_AbsoluteIndexedX) {
cpu.A = 0x03;
cpu.X = 0x02; // X register
cpu.PC = 0x0001;
std::vector<uint8_t> data = {0x7D, 0x03, 0x00, 0x00, 0x05, 0x00};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
EXPECT_CALL(mock_memory, ReadWord(0x0005)).WillOnce(Return(0x0005));
cpu.ExecuteInstruction(0x7D); // ADC Absolute Indexed X
EXPECT_EQ(cpu.A, 0x08);
}
TEST_F(CPUTest, ADC_AbsoluteIndexedY) {
cpu.A = 0x03;
cpu.Y = 0x02; // Y register
cpu.PC = 0x0001;
std::vector<uint8_t> data = {0x79, 0x03, 0x00, 0x00, 0x05, 0x00};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x0003));
EXPECT_CALL(mock_memory, ReadWord(0x0005)).WillOnce(Return(0x0005));
cpu.ExecuteInstruction(0x79); // ADC Absolute Indexed Y
EXPECT_EQ(cpu.A, 0x08);
}
TEST_F(CPUTest, ADC_DirectPageIndexedY) {
cpu.A = 0x03;
cpu.D = 0x2000;
cpu.Y = 0x02;
std::vector<uint8_t> data = {0x77, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2012, {0x06});
EXPECT_CALL(mock_memory, ReadByte(0x0000)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadWordLong(0x2012)).WillOnce(Return(0x06));
cpu.ExecuteInstruction(0x77); // ADC Direct Page Indexed Y
EXPECT_EQ(cpu.A, 0x09);
}
TEST_F(CPUTest, ADC_DirectPageIndirectLong) {
cpu.A = 0x03;
cpu.D = 0x2000;
cpu.PC = 0x0001;
std::vector<uint8_t> data = {0x67, 0x10};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x05, 0x00, 0x30});
mock_memory.InsertMemory(0x300005, {0x06});
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
EXPECT_CALL(mock_memory, ReadWordLong(0x2010)).WillOnce(Return(0x300005));
EXPECT_CALL(mock_memory, ReadWord(0x300005)).WillOnce(Return(0x06));
cpu.ExecuteInstruction(0x67); // ADC Direct Page Indirect Long
EXPECT_EQ(cpu.A, 0x09);
}
TEST_F(CPUTest, ADC_StackRelative) {
cpu.A = 0x03;
cpu.PC = 0x0001;
cpu.SetSP(0x01FF); // Setting Stack Pointer to 0x01FF
std::vector<uint8_t> data = {0x63, 0x02}; // ADC sr
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0201, {0x06}); // [0x0201] = 0x06
EXPECT_CALL(mock_memory, SP()).WillOnce(Return(0x01FF));
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x02)); // Operand
EXPECT_CALL(mock_memory, ReadByte(0x0201))
.WillOnce(Return(0x06)); // Memory value
cpu.ExecuteInstruction(0x63); // ADC Stack Relative
EXPECT_EQ(cpu.A, 0x09); // 0x03 + 0x06 = 0x09
}
// ============================================================================
// AND - Logical AND
TEST_F(CPUTest, AND_Immediate) {
cpu.PC = 0;
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0b11110000; // A register
std::vector<uint8_t> data = {0x29, 0b10101010}; // AND #0b10101010
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0b11110000; // A register
std::vector<uint8_t> data = {0b10101010}; // AND #0b10101010
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0b10101010));
cpu.ExecuteInstruction(0x29); // AND Immediate
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
@@ -403,6 +491,71 @@ TEST_F(CPUTest, AND_AbsoluteLongIndexedX) {
EXPECT_EQ(cpu.A, 0b10100000); // A register should now be 0b10100000
}
// ============================================================================
// ASL - Arithmetic Shift Left
TEST_F(CPUTest, ASL_DirectPage) {
cpu.D = 0x1000; // Setting Direct Page register to 0x1000
cpu.PC = 0x1000;
std::vector<uint8_t> data = {0x06, 0x10}; // ASL dp
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1010, {0x40}); // [0x1010] = 0x40
cpu.ExecuteInstruction(0x06); // ASL Direct Page
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CPUTest, ASL_Accumulator) {
cpu.status = 0xFF; // 8-bit mode
cpu.A = 0x40;
std::vector<uint8_t> data = {0x0A}; // ASL A
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x0A); // ASL Accumulator
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CPUTest, ASL_Absolute) {
std::vector<uint8_t> data = {0x0E, 0x10, 0x20}; // ASL abs
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2010, {0x40}); // [0x2010] = 0x40
cpu.ExecuteInstruction(0x0E); // ASL Absolute
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CPUTest, ASL_DP_Indexed_X) {
cpu.D = 0x1000; // Setting Direct Page register to 0x1000
cpu.X = 0x02; // Setting X register to 0x02
std::vector<uint8_t> data = {0x16, 0x10}; // ASL dp,X
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x1012, {0x40}); // [0x1012] = 0x40
cpu.ExecuteInstruction(0x16); // ASL DP Indexed, X
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
TEST_F(CPUTest, ASL_Absolute_Indexed_X) {
cpu.X = 0x02; // Setting X register to 0x02
std::vector<uint8_t> data = {0x1E, 0x10, 0x20}; // ASL abs,X
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x2012, {0x40}); // [0x2012] = 0x40
cpu.ExecuteInstruction(0x1E); // ASL Absolute Indexed, X
EXPECT_TRUE(cpu.GetCarryFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
EXPECT_TRUE(cpu.GetNegativeFlag());
}
// ============================================================================
// BCC - Branch if Carry Clear
@@ -431,6 +584,169 @@ TEST_F(CPUTest, BCC_WhenCarryFlagSet) {
EXPECT_EQ(cpu.PC, 0x1000);
}
// ============================================================================
// BCS - Branch if Carry Set
TEST_F(CPUTest, BCS_WhenCarryFlagSet) {
cpu.SetCarryFlag(true);
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xB0, 0x03, 0x02}; // Operand at address 0x1001
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x03));
cpu.ExecuteInstruction(0xB0); // BCS
EXPECT_EQ(cpu.PC, 0x1004);
}
TEST_F(CPUTest, BCS_WhenCarryFlagClear) {
cpu.SetCarryFlag(false);
cpu.PC = 0x1000;
std::vector<uint8_t> data = {0x10, 0x02, 0x01}; // Operand at address 0x1001
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(2));
cpu.ExecuteInstruction(0xB0); // BCS
cpu.BCS(2);
EXPECT_EQ(cpu.PC, 0x1000);
}
TEST_F(CPUTest, BIT_Immediate) {
cpu.A = 0x01;
cpu.PC = 0x0001;
cpu.status = 0xFF;
std::vector<uint8_t> data = {0x00, 0x10}; // BIT
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0010, {0x81}); // [0x0010] = 0x81
cpu.ExecuteInstruction(0x89); // BIT
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, BIT_Absolute) {
cpu.A = 0x01;
cpu.PC = 0x0001;
cpu.status = 0xFF;
std::vector<uint8_t> data = {0x00, 0x10}; // BIT
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0010, {0x81}); // [0x0010] = 0x81
// Read the operand
EXPECT_CALL(mock_memory, ReadByte(0x0001)).WillOnce(Return(0x10));
// Read the value at the address of the operand
EXPECT_CALL(mock_memory, ReadByte(0x0010)).WillOnce(Return(0x81));
cpu.ExecuteInstruction(0x24); // BIT
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetOverflowFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, BIT_AbsoluteIndexedX) {
cpu.A = 0x01;
cpu.X = 0x02;
cpu.PC = 0x0001;
cpu.status = 0xFF;
std::vector<uint8_t> data = {0x00, 0x10}; // BIT
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x0012, {0x81}); // [0x0010] = 0x81
// Read the operand
EXPECT_CALL(mock_memory, ReadWord(0x0001)).WillOnce(Return(0x10));
// Read the value at the address of the operand
EXPECT_CALL(mock_memory, ReadByte(0x0012)).WillOnce(Return(0x81));
cpu.ExecuteInstruction(0x3C); // BIT
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetOverflowFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, BMI_BranchTaken) {
cpu.PC = 0x0000;
cpu.SetNegativeFlag(true);
std::vector<uint8_t> data = {0x02}; // BMI
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x30); // BMI
EXPECT_EQ(cpu.PC, 0x0002);
}
TEST_F(CPUTest, BMI_BranchNotTaken) {
cpu.PC = 0x0000;
cpu.SetNegativeFlag(false);
std::vector<uint8_t> data = {0x30, 0x02}; // BMI
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x30); // BMI
EXPECT_EQ(cpu.PC, 0x0000);
}
TEST_F(CPUTest, BNE_BranchTaken) {
cpu.PC = 0x0000;
cpu.SetZeroFlag(false);
std::vector<uint8_t> data = {0x02}; // BNE
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xD0); // BNE
EXPECT_EQ(cpu.PC, 0x0002);
}
TEST_F(CPUTest, BNE_BranchNotTaken) {
cpu.PC = 0x0000;
cpu.SetZeroFlag(true);
std::vector<uint8_t> data = {0xD0, 0x02}; // BNE
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xD0); // BNE
EXPECT_EQ(cpu.PC, 0x0000);
}
TEST_F(CPUTest, BPL_BranchTaken) {
cpu.PC = 0x0000;
cpu.SetNegativeFlag(false);
std::vector<uint8_t> data = {0x02}; // BPL
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x10); // BPL
EXPECT_EQ(cpu.PC, 0x0002);
}
TEST_F(CPUTest, BPL_BranchNotTaken) {
cpu.PC = 0x0000;
cpu.SetNegativeFlag(true);
std::vector<uint8_t> data = {0x10, 0x02}; // BPL
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x10); // BPL
EXPECT_EQ(cpu.PC, 0x0000);
}
TEST_F(CPUTest, BRA) {
cpu.PC = 0x0000;
std::vector<uint8_t> data = {0x02}; // BRA
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0x80); // BRA
EXPECT_EQ(cpu.PC, 0x0002);
}
TEST_F(CPUTest, BRK) {
cpu.PC = 0x0000;
std::vector<uint8_t> data = {0x00}; // BRK
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0xFFFE, {0x10, 0x20}); // [0xFFFE] = 0x2010
EXPECT_CALL(mock_memory, ReadWord(0xFFFE)).WillOnce(Return(0x2010));
cpu.ExecuteInstruction(0x00); // BRK
EXPECT_EQ(cpu.PC, 0x2010);
EXPECT_TRUE(cpu.GetInterruptFlag());
}
// ============================================================================
// BRL - Branch Long
@@ -446,50 +762,57 @@ TEST_F(CPUTest, BRL) {
}
// ============================================================================
// Test for CPX instruction
TEST_F(CPUTest, CPX_CarryFlagSet) {
cpu.X = 0x1000;
cpu.CPX(0x0F00);
cpu.CPX(0x0FFF);
ASSERT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
}
TEST_F(CPUTest, CPX_ZeroFlagSet) {
cpu.X = 0x0F00;
cpu.SetIndexSize(false); // Set X register to 16-bit mode
cpu.SetAccumulatorSize(false);
cpu.X = 0x1234;
std::vector<uint8_t> data = {0x34, 0x12}; // CPX #0x1234
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE0); // Immediate CPX
ASSERT_TRUE(cpu.GetZeroFlag()); // Zero flag should be set
}
TEST_F(CPUTest, CPX_NegativeFlagSet) {
cpu.PC = 1;
cpu.X = 0x8000;
std::vector<uint8_t> data = {0xE0, 0xFF, 0xFF};
cpu.SetIndexSize(false); // Set X register to 16-bit mode
cpu.PC = 0;
cpu.X = 0x9000;
std::vector<uint8_t> data = {0xE0, 0x01, 0x80}; // CPX #0x8001
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xE0); // Immediate CPX (0xFFFF)
cpu.ExecuteInstruction(0xE0); // Immediate CPX
ASSERT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
// Test for CPY instruction
TEST_F(CPUTest, CPY_CarryFlagSet) {
cpu.Y = 0x1000;
cpu.CPY(0x0F00);
cpu.CPY(0x0FFF);
ASSERT_TRUE(cpu.GetCarryFlag()); // Carry flag should be set
}
TEST_F(CPUTest, CPY_ZeroFlagSet) {
cpu.Y = 0x0F00;
cpu.CPY(0x0F00);
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
cpu.SetAccumulatorSize(false);
cpu.Y = 0x5678;
std::vector<uint8_t> data = {0x78, 0x56}; // CPY #0x5678
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xC0); // Immediate CPY
ASSERT_TRUE(cpu.GetZeroFlag()); // Zero flag should be set
}
TEST_F(CPUTest, CPY_NegativeFlagSet) {
cpu.PC = 1;
cpu.Y = 0x8000;
std::vector<uint8_t> data = {0xC0, 0xFF, 0xFF};
cpu.SetIndexSize(false); // Set Y register to 16-bit mode
cpu.PC = 0;
cpu.Y = 0x9000;
std::vector<uint8_t> data = {0xC0, 0x01, 0x80}; // CPY #0x8001
mock_memory.SetMemoryContents(data);
cpu.ExecuteInstruction(0xC0); // Immediate CPY (0xFFFF)
cpu.ExecuteInstruction(0xC0); // Immediate CPY
ASSERT_TRUE(cpu.GetNegativeFlag()); // Negative flag should be set
}
@@ -498,6 +821,7 @@ TEST_F(CPUTest, CPY_NegativeFlagSet) {
// Test for DEX instruction
TEST_F(CPUTest, DEX) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
cpu.X = 0x02; // Set X register to 2
cpu.ExecuteInstruction(0xCA); // Execute DEX instruction
EXPECT_EQ(0x01, cpu.X); // Expected value of X register after decrementing
@@ -513,6 +837,7 @@ TEST_F(CPUTest, DEX) {
// Test for DEY instruction
TEST_F(CPUTest, DEY) {
cpu.SetIndexSize(true); // Set Y register to 8-bit mode
cpu.Y = 0x02; // Set Y register to 2
cpu.ExecuteInstruction(0x88); // Execute DEY instruction
EXPECT_EQ(0x01, cpu.Y); // Expected value of Y register after decrementing
@@ -530,30 +855,109 @@ TEST_F(CPUTest, DEY) {
// INC - Increment Memory
/**
TEST_F(CPUTest, INC) {
cpu.status &= 0x20;
TEST_F(CPUTest, INC_DirectPage_8bit) {
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xE6, 0x7F, 0x7F};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0x7F)).WillOnce(Return());
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x7F));
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0x80)).WillOnce(Return());
EXPECT_CALL(mock_memory, ReadByte(0x7F)).WillOnce(Return(0x7F));
EXPECT_CALL(mock_memory, WriteByte(0, 0x80)).Times(1);
cpu.WriteByte(0x1000, 0x7F);
cpu.INC(0x1000);
EXPECT_EQ(cpu.ReadByte(0x1000), 0x80);
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xE6); // INC Direct Page
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
EXPECT_CALL(mock_memory, WriteByte(0x1000, 0xFF)).WillOnce(Return());
cpu.WriteByte(0x1000, 0xFF);
cpu.INC(0x1000);
EXPECT_CALL(mock_memory, ReadByte(_)).WillOnce(Return(0x00));
EXPECT_EQ(cpu.ReadByte(0x1000), 0x00);
TEST_F(CPUTest, INC_Absolute_16bit) {
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xEE, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0xFF7F)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, WriteWord(0xFF7F, 0x8000)).Times(1);
cpu.SetAccumulatorSize(false);
cpu.ExecuteInstruction(0xEE); // INC Absolute
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, INC_DirectPage_ZeroResult_8bit) {
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xE6, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(0xFF)).WillOnce(Return(0xFF));
EXPECT_CALL(mock_memory, WriteByte(0xFF, 0x00)).Times(1);
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xE6); // INC Direct Page
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, INC_Absolute_ZeroResult_16bit) {
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xEE, 0xFF, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0xFFFF)).WillOnce(Return(0xFFFF));
EXPECT_CALL(mock_memory, WriteWord(0xFFFF, 0x0000)).Times(1);
cpu.SetAccumulatorSize(false);
cpu.ExecuteInstruction(0xEE); // INC Absolute
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, INC_DirectPage_8bit_Overflow) {
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xE6, 0x80};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(0x80)).WillOnce(Return(0xFF));
EXPECT_CALL(mock_memory, WriteByte(0x80, 0x00)).Times(1);
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xE6); // INC Direct Page
EXPECT_FALSE(cpu.GetNegativeFlag());
EXPECT_TRUE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, INC_DirectPageIndexedX_8bit) {
cpu.PC = 0x1001;
cpu.X = 0x01;
std::vector<uint8_t> data = {0xF6, 0x7E};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(0x7F)).WillOnce(Return(0x7F));
EXPECT_CALL(mock_memory, WriteByte(0x7F, 0x80)).Times(1);
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xF6); // INC DP Indexed, X
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, INC_AbsoluteIndexedX_16bit) {
cpu.PC = 0x1001;
cpu.X = 0x01;
std::vector<uint8_t> data = {0xFE, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadWord(0xFF80)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, WriteWord(0xFF80, 0x8000)).Times(1);
cpu.SetAccumulatorSize(false);
cpu.ExecuteInstruction(0xFE); // INC Absolute Indexed, X
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
*/
TEST_F(CPUTest, INX) {
cpu.SetIndexSize(true); // Set X register to 8-bit mode
cpu.X = 0x7F;
cpu.INX();
EXPECT_EQ(cpu.X, 0x80);
@@ -568,6 +972,7 @@ TEST_F(CPUTest, INX) {
}
TEST_F(CPUTest, INY) {
cpu.SetIndexSize(true); // Set Y register to 8-bit mode
cpu.Y = 0x7F;
cpu.INY();
EXPECT_EQ(cpu.Y, 0x80);
@@ -662,6 +1067,68 @@ TEST_F(CPUTest, JSL_AbsoluteLong) {
EXPECT_EQ(cpu.PC, 0x002005);
}
// ============================================================================
// LDA - Load Accumulator
/**
TEST_F(CPUTest, LDA_Immediate_8bit) {
cpu.PC = 0x1001;
cpu.SetAccumulatorSize(true);
cpu.A = 0x00;
std::vector<uint8_t> data = {0xA9, 0x7F, 0x7F};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7F, {0xAA});
cpu.ExecuteInstruction(0xA9); // LDA Immediate
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, LDA_Immediate_16bit) {
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xA9, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
cpu.SetAccumulatorSize(false);
cpu.ExecuteInstruction(0xA9); // LDA Immediate
EXPECT_EQ(cpu.A, 0xFF7F);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, LDA_DirectPage) {
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xA5, 0x7F};
mock_memory.SetMemoryContents(data);
EXPECT_CALL(mock_memory, ReadByte(0x7F)).WillOnce(Return(0x80));
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xA5); // LDA Direct Page
EXPECT_EQ(cpu.A, 0x80);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
TEST_F(CPUTest, LDA_Absolute) {
cpu.PC = 0x1001;
std::vector<uint8_t> data = {0xAD, 0x7F, 0xFF};
mock_memory.SetMemoryContents(data);
mock_memory.InsertMemory(0x7FFF, {0x7F});
EXPECT_CALL(mock_memory, ReadWord(0x1001)).WillOnce(Return(0x7FFF));
EXPECT_CALL(mock_memory, ReadByte(0x7FFF)).WillOnce(Return(0x7F));
cpu.SetAccumulatorSize(true);
cpu.ExecuteInstruction(0xAD); // LDA Absolute
EXPECT_EQ(cpu.A, 0x7F);
EXPECT_TRUE(cpu.GetNegativeFlag());
EXPECT_FALSE(cpu.GetZeroFlag());
}
*/
// ============================================================================
// Stack Tests