all 151 offical opcodes implemented
This commit is contained in:
@@ -24,8 +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 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
|
||||
- Trace now matches the nestest reference log through line 678 (CCBA TAY, CYC:1592), field-for-field (PC/A/X/Y/P/SP/CYC verified by label-comparison script). Next panic is on 0xA8 (TAY) at line 678, a Batch 10 transfer opcode
|
||||
- Batch 8 done (inc/dec): INC (4 modes), DEC (4 modes), INX, INY, DEX, DEY. RMW cores (inc/dec) read-modify-write and correctly return base WITHOUT the page-cross extra (RMW cycles are fixed). Register ops are wrapping_add/sub with Z/N only. 124 of 151 official opcodes done. INY/INX carried the log from 506 to 678 lines
|
||||
- Batch 9 done (shifts): ASL, LSR, ROL, ROR (accumulator + 4 memory modes each) via four shift cores (shift_asl/lsr/rol/ror) + wrappers. ROL/ROR read carry-in before overwriting it. Memory shifts follow the RMW fixed-cycle rule. 144 of 151
|
||||
- Batch 10 done (transfers + JMP ind): TAX, TAY, TXA, TYA, TSX, TXS (all 2 cycles; TXS sets NO flags, the other five set Z/N), plus JMP (0x6C) which finally uses address_ind. Resolved the long-standing address_ind dead-code warning
|
||||
- OFFICIAL CPU COMPLETE: all 151 official opcodes implemented. Trace matches the nestest reference log through line 5003 (entire official section), 0 mismatches. Stops at line 5004 (0x04, first illegal opcode) by design
|
||||
- Fixed a latent Batch 4 bug the log caught at line 3319: the sta core added the page-cross extra, but stores have FIXED cycle counts. Fixed sta core to return base without extra, and corrected bases (sta_abx/sta_aby 5, sta_izy 6). Before the fix the diff had a +1 CYC drift from line 3319 onward
|
||||
- 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 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
|
||||
@@ -36,37 +39,13 @@
|
||||
|
||||
## Next
|
||||
|
||||
Finish the official CPU. Nestest analysis findings: the full 8991-line log tests illegal opcodes too (225 distinct opcodes total; first illegal is 0x04 at line 5004). So the official-only CPU is verified against lines 1-5003, then panics on 0x04 by design. Official opcodes never seen in the log: BRK 0x00, CLI 0x58.
|
||||
Official CPU milestone is COMPLETE (all 151 opcodes, nestest-verified through line 5003). The full 8991-line nestest log tests illegal opcodes too (225 distinct opcodes total; first illegal is 0x04 at line 5004). Official opcodes never seen in the log: BRK 0x00, CLI 0x58.
|
||||
|
||||
CPU implementation batches (by family, ordered by nestest log frequency):
|
||||
|
||||
- Batch 1 - DONE (see Done section)
|
||||
- Batch 2 - DONE (branches, see Done section)
|
||||
- Batch 3 - DONE (loads, see Done section)
|
||||
- Batch 4 - DONE (stores, see Done section)
|
||||
- Batch 5 - DONE (compares, see Done section)
|
||||
- Batch 6 - DONE (arithmetic, see Done section)
|
||||
- Batch 7 - DONE (logic, see Done section)
|
||||
- Batch 8 - DONE (inc/dec, see Done section)
|
||||
- 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. Next in log: TAY (0xA8) at line 678
|
||||
|
||||
Rules for each batch:
|
||||
- Add the opcode's length to opcode_len in the same edit (never let them drift)
|
||||
- Re-diff after each batch (cargo run > ours.log + awk column compare)
|
||||
- Check base cycles per mode, feed page-cross extra into the cycle total
|
||||
|
||||
Verification for this phase:
|
||||
- All 151 official opcodes implemented
|
||||
- Trace matches lines 1-5003 field-for-field (PC/A/X/Y/P/SP/CYC)
|
||||
- cargo build clean
|
||||
- Commit + update STATE.md
|
||||
|
||||
After official CPU is done (follow-ups):
|
||||
- Add MMC1 (mapper 1) to cartridge so blargg official_only.nes / all_instrs.nes can run (authoritative official check)
|
||||
Follow-up options, in any order:
|
||||
- Illegal-opcode phase: implement the undocumented opcodes (0x04 and friends) for the full 8991-line nestest pass. ~76 illegal opcodes present in the log. Reference: nesdev wiki undocumented opcode table
|
||||
- MMC1 (mapper 1) in the cartridge so blargg official_only.nes / all_instrs.nes can run (authoritative official check)
|
||||
- Run blargg mapper-0 suite (coredump, cpu_timing_test, ram_after_reset, registers)
|
||||
- Then the illegal-opcode phase for the full 8991-line nestest pass
|
||||
- Then bus/PPU/timing, GUI (egui + winit) come after the CPU milestone
|
||||
- Then PPU/bus/timing, GUI (egui + winit) come after the CPU milestone
|
||||
|
||||
## Decisions
|
||||
|
||||
|
||||
+245
-9
@@ -98,7 +98,7 @@ impl Cpu {
|
||||
let cycles = match opcode {
|
||||
// Jumps & subroutines
|
||||
0x4C => self.jmp_abs(bus), 0x20 => self.jsr_abs(bus), 0x60 => self.rts_imp(bus),
|
||||
0x40 => self.rti_imp(bus), 0x00 => self.brk_imp(bus),
|
||||
0x40 => self.rti_imp(bus), 0x00 => self.brk_imp(bus), 0x6C => self.jmp_ind(bus),
|
||||
// Stack
|
||||
0x48 => self.pha_imp(bus), 0x68 => self.pla_imp(bus), 0x08 => self.php_imp(bus),
|
||||
0x28 => self.plp_imp(bus),
|
||||
@@ -154,6 +154,19 @@ impl Cpu {
|
||||
// Decrements
|
||||
0xC6 => self.dec_zp(bus), 0xD6 => self.dec_zpx(bus), 0xCE => self.dec_abs(bus),
|
||||
0xDE => self.dec_abx(bus), 0xCA => self.dex_imp(bus), 0x88 => self.dey_imp(bus),
|
||||
// Shifts
|
||||
0x0A => self.asl_acc(bus), 0x06 => self.asl_zp(bus), 0x16 => self.asl_zpx(bus),
|
||||
0x0E => self.asl_abs(bus), 0x1E => self.asl_abx(bus),
|
||||
0x4A => self.lsr_acc(bus), 0x46 => self.lsr_zp(bus), 0x56 => self.lsr_zpx(bus),
|
||||
0x4E => self.lsr_abs(bus), 0x5E => self.lsr_abx(bus),
|
||||
0x2A => self.rol_acc(bus), 0x26 => self.rol_zp(bus), 0x36 => self.rol_zpx(bus),
|
||||
0x2E => self.rol_abs(bus), 0x3E => self.rol_abx(bus),
|
||||
0x6A => self.ror_acc(bus), 0x66 => self.ror_zp(bus), 0x76 => self.ror_zpx(bus),
|
||||
0x6E => self.ror_abs(bus), 0x7E => self.ror_abx(bus),
|
||||
// Transfers
|
||||
0xAA => self.tax_imp(bus), 0xA8 => self.tay_imp(bus), 0x8A => self.txa_imp(bus),
|
||||
0x98 => self.tya_imp(bus), 0xBA => self.tsx_imp(bus), 0x9A => self.txs_imp(bus),
|
||||
|
||||
_ => panic!("illegal/unkown opcode {opcode:#04X} at {:#06X}", self.pc.wrapping_sub(1)),
|
||||
};
|
||||
self.cycles += cycles as u64;
|
||||
@@ -194,6 +207,13 @@ impl Cpu {
|
||||
0xE6 => 2, /* INC zp */ 0xF6 => 2, /* INC zpx */ 0xEE => 3, /* INC abs */ 0xFE => 3, /* INC abx */
|
||||
0xE8 => 1, /* INX imp */ 0xC8 => 1, /* INY imp */ 0xC6 => 2, /* DEC zp */ 0xD6 => 2, /* DEC zpx */
|
||||
0xCE => 3, /* DEC abs */ 0xDE => 3, /* DEC abx */ 0xCA => 1, /* DEX imp */ 0x88 => 1, /* DEY imp */
|
||||
0x0A => 1, /* ASL A */ 0x06 => 2, /* ASL zp */ 0x16 => 2, /* ASL zpx */ 0x0E => 3, /* ASL abs */
|
||||
0x1E => 3, /* ASL abx */ 0x4A => 1, /* LSR A */ 0x46 => 2, /* LSR zp */ 0x56 => 2, /* LSR zpx */
|
||||
0x4E => 3, /* LSR abs */ 0x5E => 3, /* LSR abx */ 0x2A => 1, /* ROL A */ 0x26 => 2, /* ROL zp */
|
||||
0x36 => 2, /* ROL zpx */ 0x2E => 3, /* ROL abs */ 0x3E => 3, /* ROL abx */ 0x6A => 1, /* ROR A */
|
||||
0x66 => 2, /* ROR zp */ 0x76 => 2, /* ROR zpx */ 0x6E => 3, /* ROR abs */ 0x7E => 3, /* ROR abx */
|
||||
0xAA => 1, /* TAX */ 0xA8 => 1, /* TAY */ 0x8A => 1, /* TXA */ 0x98 => 1, /* TYA */
|
||||
0xBA => 1, /* TSX */ 0x9A => 1, /* TXS */ 0x6C => 3, /* JMP ind */
|
||||
_ => 1, // fallback, would show the invalid/unknown opcode only not its parameters
|
||||
}
|
||||
}
|
||||
@@ -309,9 +329,9 @@ impl Cpu {
|
||||
}
|
||||
|
||||
// Shared cores for STx instructions
|
||||
fn sta(&mut self, bus: &mut impl Bus, (address, extra): (u16, u8), base: u8) -> u8 {
|
||||
fn sta(&mut self, bus: &mut impl Bus, (address, _extra): (u16, u8), base: u8) -> u8 {
|
||||
self.write(bus, address, self.a);
|
||||
base + extra
|
||||
base
|
||||
}
|
||||
|
||||
fn stx(&mut self, bus: &mut impl Bus, (address, extra): (u16, u8), base: u8) -> u8 {
|
||||
@@ -430,6 +450,42 @@ impl Cpu {
|
||||
base // NO + extra — RMW cycles are fixed
|
||||
}
|
||||
|
||||
// Shared shifting cores
|
||||
// ASL: arithmetic shift left
|
||||
fn shift_asl(&mut self, value: u8) -> u8 {
|
||||
if value & 0x80 != 0 { self.set_flag(FLAG_CARRY); } else { self.clear_flag(FLAG_CARRY); }
|
||||
let result = value << 1;
|
||||
self.set_zp_flags(result);
|
||||
result
|
||||
}
|
||||
|
||||
// LSR: arithmetic shift right
|
||||
fn shift_lsr(&mut self, value: u8) -> u8 {
|
||||
if value & 0x01 != 0 { self.set_flag(FLAG_CARRY); } else { self.clear_flag(FLAG_CARRY); }
|
||||
let result = value >> 1;
|
||||
self.set_zp_flags(result);
|
||||
result
|
||||
}
|
||||
|
||||
// ROL: rotate left through carry
|
||||
fn shift_rol(&mut self, value: u8) -> u8 {
|
||||
let carry_in = if self.flag(FLAG_CARRY) { 1u8 } else { 0 };
|
||||
if value & 0x80 != 0 { self.set_flag(FLAG_CARRY); } else { self.clear_flag(FLAG_CARRY); }
|
||||
let result = (value << 1) | carry_in;
|
||||
self.set_zp_flags(result);
|
||||
result
|
||||
}
|
||||
|
||||
// ROR: rotate right through carry
|
||||
fn shift_ror(&mut self, value: u8) -> u8 {
|
||||
let carry_in = if self.flag(FLAG_CARRY) { 1u8 } else { 0 };
|
||||
if value & 0x01 != 0 { self.set_flag(FLAG_CARRY); } else { self.clear_flag(FLAG_CARRY); }
|
||||
let result = (value >> 1) | (carry_in << 7);
|
||||
self.set_zp_flags(result);
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
// NES 6502 opcode -> functions
|
||||
fn jmp_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0x4C, 3 bytes, 3 cycles
|
||||
self.pc = self.fetch16(bus);
|
||||
@@ -630,14 +686,14 @@ impl Cpu {
|
||||
self.sta(bus, (address, extra), 4)
|
||||
}
|
||||
|
||||
fn sta_abx(&mut self, bus: &mut impl Bus) -> u8 { // 0x9D, 3 bytes, 4 cycles
|
||||
fn sta_abx(&mut self, bus: &mut impl Bus) -> u8 { // 0x9D, 3 bytes, 4 + 1 cycles
|
||||
let (address, extra) = self.address_abx(bus);
|
||||
self.sta(bus, (address, extra), 4)
|
||||
self.sta(bus, (address, extra), 5)
|
||||
}
|
||||
|
||||
fn sta_aby(&mut self, bus: &mut impl Bus) -> u8 { // 0x99, 3 bytes, 4 cycles
|
||||
fn sta_aby(&mut self, bus: &mut impl Bus) -> u8 { // 0x99, 3 bytes, 4 + 1 cycles
|
||||
let (address, extra) = self.address_aby(bus);
|
||||
self.sta(bus, (address, extra), 4)
|
||||
self.sta(bus, (address, extra), 5)
|
||||
}
|
||||
|
||||
fn sta_izx(&mut self, bus: &mut impl Bus) -> u8 { // 0x81, 2 bytes, 6 cycles
|
||||
@@ -645,9 +701,9 @@ impl Cpu {
|
||||
self.sta(bus, (address, extra), 6)
|
||||
}
|
||||
|
||||
fn sta_izy(&mut self, bus: &mut impl Bus) -> u8 { // 0x91, 2 bytes, 5 cycles
|
||||
fn sta_izy(&mut self, bus: &mut impl Bus) -> u8 { // 0x91, 2 bytes, 6 cycles
|
||||
let (address, extra) = self.address_izy(bus);
|
||||
self.sta(bus, (address, extra), 5)
|
||||
self.sta(bus, (address, extra), 6)
|
||||
}
|
||||
|
||||
// STX variants
|
||||
@@ -1061,6 +1117,186 @@ impl Cpu {
|
||||
2
|
||||
}
|
||||
|
||||
// ASL variants
|
||||
fn asl_acc(&mut self, _bus: &mut impl Bus) -> u8 { // 0x0A, 1 byte, 2 cycles
|
||||
self.a = self.shift_asl(self.a);
|
||||
2
|
||||
}
|
||||
|
||||
fn asl_zp(&mut self, bus: &mut impl Bus) -> u8 { // 0x06, 2 bytes, 5 cycles
|
||||
let (address, _extra) = self.address_zp(bus);
|
||||
let result = self.shift_asl(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
5
|
||||
}
|
||||
|
||||
fn asl_zpx(&mut self, bus: &mut impl Bus) -> u8 { // 0x16, 2 bytes, 6 cycles
|
||||
let (address, _extra) = self.address_zpx(bus);
|
||||
let result = self.shift_asl(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
6
|
||||
}
|
||||
|
||||
fn asl_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0x0E, 3 bytes, 6 cycles
|
||||
let (address, _extra) = self.address_abs(bus);
|
||||
let result = self.shift_asl(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
6
|
||||
}
|
||||
|
||||
fn asl_abx(&mut self, bus: &mut impl Bus) -> u8 { // 0x1E, 3 bytes, 7 cycles
|
||||
let (address, _extra) = self.address_abx(bus);
|
||||
let result = self.shift_asl(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
7
|
||||
}
|
||||
|
||||
// LSR variants
|
||||
fn lsr_acc(&mut self, _bus: &mut impl Bus) -> u8 { // 0x4A, 1 byte, 2 cycles
|
||||
self.a = self.shift_lsr(self.a);
|
||||
2
|
||||
}
|
||||
|
||||
fn lsr_zp(&mut self, bus: &mut impl Bus) -> u8 { // 0x46, 2 bytes, 5 cycles
|
||||
let (address, _extra) = self.address_zp(bus);
|
||||
let result = self.shift_lsr(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
5
|
||||
}
|
||||
|
||||
fn lsr_zpx(&mut self, bus: &mut impl Bus) -> u8 { // 0x56, 2 bytes, 6 cycles
|
||||
let (address, _extra) = self.address_zpx(bus);
|
||||
let result = self.shift_lsr(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
6
|
||||
}
|
||||
|
||||
fn lsr_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0x4E, 3 bytes, 6 cycles
|
||||
let (address, _extra) = self.address_abs(bus);
|
||||
let result = self.shift_lsr(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
6
|
||||
}
|
||||
|
||||
fn lsr_abx(&mut self, bus: &mut impl Bus) -> u8 { // 0x5E, 3 bytes, 7 cycles
|
||||
let (address, _extra) = self.address_abx(bus);
|
||||
let result = self.shift_lsr(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
7
|
||||
}
|
||||
|
||||
// ROL variants
|
||||
fn rol_acc(&mut self, _bus: &mut impl Bus) -> u8 { // 0x2A, 1 byte, 2 cycles
|
||||
self.a = self.shift_rol(self.a);
|
||||
2
|
||||
}
|
||||
|
||||
fn rol_zp(&mut self, bus: &mut impl Bus) -> u8 { // 0x26, 2 bytes, 5 cycles
|
||||
let (address, _extra) = self.address_zp(bus);
|
||||
let result = self.shift_rol(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
5
|
||||
}
|
||||
|
||||
fn rol_zpx(&mut self, bus: &mut impl Bus) -> u8 { // 0x36, 2 bytes, 6 cycles
|
||||
let (address, _extra) = self.address_zpx(bus);
|
||||
let result = self.shift_rol(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
6
|
||||
}
|
||||
|
||||
fn rol_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0x2E, 3 bytes, 6 cycles
|
||||
let (address, _extra) = self.address_abs(bus);
|
||||
let result = self.shift_rol(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
6
|
||||
}
|
||||
|
||||
fn rol_abx(&mut self, bus: &mut impl Bus) -> u8 { // 0x3E, 3 bytes, 7 cycles
|
||||
let (address, _extra) = self.address_abx(bus);
|
||||
let result = self.shift_rol(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
7
|
||||
}
|
||||
|
||||
// ROR variants
|
||||
fn ror_acc(&mut self, _bus: &mut impl Bus) -> u8 { // 0x6A, 1 byte, 2 cycles
|
||||
self.a = self.shift_ror(self.a);
|
||||
2
|
||||
}
|
||||
|
||||
fn ror_zp(&mut self, bus: &mut impl Bus) -> u8 { // 0x66, 2 bytes, 5 cycles
|
||||
let (address, _extra) = self.address_zp(bus);
|
||||
let result = self.shift_ror(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
5
|
||||
}
|
||||
|
||||
fn ror_zpx(&mut self, bus: &mut impl Bus) -> u8 { // 0x76, 2 bytes, 6 cycles
|
||||
let (address, _extra) = self.address_zpx(bus);
|
||||
let result = self.shift_ror(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
6
|
||||
}
|
||||
|
||||
fn ror_abs(&mut self, bus: &mut impl Bus) -> u8 { // 0x6E, 3 bytes, 6 cycles
|
||||
let (address, _extra) = self.address_abs(bus);
|
||||
let result = self.shift_ror(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
6
|
||||
}
|
||||
|
||||
fn ror_abx(&mut self, bus: &mut impl Bus) -> u8 { // 0x7E, 3 bytes, 7 cycles
|
||||
let (address, _extra) = self.address_abx(bus);
|
||||
let result = self.shift_ror(self.read(bus, address));
|
||||
self.write(bus, address, result);
|
||||
7
|
||||
}
|
||||
|
||||
// Transfers (all 1 byte, 2 cycles) TAX/TXx family
|
||||
fn tax_imp(&mut self, _bus: &mut impl Bus) -> u8 { // 0xAA: A -> X
|
||||
self.x = self.a;
|
||||
self.set_zp_flags(self.x);
|
||||
2
|
||||
}
|
||||
|
||||
fn tay_imp(&mut self, _bus: &mut impl Bus) -> u8 { // 0xA8: A -> Y
|
||||
self.y = self.a;
|
||||
self.set_zp_flags(self.y);
|
||||
2
|
||||
}
|
||||
|
||||
fn txa_imp(&mut self, _bus: &mut impl Bus) -> u8 { // 0x8A: X -> A
|
||||
self.a = self.x;
|
||||
self.set_zp_flags(self.a);
|
||||
2
|
||||
}
|
||||
|
||||
fn tya_imp(&mut self, _bus: &mut impl Bus) -> u8 { // 0x98: Y -> A
|
||||
self.a = self.y;
|
||||
self.set_zp_flags(self.a);
|
||||
2
|
||||
}
|
||||
|
||||
fn tsx_imp(&mut self, _bus: &mut impl Bus) -> u8 { // 0xBA: SP -> X
|
||||
self.x = self.sp;
|
||||
self.set_zp_flags(self.x);
|
||||
2
|
||||
}
|
||||
|
||||
fn txs_imp(&mut self, _bus: &mut impl Bus) -> u8 { // 0x9A: X -> SP, NO flags
|
||||
self.sp = self.x;
|
||||
2
|
||||
}
|
||||
|
||||
// JMP indirect
|
||||
fn jmp_ind(&mut self, bus: &mut impl Bus) -> u8 { // 0x6C, 3 bytes, 5 cycles
|
||||
let (addr, _) = self.address_ind(bus);
|
||||
self.pc = addr;
|
||||
5
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
fn bcc_rel(&mut self, bus: &mut impl Bus) -> u8 { self.branch(bus, !self.flag(FLAG_CARRY)) } // 0x90
|
||||
|
||||
Reference in New Issue
Block a user