implemented SBC, ADC and BIT family of instruction, .logs match now 73 instructions on nestest

This commit is contained in:
2026-08-08 23:08:20 -05:00
parent c2fd920dae
commit b3557b78d6
3 changed files with 210 additions and 4 deletions
+171 -1
View File
@@ -166,6 +166,24 @@ impl Cpu {
0xC0 => self.cpy_imm(bus),
0xC4 => self.cpy_zp(bus),
0xCC => self.cpy_abs(bus),
0x69 => self.adc_imm(bus),
0x65 => self.adc_zp(bus),
0x75 => self.adc_zpx(bus),
0x6D => self.adc_abs(bus),
0x7D => self.adc_abx(bus),
0x79 => self.adc_aby(bus),
0x61 => self.adc_izx(bus),
0x71 => self.adc_izy(bus),
0xE9 => self.sbc_imm(bus),
0xE5 => self.sbc_zp(bus),
0xF5 => self.sbc_zpx(bus),
0xED => self.sbc_abs(bus),
0xFD => self.sbc_abx(bus),
0xF9 => self.sbc_aby(bus),
0xE1 => self.sbc_izx(bus),
0xF1 => self.sbc_izy(bus),
0x24 => self.bit_zp(bus),
0x2C => self.bit_abs(bus),
_ => panic!("illegal/unkown opcode {opcode:#04X} at {:#06X}", self.pc.wrapping_sub(1)),
};
self.cycles += cycles as u64;
@@ -324,6 +342,46 @@ impl Cpu {
base + extra
}
// shared add/sbc cores (based on adding the complement)
fn add_with_carry(&mut self, value: u8) {
let carry = if self.flag(FLAG_CARRY) { 1u16 } else { 0 };
let sum = self.a as u16 + value as u16 + carry;
let result = sum as u8;
if sum > 0xFF { self.set_flag(FLAG_CARRY); } else { self.clear_flag(FLAG_CARRY); }
if (self.a ^ result) & (value ^ result) & 0x80 != 0 {
self.set_flag(FLAG_OVERFLOW);
} else {
self.clear_flag(FLAG_OVERFLOW);
}
self.set_zp_flags(result);
self.a = result;
}
fn adc(&mut self, bus: &mut impl Bus, (address, extra): (u16, u8), base: u8) -> u8 {
let value = self.read(bus, address);
self.add_with_carry(value); // add as-is
base + extra
}
fn sbc(&mut self, bus: &mut impl Bus, (address, extra): (u16, u8), base: u8) -> u8 {
let value = self.read(bus, address);
self.add_with_carry(!value); // add the complement => subtract
base + extra
}
// BIT core
fn bit(&mut self, bus: &mut impl Bus, (address, extra): (u16, u8), base: u8) -> u8 {
let value = self.read(bus, address);
self.clear_flag(FLAG_ZERO);
if self.a & value == 0 { self.set_flag(FLAG_ZERO); }
self.clear_flag(FLAG_NEGATIVE);
if value & 0x80 != 0 { self.set_flag(FLAG_NEGATIVE); }
self.clear_flag(FLAG_OVERFLOW);
if value & 0x40 != 0 { self.set_flag(FLAG_OVERFLOW); }
base + extra
}
// NES 6502 opcode -> functions
fn jmp_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0x4C, 3 bytes, 3 cycles
@@ -663,7 +721,101 @@ impl Cpu {
2
}
// ADC variants
fn adc_zp(&mut self, bus: &mut impl Bus) -> u8 { // 0x65, 2 bytes, 3 cycles
let (address, extra) = self.address_zp(bus);
self.adc(bus, (address, extra), 3)
}
fn adc_zpx(&mut self, bus: &mut impl Bus) -> u8 { // 0x75, 2 bytes, 4 cycles
let (address, extra) = self.address_zpx(bus);
self.adc(bus, (address, extra), 4)
}
fn adc_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0x6D, 3 bytes, 4 cycles
let (address, extra) = self.address_abs(bus);
self.adc(bus, (address, extra), 4)
}
fn adc_abx(&mut self, bus: &mut impl Bus) -> u8 { // 0x7D, 3 bytes, 4 cycles
let (address, extra) = self.address_abx(bus);
self.adc(bus, (address, extra), 4)
}
fn adc_aby(&mut self, bus: &mut impl Bus) -> u8 { // 0x79, 3 bytes, 4 cycles
let (address, extra) = self.address_aby(bus);
self.adc(bus, (address, extra), 4)
}
fn adc_izx(&mut self, bus: &mut impl Bus) -> u8 { // 0x61, 2 bytes, 6 cycles
let (address, extra) = self.address_izx(bus);
self.adc(bus, (address, extra), 6)
}
fn adc_izy(&mut self, bus: &mut impl Bus) -> u8 { // 0x71, 2 bytes, 5 cycles
let (address, extra) = self.address_izy(bus);
self.adc(bus, (address, extra), 5)
}
// SBC variants
fn sbc_zp(&mut self, bus: &mut impl Bus) -> u8 { // 0xE5, 2 bytes, 3 cycles
let (address, extra) = self.address_zp(bus);
self.sbc(bus, (address, extra), 3)
}
fn sbc_zpx(&mut self, bus: &mut impl Bus) -> u8 { // 0xF5, 2 bytes, 4 cycles
let (address, extra) = self.address_zpx(bus);
self.sbc(bus, (address, extra), 4)
}
fn sbc_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0xED, 3 bytes, 4 cycles
let (address, extra) = self.address_abs(bus);
self.sbc(bus, (address, extra), 4)
}
fn sbc_abx(&mut self, bus: &mut impl Bus) -> u8 { // 0xFD, 3 bytes, 4 cycles
let (address, extra) = self.address_abx(bus);
self.sbc(bus, (address, extra), 4)
}
fn sbc_aby(&mut self, bus: &mut impl Bus) -> u8 { // 0xF9, 3 bytes, 4 cycles
let (address, extra) = self.address_aby(bus);
self.sbc(bus, (address, extra), 4)
}
fn sbc_izx(&mut self, bus: &mut impl Bus) -> u8 { // 0xE1, 2 bytes, 6 cycles
let (address, extra) = self.address_izx(bus);
self.sbc(bus, (address, extra), 6)
}
fn sbc_izy(&mut self, bus: &mut impl Bus) -> u8 { // 0xF1, 2 bytes, 5 cycles
let (address, extra) = self.address_izy(bus);
self.sbc(bus, (address, extra), 5)
}
// BIT variants
fn bit_zp(&mut self, bus: &mut impl Bus) -> u8 { // 0x24, 2 bytes, 3 cycles
let (address, extra) = self.address_zp(bus);
self.bit(bus, (address, extra), 3)
}
fn bit_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0x2C, 3 bytes, 4 cycles
let (address, extra) = self.address_abs(bus);
self.bit(bus, (address, extra), 4)
}
// ADC/SBC immediate variants
fn adc_imm(&mut self, bus: &mut impl Bus) -> u8 { // 0x69, 2 bytes, 2 cycles
let value = self.fetch(bus);
self.add_with_carry(value);
2
}
fn sbc_imm(&mut self, bus: &mut impl Bus) -> u8 { // 0xE9, 2 bytes, 2 cycles
let value = self.fetch(bus);
self.add_with_carry(!value);
2
}
// all branching alternatives here all 1 bytes
fn bcs_rel(&mut self, bus: &mut impl Bus) -> u8 { self.branch(bus, self.flag(FLAG_CARRY)) } // 0xB0
@@ -748,6 +900,24 @@ impl Cpu {
0xC0 => 2, // CPY imm
0xC4 => 2, // CPY zp
0xCC => 3, // CPY abs
0x69 => 2, // ADC imm
0x65 => 2, // ADC zp
0x75 => 2, // ADC zpx
0x6D => 3, // ADC abs
0x7D => 3, // ADC abx
0x79 => 3, // ADC aby
0x61 => 2, // ADC izx
0x71 => 2, // ADC izy
0xE9 => 2, // SBC imm
0xE5 => 2, // SBC zp
0xF5 => 2, // SBC zpx
0xED => 3, // SBC abs
0xFD => 3, // SBC abx
0xF9 => 3, // SBC aby
0xE1 => 2, // SBC izx
0xF1 => 2, // SBC izy
0x24 => 2, // BIT zp
0x2C => 3, // BIT abs
_ => 1, // fallback, would show the invalid/unknown opcode only not its parameters
}
}