changed format of match tables to use 4 matches per line to have a more compact layout

This commit is contained in:
2026-08-08 23:26:31 -05:00
parent b3557b78d6
commit 91f8fd0f4e
2 changed files with 71 additions and 184 deletions
+4 -3
View File
@@ -24,10 +24,11 @@
- Batch 1 done (subroutines + stack): JSR, RTS, PHA, PLA, PHP, PLP, RTI, BRK, plus NOP and SEC as quick wins. Verified SP:FD->FB across JSR (push high-then-low works) - Batch 1 done (subroutines + stack): JSR, RTS, PHA, PLA, PHP, PLP, RTI, BRK, plus NOP and SEC as quick wins. Verified SP:FD->FB across JSR (push high-then-low works)
- Batch 2 done (branches): all 8 branches (BEQ/BNE/BCC/BCS/BPL/BMI/BVC/BVS) via one shared branch() routine with condition param. Taken = +3 cycles, page-cross = +1 more. Verified both taken and not-taken paths in the log - Batch 2 done (branches): all 8 branches (BEQ/BNE/BCC/BCS/BPL/BMI/BVC/BVS) via one shared branch() routine with condition param. Taken = +3 cycles, page-cross = +1 more. Verified both taken and not-taken paths in the log
- Flag set/clear ops done (part of Batch 10): CLC, CLI, CLV, CLD, SEI, SED (SEC done in Batch 1). SEI/SED set, the rest clear. Fixed a real bug where SEI/SED were clearing instead of setting - Flag set/clear ops done (part of Batch 10): CLC, CLI, CLV, CLD, SEI, SED (SEC done in Batch 1). SEI/SED set, the rest clear. Fixed a real bug where SEI/SED were clearing instead of setting
- Trace now matches the nestest reference log through line 38 (C782 BIT, CYC:98), field-for-field (PC/A/X/Y/P/SP/CYC verified by label-comparison script). Next panic is on 0x24 (BIT zp) at line 38, top of Batch 6 - Trace now matches the nestest reference log through line 73 (C7E9 AND, CYC:192), field-for-field (PC/A/X/Y/P/SP/CYC verified by label-comparison script). Next panic is on 0x29 (AND imm) at line 73, top of Batch 7
- Batch 3 done (loads): LDA (8 modes), LDX (5 modes), LDY (5 modes) via three shared cores (lda/ldx/ldy) + thin wrappers. Caught two real bugs in review: all 4 LDY wrappers called self.ldx (would write to X instead of Y), and 6 of 8 LDX/LDY wrappers had wrong base cycles (3 instead of 4). Both fixed - Batch 3 done (loads): LDA (8 modes), LDX (5 modes), LDY (5 modes) via three shared cores (lda/ldx/ldy) + thin wrappers. Caught two real bugs in review: all 4 LDY wrappers called self.ldx (would write to X instead of Y), and 6 of 8 LDX/LDY wrappers had wrong base cycles (3 instead of 4). Both fixed
- Batch 4 done (stores): STA (7 modes), STX (3 modes), STY (3 modes) via three shared cores (sta/stx/sty) + thin wrappers. No flag changes. Refactored stx_zp to use the shared stx core for consistency. Fixed a comment typo (sta_abx was labeled 0x95 instead of 0x9D) - Batch 4 done (stores): STA (7 modes), STX (3 modes), STY (3 modes) via three shared cores (sta/stx/sty) + thin wrappers. No flag changes. Refactored stx_zp to use the shared stx core for consistency. Fixed a comment typo (sta_abx was labeled 0x95 instead of 0x9D)
- Batch 5 done (compares): CMP (8 modes), CPX (3 modes), CPY (3 modes) via three shared cores (cmp/cpx/cpy) + wrappers + immediate variants. Sets C (reg >= mem), Z, N; no store. Uses wrapping_sub for the borrow math. 70 of 151 official opcodes done. No diff progress expected until the log reaches these opcodes - Batch 5 done (compares): CMP (8 modes), CPX (3 modes), CPY (3 modes) via three shared cores (cmp/cpx/cpy) + wrappers + immediate variants. Sets C (reg >= mem), Z, N; no store. Uses wrapping_sub for the borrow math. 70 of 151 official opcodes done. No diff progress expected until the log reaches these opcodes
- Batch 6 done (arithmetic): ADC (8 modes), SBC (8 modes), BIT (2 modes) via shared add_with_carry core + adc/sbc/bit cores + wrappers. SBC adds the one's complement (A + ~mem + C), which makes the V-flag math correct. Decimal flag inert (binary only). 88 of 151 official opcodes done. Big diff progress: BIT/PHP/PLA/PHA carried the log from 38 to 73 lines
- trace bytes are length-aware via opcode_len (fixed-width byte field, columns align for awk diff) - trace bytes are length-aware via opcode_len (fixed-width byte field, columns align for awk diff)
## Next ## Next
@@ -41,8 +42,8 @@ CPU implementation batches (by family, ordered by nestest log frequency):
- Batch 3 - DONE (loads, see Done section) - Batch 3 - DONE (loads, see Done section)
- Batch 4 - DONE (stores, see Done section) - Batch 4 - DONE (stores, see Done section)
- Batch 5 - DONE (compares, see Done section) - Batch 5 - DONE (compares, see Done section)
- Batch 6 - Arithmetic: ADC 8 modes, SBC 8 modes (N/V/C/Z, decimal flag inert), BIT 2 modes. Next up - Batch 6 - DONE (arithmetic, see Done section)
- Batch 7 - Logic: AND, ORA, EOR (8 modes each) - Batch 7 - Logic: AND, ORA, EOR (8 modes each). Next up
- Batch 8 - Inc/Dec: INC/DEC 4 modes each (RMW), INX, INY, DEX, DEY - Batch 8 - Inc/Dec: INC/DEC 4 modes each (RMW), INX, INY, DEX, DEY
- Batch 9 - Shifts: ASL, LSR, ROL, ROR (accumulator + 4 memory modes each, RMW) - Batch 9 - Shifts: ASL, LSR, ROL, ROR (accumulator + 4 memory modes each, RMW)
- Batch 10 - PARTIAL: flag ops done (CLC/CLI/CLV/CLD/SEI/SED, plus SEC/NOP). Remaining: JMP ind 6C, transfers TAX/TAY/TXA/TYA/TSX/TXS - Batch 10 - PARTIAL: flag ops done (CLC/CLI/CLV/CLD/SEI/SED, plus SEC/NOP). Remaining: JMP ind 6C, transfers TAX/TAY/TXA/TYA/TSX/TXS
+67 -181
View File
@@ -96,100 +96,81 @@ impl Cpu {
pub fn step(&mut self, bus: &mut impl Bus) -> u8 { pub fn step(&mut self, bus: &mut impl Bus) -> u8 {
let opcode: u8 = self.fetch(bus); let opcode: u8 = self.fetch(bus);
let cycles = match opcode { let cycles = match opcode {
0x4C => self.jmp_abs(bus), // Jumps & subroutines
0xA2 => self.ldx_imm(bus), 0x4C => self.jmp_abs(bus), 0x20 => self.jsr_abs(bus), 0x60 => self.rts_imp(bus),
0x86 => self.stx_zp(bus), 0x40 => self.rti_imp(bus), 0x00 => self.brk_imp(bus),
0x20 => self.jsr_abs(bus), // Stack
0x60 => self.rts_imp(bus), 0x48 => self.pha_imp(bus), 0x68 => self.pla_imp(bus), 0x08 => self.php_imp(bus),
0x48 => self.pha_imp(bus),
0x68 => self.pla_imp(bus),
0x08 => self.php_imp(bus),
0x28 => self.plp_imp(bus), 0x28 => self.plp_imp(bus),
0x40 => self.rti_imp(bus), // Flags & misc
0x00 => self.brk_imp(bus), 0x38 => self.sec_imp(bus), 0x18 => self.clc_imp(bus), 0x58 => self.cli_imp(bus),
0xEA => self.nop_imp(bus), 0x78 => self.sei_imp(bus), 0xD8 => self.cld_imp(bus), 0xF8 => self.sed_imp(bus),
0x38 => self.sec_imp(bus), 0xB8 => self.clv_imp(bus), 0xEA => self.nop_imp(bus),
0x90 => self.bcc_rel(bus), // Branches
0xB0 => self.bcs_rel(bus), 0x90 => self.bcc_rel(bus), 0xB0 => self.bcs_rel(bus), 0xF0 => self.beq_rel(bus),
0xF0 => self.beq_rel(bus), 0xD0 => self.bne_rel(bus), 0x10 => self.bpl_rel(bus), 0x30 => self.bmi_rel(bus),
0xD0 => self.bne_rel(bus), 0x50 => self.bvc_rel(bus), 0x70 => self.bvs_rel(bus),
0x10 => self.bpl_rel(bus), // Loads
0x30 => self.bmi_rel(bus), 0xA9 => self.lda_imm(bus), 0xA5 => self.lda_zp(bus), 0xB5 => self.lda_zpx(bus),
0x50 => self.bvc_rel(bus), 0xAD => self.lda_abs(bus), 0xBD => self.lda_abx(bus), 0xB9 => self.lda_aby(bus),
0x70 => self.bvs_rel(bus), 0xA1 => self.lda_izx(bus), 0xB1 => self.lda_izy(bus), 0xA2 => self.ldx_imm(bus),
0x18 => self.clc_imp(bus), 0xA6 => self.ldx_zp(bus), 0xB6 => self.ldx_zpy(bus), 0xAE => self.ldx_abs(bus),
0x58 => self.cli_imp(bus), 0xBE => self.ldx_aby(bus), 0xA0 => self.ldy_imm(bus), 0xA4 => self.ldy_zp(bus),
0xB8 => self.clv_imp(bus), 0xB4 => self.ldy_zpx(bus), 0xAC => self.ldy_abs(bus), 0xBC => self.ldy_abx(bus),
0xD8 => self.cld_imp(bus), // Stores
0x78 => self.sei_imp(bus), 0x85 => self.sta_zp(bus), 0x95 => self.sta_zpx(bus), 0x8D => self.sta_abs(bus),
0xF8 => self.sed_imp(bus), 0x9D => self.sta_abx(bus), 0x99 => self.sta_aby(bus), 0x81 => self.sta_izx(bus),
0xA9 => self.lda_imm(bus), 0x91 => self.sta_izy(bus), 0x86 => self.stx_zp(bus), 0x96 => self.stx_zpy(bus),
0xA5 => self.lda_zp(bus), 0x8E => self.stx_abs(bus), 0x84 => self.sty_zp(bus), 0x94 => self.sty_zpx(bus),
0xB5 => self.lda_zpx(bus),
0xAD => self.lda_abs(bus),
0xBD => self.lda_abx(bus),
0xB9 => self.lda_aby(bus),
0xA1 => self.lda_izx(bus),
0xB1 => self.lda_izy(bus),
0xA6 => self.ldx_zp(bus),
0xB6 => self.ldx_zpy(bus),
0xAE => self.ldx_abs(bus),
0xBE => self.ldx_aby(bus),
0xA0 => self.ldy_imm(bus),
0xA4 => self.ldy_zp(bus),
0xB4 => self.ldy_zpx(bus),
0xAC => self.ldy_abs(bus),
0xBC => self.ldy_abx(bus),
0x85 => self.sta_zp(bus),
0x95 => self.sta_zpx(bus),
0x8D => self.sta_abs(bus),
0x9D => self.sta_abx(bus),
0x99 => self.sta_aby(bus),
0x81 => self.sta_izx(bus),
0x91 => self.sta_izy(bus),
0x96 => self.stx_zpy(bus),
0x8E => self.stx_abs(bus),
0x84 => self.sty_zp(bus),
0x94 => self.sty_zpx(bus),
0x8C => self.sty_abs(bus), 0x8C => self.sty_abs(bus),
0xC9 => self.cmp_imm(bus), // Compares
0xC5 => self.cmp_zp(bus), 0xC9 => self.cmp_imm(bus), 0xC5 => self.cmp_zp(bus), 0xD5 => self.cmp_zpx(bus),
0xD5 => self.cmp_zpx(bus), 0xCD => self.cmp_abs(bus), 0xDD => self.cmp_abx(bus), 0xD9 => self.cmp_aby(bus),
0xCD => self.cmp_abs(bus), 0xC1 => self.cmp_izx(bus), 0xD1 => self.cmp_izy(bus), 0xE0 => self.cpx_imm(bus),
0xDD => self.cmp_abx(bus), 0xE4 => self.cpx_zp(bus), 0xEC => self.cpx_abs(bus), 0xC0 => self.cpy_imm(bus),
0xD9 => self.cmp_aby(bus), 0xC4 => self.cpy_zp(bus), 0xCC => self.cpy_abs(bus),
0xC1 => self.cmp_izx(bus), // Arithmetic
0xD1 => self.cmp_izy(bus), 0x69 => self.adc_imm(bus), 0x65 => self.adc_zp(bus), 0x75 => self.adc_zpx(bus),
0xE0 => self.cpx_imm(bus), 0x6D => self.adc_abs(bus), 0x7D => self.adc_abx(bus), 0x79 => self.adc_aby(bus),
0xE4 => self.cpx_zp(bus), 0x61 => self.adc_izx(bus), 0x71 => self.adc_izy(bus), 0xE9 => self.sbc_imm(bus),
0xEC => self.cpx_abs(bus), 0xE5 => self.sbc_zp(bus), 0xF5 => self.sbc_zpx(bus), 0xED => self.sbc_abs(bus),
0xC0 => self.cpy_imm(bus), 0xFD => self.sbc_abx(bus), 0xF9 => self.sbc_aby(bus), 0xE1 => self.sbc_izx(bus),
0xC4 => self.cpy_zp(bus), 0xF1 => self.sbc_izy(bus), 0x24 => self.bit_zp(bus), 0x2C => self.bit_abs(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)), _ => panic!("illegal/unkown opcode {opcode:#04X} at {:#06X}", self.pc.wrapping_sub(1)),
}; };
self.cycles += cycles as u64; self.cycles += cycles as u64;
cycles cycles
} }
// NES 6502 opcode length table/matcher
pub fn opcode_len(opcode: u8) -> u8 {
match opcode {
0x4C => 3, /* JMP abs */ 0xA2 => 2, /* LDX imm */ 0x86 => 2, /* STX zp */ 0x20 => 3, /* JSR abs */
0x60 => 1, /* RTS imp */ 0x48 => 1, /* PHA imp */ 0x68 => 1, /* PLA imp */ 0x08 => 1, /* PHP imp */
0x28 => 1, /* PLP imp */ 0x40 => 1, /* RTI imp */ 0x00 => 1, /* BRK imp */ 0xEA => 1, /* NOP */
0x38 => 1, /* SEC imp */ 0x18 => 1, /* CLC imp */ 0x58 => 1, /* CLI imp */ 0x78 => 1, /* SEI imp */
0xD8 => 1, /* CLD imp */ 0xF8 => 1, /* SED imp */ 0xB8 => 1, /* CLV imp */ 0x90 => 2, /* BCC rel */
0xB0 => 2, /* BCS rel */ 0xF0 => 2, /* BEQ rel */ 0xD0 => 2, /* BNE rel */ 0x10 => 2, /* BPL rel */
0x30 => 2, /* BMI rel */ 0x50 => 2, /* BVC rel */ 0x70 => 2, /* BVS rel */ 0xA9 => 2, /* LDA imm */
0xA5 => 2, /* LDA zp */ 0xB5 => 2, /* LDA zpx */ 0xAD => 3, /* LDA abs */ 0xBD => 3, /* LDA abx */
0xB9 => 3, /* LDA aby */ 0xA1 => 2, /* LDA izx */ 0xB1 => 2, /* LDA izy */ 0xA6 => 2, /* LDX zp */
0xB6 => 2, /* LDX zpy */ 0xAE => 3, /* LDX abs */ 0xBE => 3, /* LDX aby */ 0xA0 => 2, /* LDY imm */
0xA4 => 2, /* LDY zp */ 0xB4 => 2, /* LDY zpx */ 0xAC => 3, /* LDY abs */ 0xBC => 3, /* LDY abx */
0x85 => 2, /* STA zp */ 0x95 => 2, /* STA zpx */ 0x8D => 3, /* STA abs */ 0x9D => 3, /* STA abx */
0x99 => 3, /* STA aby */ 0x81 => 2, /* STA izx */ 0x91 => 2, /* STA izy */ 0x96 => 2, /* STX zpy */
0x8E => 3, /* STX abs */ 0x84 => 2, /* STY zp */ 0x94 => 2, /* STY zpx */ 0x8C => 3, /* STY abs */
0xC9 => 2, /* CMP imm */ 0xC5 => 2, /* CMP zp */ 0xD5 => 2, /* CMP zpx */ 0xCD => 3, /* CMP abs */
0xDD => 3, /* CMP abx */ 0xD9 => 3, /* CMP aby */ 0xC1 => 2, /* CMP izx */ 0xD1 => 2, /* CMP izy */
0xE0 => 2, /* CPX imm */ 0xE4 => 2, /* CPX zp */ 0xEC => 3, /* CPX abs */ 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
}
}
// Trace for testing the cpu // Trace for testing the cpu
pub fn trace(&self, bus: &mut impl Bus) -> String { pub fn trace(&self, bus: &mut impl Bus) -> String {
let opcode: u8 = bus.read(self.pc); let opcode: u8 = bus.read(self.pc);
@@ -827,100 +808,5 @@ impl Cpu {
fn bvc_rel(&mut self, bus: &mut impl Bus) -> u8 { self.branch(bus, !self.flag(FLAG_OVERFLOW)) } // 0x50 fn bvc_rel(&mut self, bus: &mut impl Bus) -> u8 { self.branch(bus, !self.flag(FLAG_OVERFLOW)) } // 0x50
fn bvs_rel(&mut self, bus: &mut impl Bus) -> u8 { self.branch(bus, self.flag(FLAG_OVERFLOW)) } //0x70 fn bvs_rel(&mut self, bus: &mut impl Bus) -> u8 { self.branch(bus, self.flag(FLAG_OVERFLOW)) } //0x70
// NES 6502 opcode length table/matcher
pub fn opcode_len(opcode: u8) -> u8 {
match opcode {
0x4C => 3, // JMP abs
0xA2 => 2, // LDX imm
0x86 => 2, // STX zp
0x20 => 3, // JSR abs
0x60 => 1, // RTS imp
0x48 => 1, // PHA imp
0x68 => 1, // PLA imp
0x08 => 1, // PHP imp
0x28 => 1, // PLP imp
0x40 => 1, // RTI imp
0x00 => 1, // BRK imp
0xEA => 1, // NOP
0x38 => 1, // SEC imp
0x90 => 2, // BCC rel
0xB0 => 2, // BCS rel
0xF0 => 2, // BEQ rel
0xD0 => 2, // BNE rel
0x10 => 2, // BPL rel
0x30 => 2, // BMI rel
0x50 => 2, // BVC rel
0x70 => 2, // BVS rel
0x18 => 1, // CLC imp
0x58 => 1, // CLI imp
0xB8 => 1, // CLV imp
0xD8 => 1, // CLD imp
0x78 => 1, // SEI imp
0xF8 => 1, // SED imp
0xA9 => 2, // LDA imm
0xA5 => 2, // LDA zp
0xB5 => 2, // LDA zpx
0xAD => 3, // LDA abs
0xBD => 3, // LDA abx
0xB9 => 3, // LDA aby
0xA1 => 2, // LDA izx
0xB1 => 2, // LDA izy
0xA6 => 2, // LDX zp
0xB6 => 2, // LDX zpy
0xAE => 3, // LDX abs
0xBE => 3, // LDX aby
0xA0 => 2, // LDY imm
0xA4 => 2, // LDY zp
0xB4 => 2, // LDY zpx
0xAC => 3, // LDY abs
0xBC => 3, // LDY abx
0x85 => 2, // STA zp
0x95 => 2, // STA zpx
0x8D => 3, // STA abs
0x9D => 3, // STA abx
0x99 => 3, // STA aby
0x81 => 2, // STA izx
0x91 => 2, // STA izy
0x96 => 2, // STX zpy
0x8E => 3, // STX abs
0x84 => 2, // STY zp
0x94 => 2, // STY zpx
0x8C => 3, // STY abs
0xC9 => 2, // CMP imm
0xC5 => 2, // CMP zp
0xD5 => 2, // CMP zpx
0xCD => 3, // CMP abs
0xDD => 3, // CMP abx
0xD9 => 3, // CMP aby
0xC1 => 2, // CMP izx
0xD1 => 2, // CMP izy
0xE0 => 2, // CPX imm
0xE4 => 2, // CPX zp
0xEC => 3, // CPX abs
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
}
}
} }