Implement ADC Instructions. Decimal mode may need some work.

This commit is contained in:
2025-07-23 09:05:32 -04:00
parent cc1439843e
commit 748cb6e43d
2 changed files with 405 additions and 0 deletions

View File

@@ -142,9 +142,86 @@ uint16_t CPU::PopWord() {
return (high << 8) | low; return (high << 8) | low;
} }
void CPU::DoADC(uint16_t value) {
uint32_t result;
if (P & FLAG_M) {
// 8-bit mode
const uint8_t acc_low = A & 0xFF;
const uint8_t val_low = value & 0xFF;
if (P & FLAG_D) {
// Decimal mode
result = acc_low + val_low + (P & FLAG_C ? 1 : 0);
result = AdjustDecimal(result, false);
} else {
// Binary mode
result = acc_low + val_low + (P & FLAG_C ? 1 : 0);
}
P = (P & ~FLAG_C) | (result > 0xFF ? FLAG_C : 0);
P = (P & ~FLAG_V) | (((acc_low ^ result) & (val_low ^ result) & 0x80) ? FLAG_V : 0);
A = (A & 0xFF00) | (result & 0xFF);
UpdateNZ8(A & 0xFF);
} else {
// 16-bit mode
if (P & FLAG_D) {
// Decimal mode
result = A + value + (P & FLAG_C ? 1 : 0);
result = AdjustDecimal(result, true);
} else {
// Binary mode
result = A + value + (P & FLAG_C ? 1 : 0);
}
P = (P & ~FLAG_C) | (result > 0xFFFF ? FLAG_C : 0);
P = (P & ~FLAG_V) | (((A ^ result) & (value ^ result) & 0x8000) ? FLAG_V : 0);
A = result & 0xFFFF;
UpdateNZ16(A);
}
}
uint16_t CPU::AdjustDecimal(const uint16_t binary_result, const bool is_16bit) {
//TODO: Make sure this works? I'm not sure I understand.
if (is_16bit) {
// 16-bit decimal adjustment
uint16_t result = binary_result;
if ((result & 0x0F) > 0x09) result += 0x06;
if ((result & 0xF0) > 0x90) result += 0x60;
if ((result & 0x0F00) > 0x0900) result += 0x0600;
if ((result & 0xF000) > 0x9000) result += 0x6000;
return result;
}
// 8-bit decimal adjustment
uint16_t result = binary_result;
if ((result & 0x0F) > 0x09) result += 0x06;
if ((result & 0xF0) > 0x90) result += 0x60;
return result;
}
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++)) {
// ADC - Add with Carry
case 0x69: ADC_Immediate(); break; // ADC #$nn/#$nnnn
case 0x6D: ADC_Absolute(); break; // ADC $nnnn
case 0x7D: ADC_AbsoluteX(); break; // ADC $nnnn,X
case 0x79: ADC_AbsoluteY(); break; // ADC $nnnn,Y
case 0x6F: ADC_AbsoluteLong(); break; // ADC $nnnnnn
case 0x7F: ADC_AbsoluteLongX(); break; // ADC $nnnnnn,X
case 0x65: ADC_DirectPage(); break; // ADC $nn
case 0x75: ADC_DirectPageX(); break; // ADC $nn,X
case 0x72: ADC_IndirectDirectPage(); break; // ADC ($nn)
case 0x71: ADC_IndirectDirectPageY(); break; // ADC ($nn),Y
case 0x61: ADC_DirectPageIndirectX(); break; // ADC ($nn,X)
case 0x67: ADC_DirectPageIndirectLong(); break; // ADC [$nn]
case 0x77: ADC_DirectPageIndirectLongY(); break;// ADC [$nn],Y
case 0x63: ADC_StackRelative(); break; // ADC $nn,S
case 0x73: ADC_StackRelativeIndirectY(); break; // ADC ($nn,S),Y
// Branch Instructions // Branch Instructions
case 0xF0: BEQ_Relative(); break; // BEQ $nn case 0xF0: BEQ_Relative(); break; // BEQ $nn
case 0xD0: BNE_Relative(); break; // BNE $nn case 0xD0: BNE_Relative(); break; // BNE $nn
@@ -1743,4 +1820,310 @@ void CPU::PLD() {
void CPU::PHK() { void CPU::PHK() {
PushByte(PB); PushByte(PB);
cycles += 3; cycles += 3;
}
void CPU::ADC_Immediate() {
if (P & FLAG_M) {
// 8-bit immediate
const uint8_t value = ReadByte(PC);
PC++;
DoADC(value);
cycles += 2;
} else {
// 16-bit immediate
const uint16_t value = ReadWord(PC);
PC += 2;
DoADC(value);
cycles += 3;
}
}
void CPU::ADC_Absolute() {
const uint16_t address = ReadWord(PC);
PC += 2;
const uint32_t full_address = (static_cast<uint32_t>(DB) << 16) | address;
if (P & FLAG_M) {
const uint8_t value = ReadByte(full_address);
DoADC(value);
cycles += 4;
} else {
const uint16_t value = ReadWord(full_address);
DoADC(value);
cycles += 5;
}
}
void CPU::ADC_AbsoluteX() {
const uint16_t base_address = ReadWord(PC);
PC += 2;
const uint32_t full_address = (static_cast<uint32_t>(DB) << 16) | ((base_address + X) & 0xFFFF);
if (P & FLAG_M) {
const uint8_t value = ReadByte(full_address);
DoADC(value);
cycles += 4;
if ((base_address & 0xFF00) != ((base_address + X) & 0xFF00)) {
cycles++;
}
} else {
const uint16_t value = ReadWord(full_address);
DoADC(value);
cycles += 5;
if ((base_address & 0xFF00) != ((base_address + X) & 0xFF00)) {
cycles++;
}
}
}
void CPU::ADC_AbsoluteY() {
const uint16_t base_address = ReadWord(PC);
PC += 2;
const uint32_t full_address = (static_cast<uint32_t>(DB) << 16) | ((base_address + Y) & 0xFFFF);
if (P & FLAG_M) {
const uint8_t value = ReadByte(full_address);
DoADC(value);
cycles += 4;
if ((base_address & 0xFF00) != ((base_address + Y) & 0xFF00)) {
cycles++;
}
} else {
const uint16_t value = ReadWord(full_address);
DoADC(value);
cycles += 5;
if ((base_address & 0xFF00) != ((base_address + Y) & 0xFF00)) {
cycles++;
}
}
}
void CPU::ADC_DirectPage() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t address = D + offset;
if (P & FLAG_M) {
const uint8_t value = ReadByte(address);
DoADC(value);
cycles += 3;
if (D & 0xFF) cycles++;
} else {
const uint16_t value = ReadWord(address);
DoADC(value);
cycles += 4;
if (D & 0xFF) cycles++;
}
}
void CPU::ADC_DirectPageX() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t address = D + offset + X;
if (P & FLAG_M) {
const uint8_t value = ReadByte(address);
DoADC(value);
cycles += 4;
if (D & 0xFF) cycles++;
} else {
const uint16_t value = ReadWord(address);
DoADC(value);
cycles += 5;
if (D & 0xFF) cycles++;
}
}
void CPU::ADC_IndirectDirectPage() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t pointer_address = D + offset;
const uint16_t target_address = ReadWord(pointer_address);
const uint32_t full_address = (static_cast<uint32_t>(DB) << 16) | target_address;
if (P & FLAG_M) {
const uint8_t value = ReadByte(full_address);
DoADC(value);
cycles += 5;
if (D & 0xFF) cycles++;
} else {
const uint16_t value = ReadWord(full_address);
DoADC(value);
cycles += 6;
if (D & 0xFF) cycles++;
}
}
void CPU::ADC_IndirectDirectPageY() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t pointer_address = D + offset;
const uint16_t base_address = ReadWord(pointer_address);
const uint32_t full_address = (static_cast<uint32_t>(DB) << 16) | ((base_address + Y) & 0xFFFF);
if (P & FLAG_M) {
const uint8_t value = ReadByte(full_address);
DoADC(value);
cycles += 5;
if (D & 0xFF) cycles++;
if ((base_address & 0xFF00) != ((base_address + Y) & 0xFF00)) {
cycles++;
}
} else {
const uint16_t value = ReadWord(full_address);
DoADC(value);
cycles += 6;
if (D & 0xFF) cycles++;
if ((base_address & 0xFF00) != ((base_address + Y) & 0xFF00)) {
cycles++;
}
}
}
void CPU::ADC_DirectPageIndirectX() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t pointer_address = D + offset + X;
const uint16_t target_address = ReadWord(pointer_address);
const uint32_t full_address = (static_cast<uint32_t>(DB) << 16) | target_address;
if (P & FLAG_M) {
const uint8_t value = ReadByte(full_address);
DoADC(value);
cycles += 6;
if (D & 0xFF) cycles++;
} else {
const uint16_t value = ReadWord(full_address);
DoADC(value);
cycles += 7;
if (D & 0xFF) cycles++;
}
}
void CPU::ADC_AbsoluteLong() {
const uint16_t addr_low = ReadWord(PC);
PC += 2;
const uint8_t addr_high = ReadByte(PC);
PC++;
const uint32_t full_address = (static_cast<uint32_t>(addr_high) << 16) | addr_low;
if (P & FLAG_M) {
const uint8_t value = ReadByte(full_address);
DoADC(value);
cycles += 5;
} else {
const uint16_t value = ReadWord(full_address);
DoADC(value);
cycles += 6;
}
}
void CPU::ADC_AbsoluteLongX() {
const uint16_t addr_low = ReadWord(PC);
PC += 2;
const uint8_t addr_high = ReadByte(PC);
PC++;
const uint32_t base_address = (static_cast<uint32_t>(addr_high) << 16) | addr_low;
const uint32_t full_address = base_address + X;
if (P & FLAG_M) {
const uint8_t value = ReadByte(full_address);
DoADC(value);
cycles += 5;
} else {
const uint16_t value = ReadWord(full_address);
DoADC(value);
cycles += 6;
}
}
void CPU::ADC_DirectPageIndirectLong() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t pointer_address = D + offset;
const uint16_t addr_low = ReadWord(pointer_address);
const uint8_t addr_high = ReadByte(pointer_address + 2);
const uint32_t target_address = (static_cast<uint32_t>(addr_high) << 16) | addr_low;
if (P & FLAG_M) {
const uint8_t value = ReadByte(target_address);
DoADC(value);
cycles += 6;
if (D & 0xFF) cycles++;
} else {
const uint16_t value = ReadWord(target_address);
DoADC(value);
cycles += 7;
if (D & 0xFF) cycles++;
}
}
void CPU::ADC_DirectPageIndirectLongY() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t pointer_address = D + offset;
const uint16_t addr_low = ReadWord(pointer_address);
const uint8_t addr_high = ReadByte(pointer_address + 2);
const uint32_t base_address = (static_cast<uint32_t>(addr_high) << 16) | addr_low;
const uint32_t target_address = base_address + Y;
if (P & FLAG_M) {
const uint8_t value = ReadByte(target_address);
DoADC(value);
cycles += 6;
if (D & 0xFF) cycles++;
} else {
const uint16_t value = ReadWord(target_address);
DoADC(value);
cycles += 7;
if (D & 0xFF) cycles++;
}
}
void CPU::ADC_StackRelative() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t address = SP + offset;
if (P & FLAG_M) {
const uint8_t value = ReadByte(address);
DoADC(value);
cycles += 4;
} else {
const uint16_t value = ReadWord(address);
DoADC(value);
cycles += 5;
}
}
void CPU::ADC_StackRelativeIndirectY() {
const uint8_t offset = ReadByte(PC);
PC++;
const uint32_t pointer_address = SP + offset;
const uint16_t base_address = ReadWord(pointer_address);
const uint32_t target_address = (static_cast<uint32_t>(DB) << 16) | ((base_address + Y) & 0xFFFF);
if (P & FLAG_M) {
const uint8_t value = ReadByte(target_address);
DoADC(value);
cycles += 7;
} else {
const uint16_t value = ReadWord(target_address);
DoADC(value);
cycles += 8;
}
} }

