diff --git a/src/lib.rs b/src/lib.rs index 86019bb..1014f82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -313,8 +313,15 @@ impl NES { Segment::mirror("Mirror of APU & IO", 0x4018, 0x0008, 2), ]; // let mut cur = 0x4020; - assert!(prg_rom.len() <= 0x8000, "Mappers for larger sizes not supported"); - segments.push(Segment::rom("PROG ROM", 0x8000 + (0x8000 - prg_rom.len() as u16), prg_rom)); + assert!( + prg_rom.len() <= 0x8000, + "Mappers for larger sizes not supported" + ); + segments.push(Segment::rom( + "PROG ROM", + 0x8000 + (0x8000 - prg_rom.len() as u16), + prg_rom, + )); Self { cycle: 7, dbg_int: false, @@ -360,7 +367,6 @@ impl NES { } } 0x16 => self.controller.write_joy_strobe(val), - 0x17 => (), // TODO: frame counter control _ => self.apu.write_reg(offset, val), }, }); @@ -631,7 +637,7 @@ impl NES { self.cpu.status.set_negative(self.cpu.x & 0x80 == 0x80); log!("{addr:04X}: LDX ${:02X} | {:02X}", off, self.cpu.x); }), - 0xB6 => inst!("LDX zp,y", 1, |off| { + 0xB6 => inst!("LDX zp,y", 2, |off| { self.cpu.x = self.read_zp_y(off); self.cpu.status.set_zero(self.cpu.x == 0); self.cpu.status.set_negative(self.cpu.x & 0x80 == 0x80); @@ -671,7 +677,7 @@ impl NES { self.cpu.status.set_negative(self.cpu.y & 0x80 == 0x80); log!("{addr:04X}: LDY ${:02X} | {:02X}", off, self.cpu.y); }), - 0xB4 => inst!("LDX zp,x", 1, |off| { + 0xB4 => inst!("LDX zp,x", 2, |off| { self.cpu.y = self.read_zp_x(off); self.cpu.status.set_zero(self.cpu.y == 0); self.cpu.status.set_negative(self.cpu.y & 0x80 == 0x80); @@ -718,7 +724,7 @@ impl NES { self.cpu.a ); }), - 0x9D => inst!("STA abs,x", 1, |low, high| { + 0x9D => inst!("STA abs,x", 2, |low, high| { self.write_abs_x(low, high, self.cpu.a); log!( "{addr:04X}: STA ${:02X}{:02X},x | {:02X}", @@ -727,7 +733,7 @@ impl NES { self.cpu.a ); }), - 0x99 => inst!("STA abs,y", 1, |low, high| { + 0x99 => inst!("STA abs,y", 2, |low, high| { self.write_abs_y(low, high, self.cpu.a); log!( "{addr:04X}: STA ${:02X}{:02X},y | {:02X}", @@ -865,11 +871,11 @@ impl NES { log!(" : - JMP ${:04X}", self.cpu.pc); } }), - 0x4C => inst!("JMP abs", 3, |low, high| { + 0x4C => inst!("JMP abs", 0, |low, high| { self.cpu.pc = u16::from_le_bytes([low, high]); log!("{addr:04X}: JMP ${:04X}", self.cpu.pc); }), - 0x6C => inst!("JMP abs", 3, |low, high| { + 0x6C => inst!("JMP abs", 2, |low, high| { self.cpu.pc = u16::from_le_bytes([ self.read_abs(low, high), self.read_abs(low.wrapping_add(1), high), // Known CPU bug @@ -979,6 +985,41 @@ impl NES { self.cpu.status ); }), + 0xC1 => inst!("CMP (ind,x)", 4, |off| { + let low = self.read_zp_x(off); + let high = self.read_zp_x(off.wrapping_add(1)); + let val = self.read_abs(low, high); + let v = self.cpu.a.wrapping_sub(val); + self.cpu.status.set_zero(v == 0); + self.cpu.status.set_negative(v & 0x80 == 0x80); + self.cpu.status.set_carry(self.cpu.a >= val); + log!( + "{addr:04X}: CMP ${:02X}{:02X},y | {:02X} - {:02X} -> {:?}", + high, + low, + self.cpu.a, + val, + self.cpu.status + ); + }), + 0xD1 => inst!("CMP (ind),y", 3, |off| { + // TODO: iymode + let low = self.read_abs(off, 0); + let high = self.read_abs(off.wrapping_add(1), 0); + let val = self.read_abs_y(low, high); + let v = self.cpu.a.wrapping_sub(val); + self.cpu.status.set_zero(v == 0); + self.cpu.status.set_negative(v & 0x80 == 0x80); + self.cpu.status.set_carry(self.cpu.a >= val); + log!( + "{addr:04X}: CMP ${:02X}{:02X},y | {:02X} - {:02X} -> {:?}", + high, + low, + self.cpu.a, + val, + self.cpu.status + ); + }), 0xE0 => inst!("CPX imm", 0, |val| { let v = self.cpu.x.wrapping_sub(val); self.cpu.status.set_zero(v == 0); @@ -1077,7 +1118,7 @@ impl NES { self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); log!("{addr:04X}: ADC #${:02X} | {:02X}", val, self.cpu.a); }), - 0x65 => inst!("ADC zp", 0, |off| { + 0x65 => inst!("ADC zp", 1, |off| { let val = self.read_abs(off, 0); let (a, carry_1) = self.cpu.a.overflowing_add(val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1090,7 +1131,7 @@ impl NES { self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); log!("{addr:04X}: ADC ${:02X} | {:02X}", off, self.cpu.a); }), - 0x75 => inst!("ADC zp,x", 0, |off| { + 0x75 => inst!("ADC zp,x", 2, |off| { let val = self.read_zp_x(off); let (a, carry_1) = self.cpu.a.overflowing_add(val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1103,7 +1144,7 @@ impl NES { self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); log!("{addr:04X}: ADC ${:02X},x | {:02X}", off, self.cpu.a); }), - 0x6D => inst!("ADC abs", 0, |low, high| { + 0x6D => inst!("ADC abs", 1, |low, high| { let val = self.read_abs(low, high); let (a, carry_1) = self.cpu.a.overflowing_add(val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1121,7 +1162,7 @@ impl NES { self.cpu.a ); }), - 0x7D => inst!("ADC abs,x", 0, |low, high| { + 0x7D => inst!("ADC abs,x", 1, |low, high| { let val = self.read_abs_x(low, high); let (a, carry_1) = self.cpu.a.overflowing_add(val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1139,7 +1180,7 @@ impl NES { self.cpu.a ); }), - 0x79 => inst!("ADC abs,y", 0, |low, high| { + 0x79 => inst!("ADC abs,y", 1, |low, high| { let val = self.read_abs_y(low, high); let (a, carry_1) = self.cpu.a.overflowing_add(val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1157,7 +1198,7 @@ impl NES { self.cpu.a ); }), - 0x61 => inst!("ADC (ind,x)", 0, |off| { + 0x61 => inst!("ADC (ind,x)", 4, |off| { let low = self.read_abs(off, 0); let high = self.read_abs(off.wrapping_add(1), 0); let val = self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16); @@ -1177,7 +1218,7 @@ impl NES { self.cpu.a ); }), - 0x71 => inst!("ADC (ind),y", 0, |off| { + 0x71 => inst!("ADC (ind),y", 3, |off| { let low = self.read_abs(off, 0); let high = self.read_abs(off.wrapping_add(1), 0); let val = self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16); @@ -1210,7 +1251,7 @@ impl NES { self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); log!("{addr:04X}: SBC #${:02X} | {:02X}", val, self.cpu.a); }), - 0xE5 => inst!("SBC zp", 0, |off| { + 0xE5 => inst!("SBC zp", 1, |off| { let val = self.read_abs(off, 0); let (a, carry_1) = self.cpu.a.overflowing_add(!val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1222,7 +1263,7 @@ impl NES { self.cpu.status.set_zero(self.cpu.a == 0); self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); }), - 0xF5 => inst!("SBC zp,x", 0, |off| { + 0xF5 => inst!("SBC zp,x", 2, |off| { let val = self.read_zp_x(off); let (a, carry_1) = self.cpu.a.overflowing_add(!val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1235,7 +1276,7 @@ impl NES { self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); log!("{addr:04X}: SBC ${:02X},x | {:02X}", off, self.cpu.a); }), - 0xED => inst!("SBC abs", 0, |low, high| { + 0xED => inst!("SBC abs", 1, |low, high| { let val = self.read_abs(low, high); let (a, carry_1) = self.cpu.a.overflowing_add(!val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1253,7 +1294,7 @@ impl NES { self.cpu.a ); }), - 0xFD => inst!("SBC abs,x", 0, |low, high| { + 0xFD => inst!("SBC abs,x", 1, |low, high| { let val = self.read_abs_x(low, high); let (a, carry_1) = self.cpu.a.overflowing_add(!val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1271,7 +1312,7 @@ impl NES { self.cpu.a ); }), - 0xF9 => inst!("SBC abs,y", 0, |low, high| { + 0xF9 => inst!("SBC abs,y", 1, |low, high| { let val = self.read_abs_y(low, high); let (a, carry_1) = self.cpu.a.overflowing_add(!val); let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into()); @@ -1289,7 +1330,7 @@ impl NES { self.cpu.a ); }), - 0xE1 => inst!("SBC (ind,x)", 0, |off| { + 0xE1 => inst!("SBC (ind,x)", 4, |off| { let low = self.read_abs(off, 0); let high = self.read_abs(off.wrapping_add(1), 0); let val = self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16); @@ -1309,7 +1350,7 @@ impl NES { self.cpu.a ); }), - 0xF1 => inst!("SBC (ind),y", 0, |off| { + 0xF1 => inst!("SBC (ind),y", 3, |off| { let low = self.read_abs(off, 0); let high = self.read_abs(off.wrapping_add(1), 0); let val = self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16); @@ -1355,7 +1396,7 @@ impl NES { self.cpu.a ); }), - 0xDE => inst!("DEC abs,x", 3, |low, high| { + 0xDE => inst!("DEC abs,x", 4, |low, high| { let val = self.read_abs_x(low, high).wrapping_sub(1); self.write_abs_x(low, high, val); self.cpu.status.set_zero(val == 0); @@ -1405,7 +1446,7 @@ impl NES { self.cpu.a ); }), - 0xFE => inst!("INC abs,x", 3, |low, high| { + 0xFE => inst!("INC abs,x", 4, |low, high| { let val = self.read_abs_x(low, high).wrapping_add(1); self.write_abs_x(low, high, val); self.cpu.status.set_zero(val == 0); @@ -1460,7 +1501,8 @@ impl NES { self.cpu.a ); }), - 0x1D => inst!("ORA abs,x", 1, |low, high| { // TODO: page crossing + 0x1D => inst!("ORA abs,x", 1, |low, high| { + // TODO: page crossing self.cpu.a |= self.read_abs_x(low, high); self.cpu.status.set_zero(self.cpu.a == 0); self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); @@ -1526,7 +1568,7 @@ impl NES { self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); log!("{addr:04X}: AND ${:02X},x | {:02X}", off, self.cpu.a); }), - 0x2D => inst!("AND abs", 2, |low, high| { + 0x2D => inst!("AND abs", 1, |low, high| { self.cpu.a &= self.read_abs(low, high); self.cpu.status.set_zero(self.cpu.a == 0); self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); @@ -1537,7 +1579,7 @@ impl NES { self.cpu.a ); }), - 0x3D => inst!("AND abs,x", 2, |low, high| { + 0x3D => inst!("AND abs,x", 1, |low, high| { self.cpu.a &= self.read_abs_x(low, high); self.cpu.status.set_zero(self.cpu.a == 0); self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80); @@ -1572,7 +1614,7 @@ impl NES { self.cpu.a ); }), - 0x31 => inst!("AND (ind),y", 4, |off| { + 0x31 => inst!("AND (ind),y", 3, |off| { let low = self.read_abs(off, 0); let high = self.read_abs(off.wrapping_add(1), 0); self.cpu.a &= self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16); @@ -2027,7 +2069,9 @@ impl NES { if self.cpu.nmi_pending { self.cpu.nmi_pending = false; self.cpu.clock_state = ClockState::HoldNmi { cycles: 6 }; + writeln!(self.debug_log, "NMI detected").unwrap(); } else if self.cpu.irq_pending && !self.cpu.status.interrupt_disable() { + writeln!(self.debug_log, "IRQ detected").unwrap(); self.cpu.clock_state = ClockState::HoldIrq { cycles: 6 }; } }