View File

@@ -69,6 +69,12 @@ public:
uint8_t PopByte(); uint8_t PopByte();
uint16_t PopWord(); uint16_t PopWord();
// Helper method for ADC instructions
void DoADC(uint16_t value);
// Helper method to check for decimal mode adjustment
static uint16_t AdjustDecimal(uint16_t binary_result, bool is_16bit);
// Instruction implementations // Instruction implementations
// TODO: Implement remaining instructions // TODO: Implement remaining instructions
void CMP_Immediate(); void CMP_Immediate();
@@ -184,6 +190,22 @@ public:
void PHD(); void PHD();
void PLD(); void PLD();
void PHK(); void PHK();
void ADC_Immediate();
void ADC_Absolute();
void ADC_AbsoluteX();
void ADC_AbsoluteY();
void ADC_DirectPage();
void ADC_DirectPageX();
void ADC_IndirectDirectPage();
void ADC_IndirectDirectPageY();
void ADC_DirectPageIndirectX();
void ADC_AbsoluteLong();
void ADC_AbsoluteLongX();
void ADC_DirectPageIndirectLong();
void ADC_DirectPageIndirectLongY();
void ADC_StackRelative();
void ADC_StackRelativeIndirectY();
}; };
#endif //CPU_H #endif //CPU_H