Finally find (& fix) bug in BIT instructions
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 26s

- BIT not longer ANDs the A register
- I now a pretty good debug view for debugging the CPU
- I wrote a number_input element for iced
- I upgraded to iced 0.14
- I added images for play and pause
- The debug log now displays in the debug view
This commit is contained in:
2025-12-14 13:10:57 -06:00
parent fecef26e2f
commit af770d232c
14 changed files with 2325 additions and 1330 deletions

View File

@@ -1,17 +1,17 @@
mod apu;
mod controllers;
pub mod debug;
pub mod debugger;
pub mod header_menu;
pub mod hex_view;
mod mem;
mod ppu;
#[cfg(test)]
mod test_roms;
pub use ppu::{Color, PPU, RenderBuffer};
use std::{fmt::{Arguments, Write as _}, fs::File, io::Read, path::Path};
use std::{fmt::Write as _, fs::File, io::Read, path::Path};
use thiserror::Error;
use tracing::{debug, info};
@@ -115,14 +115,14 @@ impl std::fmt::Debug for NES {
bitfield::bitfield! {
pub struct CpuStatus(u8);
carry, set_carry: 0;
zero, set_zero: 1;
interrupt_disable, set_interrupt_disable: 2;
decimal, set_decimal: 3;
brk, set_brk: 4;
php, set_php: 5;
overflow, set_overflow: 6;
negative, set_negative: 7;
pub carry, set_carry: 0;
pub zero, set_zero: 1;
pub interrupt_disable, set_interrupt_disable: 2;
pub decimal, set_decimal: 3;
pub brk, set_brk: 4;
pub php, set_php: 5;
pub overflow, set_overflow: 6;
pub negative, set_negative: 7;
}
impl std::fmt::Debug for CpuStatus {
@@ -151,16 +151,16 @@ impl std::fmt::Debug for CpuStatus {
#[derive(Debug)]
pub struct Cpu {
a: u8,
x: u8,
y: u8,
pc: u16,
sp: u8,
status: CpuStatus,
clock_state: ClockState,
pub a: u8,
pub x: u8,
pub y: u8,
pub pc: u16,
pub sp: u8,
pub status: CpuStatus,
pub clock_state: ClockState,
}
enum ClockState {
pub enum ClockState {
ReadInstruction,
ReadOperands {
instruction: u8,
@@ -499,22 +499,38 @@ impl NES {
}),
0x48 => inst!("PHA", 2, || {
log!("{addr:04X}: PHA | {:02X} -> 01{:02X}", self.cpu.a, self.cpu.sp);
log!(
"{addr:04X}: PHA | {:02X} -> 01{:02X}",
self.cpu.a,
self.cpu.sp
);
self.push(self.cpu.a);
}),
0x08 => inst!("PHP", 2, || {
log!("{addr:04X}: PHP | {:02X} -> 01{:02X}", self.cpu.status.0, self.cpu.sp);
log!(
"{addr:04X}: PHP | {:02X} -> 01{:02X}",
self.cpu.status.0,
self.cpu.sp
);
self.push(self.cpu.status.0 | 0b0011_0000);
}),
0x68 => inst!("PLA", 3, || {
self.cpu.a = self.pop();
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: PLA | {:02X} <- 01{:02X}", self.cpu.a, self.cpu.sp);
log!(
"{addr:04X}: PLA | {:02X} <- 01{:02X}",
self.cpu.a,
self.cpu.sp
);
}),
0x28 => inst!("PLP", 3, || {
self.cpu.status.0 = self.pop() & 0b1100_1111;
log!("{addr:04X}: PLP | {:02X} <- 01{:02X}", self.cpu.status.0, self.cpu.sp);
log!(
"{addr:04X}: PLP | {:02X} <- 01{:02X}",
self.cpu.status.0,
self.cpu.sp
);
}),
// Loads
@@ -540,19 +556,34 @@ impl NES {
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);
log!("{addr:04X}: LDA ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: LDA ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0xBD => inst!("LDA 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);
log!("{addr:04X}: LDA ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: LDA ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0xB9 => inst!("LDA abs,y", 1, |low, high| {
self.cpu.a = self.read_abs_y(low, high);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: LDA ${:02X}{:02X},y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: LDA ${:02X}{:02X},y | {:02X}",
high,
low,
self.cpu.a
);
}),
0xA1 => inst!("LDA (ind,x)", 4, |off| {
let low = self.read_zp_x(off);
@@ -592,13 +623,23 @@ impl NES {
self.cpu.x = self.read_abs(low, high);
self.cpu.status.set_zero(self.cpu.x == 0);
self.cpu.status.set_negative(self.cpu.x & 0x80 == 0x80);
log!("{addr:04X}: LDX ${:02X}{:02X} | {:02X}", high, low, self.cpu.x);
log!(
"{addr:04X}: LDX ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.x
);
}),
0xBE => inst!("LDX abs,y", 1, |low, high| {
self.cpu.x = self.read_abs_y(low, high);
self.cpu.status.set_zero(self.cpu.x == 0);
self.cpu.status.set_negative(self.cpu.x & 0x80 == 0x80);
log!("{addr:04X}: LDX ${:02X}{:02X},y | {:02X}", high, low, self.cpu.x);
log!(
"{addr:04X}: LDX ${:02X}{:02X},y | {:02X}",
high,
low,
self.cpu.x
);
}),
0xA0 => inst!("LDY imm", 0, |y| {
self.cpu.y = y;
@@ -622,13 +663,23 @@ impl NES {
self.cpu.y = self.read_abs(low, high);
self.cpu.status.set_zero(self.cpu.y == 0);
self.cpu.status.set_negative(self.cpu.y & 0x80 == 0x80);
log!("{addr:04X}: LDY ${:02X}{:02X} | {:02X}", high, low, self.cpu.y);
log!(
"{addr:04X}: LDY ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.y
);
}),
0xBC => inst!("LDX abs,x", 1, |low, high| {
self.cpu.y = self.read_abs_x(low, high);
self.cpu.status.set_zero(self.cpu.y == 0);
self.cpu.status.set_negative(self.cpu.y & 0x80 == 0x80);
log!("{addr:04X}: LDY ${:02X}{:02X},x | {:02X}", high, low, self.cpu.y);
log!(
"{addr:04X}: LDY ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.y
);
}),
// Stores
@@ -642,15 +693,30 @@ impl NES {
}),
0x8D => inst!("STA abs", 1, |low, high| {
self.write_abs(low, high, self.cpu.a);
log!("{addr:04X}: STA ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: STA ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x9D => inst!("STA abs,x", 1, |low, high| {
self.write_abs_x(low, high, self.cpu.a);
log!("{addr:04X}: STA ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: STA ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0x99 => inst!("STA abs,y", 1, |low, high| {
self.write_abs_y(low, high, self.cpu.a);
log!("{addr:04X}: STA ${:02X}{:02X},y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: STA ${:02X}{:02X},y | {:02X}",
high,
low,
self.cpu.a
);
}),
0x81 => inst!("STA (ind,x)", 4, |off| {
let low = self.read_zp_x(off);
@@ -677,7 +743,12 @@ impl NES {
}),
0x8E => inst!("STX abs", 1, |low, high| {
self.write_abs(low, high, self.cpu.x);
log!("{addr:04X}: STX ${:02X}{:02X} | {:02X}", high, low, self.cpu.x);
log!(
"{addr:04X}: STX ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.x
);
}),
0x84 => inst!("STY zp", 1, |off| {
self.write(off as u16, self.cpu.y);
@@ -689,7 +760,12 @@ impl NES {
}),
0x8C => inst!("STY abs", 1, |low, high| {
self.write_abs(low, high, self.cpu.y);
log!("{addr:04X}: STY ${:02X}{:02X} | {:02X}", high, low, self.cpu.y);
log!(
"{addr:04X}: STY ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.y
);
}),
// Transfers
@@ -804,7 +880,13 @@ impl NES {
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} - {:02X} -> {:?}", val, self.cpu.a, val, self.cpu.status);
log!(
"{addr:04X}: CMP #${:02X} | {:02X} - {:02X} -> {:?}",
val,
self.cpu.a,
val,
self.cpu.status
);
}),
0xC5 => inst!("CMP zp", 1, |off| {
let val = self.read_abs(off, 0);
@@ -812,7 +894,13 @@ impl NES {
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} - {:02X} -> {:?}", off, self.cpu.a, val, self.cpu.status);
log!(
"{addr:04X}: CMP ${:02X} | {:02X} - {:02X} -> {:?}",
off,
self.cpu.a,
val,
self.cpu.status
);
}),
0xD5 => inst!("CMP zp,x", 2, |off| {
let val = self.read_zp_x(off);
@@ -820,7 +908,13 @@ impl NES {
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},x | {:02X} - {:02X} -> {:?}", off, self.cpu.a, val, self.cpu.status);
log!(
"{addr:04X}: CMP ${:02X},x | {:02X} - {:02X} -> {:?}",
off,
self.cpu.a,
val,
self.cpu.status
);
}),
0xCD => inst!("CMP abs", 1, |low, high| {
let val = self.read_abs(low, high);
@@ -828,7 +922,14 @@ impl NES {
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} | {:02X} - {:02X} -> {:?}", high, low, self.cpu.a, val, self.cpu.status);
log!(
"{addr:04X}: CMP ${:02X}{:02X} | {:02X} - {:02X} -> {:?}",
high,
low,
self.cpu.a,
val,
self.cpu.status
);
}),
0xDD => inst!("CMP abs,x", 1, |low, high| {
let val = self.read_abs_x(low, high);
@@ -836,7 +937,14 @@ impl NES {
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},x | {:02X} - {:02X} -> {:?}", high, low, self.cpu.a, val, self.cpu.status);
log!(
"{addr:04X}: CMP ${:02X}{:02X},x | {:02X} - {:02X} -> {:?}",
high,
low,
self.cpu.a,
val,
self.cpu.status
);
}),
0xD9 => inst!("CMP abs,y", 1, |low, high| {
let val = self.read_abs_y(low, high);
@@ -844,14 +952,27 @@ impl NES {
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);
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);
self.cpu.status.set_negative(v & 0x80 == 0x80);
self.cpu.status.set_carry(self.cpu.x >= val);
log!("{addr:04X}: CPX #${:02X} | {:02X} - {:02X} -> {:?}", val, self.cpu.x, val, self.cpu.status);
log!(
"{addr:04X}: CPX #${:02X} | {:02X} - {:02X} -> {:?}",
val,
self.cpu.x,
val,
self.cpu.status
);
}),
0xE4 => inst!("CPX zp", 1, |off| {
let val = self.read_abs(off, 0);
@@ -859,7 +980,13 @@ impl NES {
self.cpu.status.set_zero(v == 0);
self.cpu.status.set_negative(v & 0x80 == 0x80);
self.cpu.status.set_carry(self.cpu.x >= val);
log!("{addr:04X}: CPX ${:02X} | {:02X} - {:02X} -> {:?}", off, self.cpu.x, val, self.cpu.status);
log!(
"{addr:04X}: CPX ${:02X} | {:02X} - {:02X} -> {:?}",
off,
self.cpu.x,
val,
self.cpu.status
);
}),
0xEC => inst!("CPX abs", 1, |low, high| {
let val = self.read_abs(low, high);
@@ -867,14 +994,27 @@ impl NES {
self.cpu.status.set_zero(v == 0);
self.cpu.status.set_negative(v & 0x80 == 0x80);
self.cpu.status.set_carry(self.cpu.x >= val);
log!("{addr:04X}: CPX ${:02X}{:02X} | {:02X} - {:02X} -> {:?}", high, low, self.cpu.x, val, self.cpu.status);
log!(
"{addr:04X}: CPX ${:02X}{:02X} | {:02X} - {:02X} -> {:?}",
high,
low,
self.cpu.x,
val,
self.cpu.status
);
}),
0xC0 => inst!("CPY imm", 0, |val| {
let v = self.cpu.y.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.y >= val);
log!("{addr:04X}: CPY #${:02X} | {:02X} - {:02X} -> {:?}", val, self.cpu.y, val, self.cpu.status);
log!(
"{addr:04X}: CPY #${:02X} | {:02X} - {:02X} -> {:?}",
val,
self.cpu.y,
val,
self.cpu.status
);
}),
0xC4 => inst!("CPY zp", 1, |off| {
let val = self.read_abs(off, 0);
@@ -882,7 +1022,13 @@ impl NES {
self.cpu.status.set_zero(v == 0);
self.cpu.status.set_negative(v & 0x80 == 0x80);
self.cpu.status.set_carry(self.cpu.y >= val);
log!("{addr:04X}: CPY ${:02X} | {:02X} - {:02X} -> {:?}", off, self.cpu.y, val, self.cpu.status);
log!(
"{addr:04X}: CPY ${:02X} | {:02X} - {:02X} -> {:?}",
off,
self.cpu.y,
val,
self.cpu.status
);
}),
0xCC => inst!("CPY zp", 1, |low, high| {
let val = self.read_abs(low, high);
@@ -890,7 +1036,14 @@ impl NES {
self.cpu.status.set_zero(v == 0);
self.cpu.status.set_negative(v & 0x80 == 0x80);
self.cpu.status.set_carry(self.cpu.y >= val);
log!("{addr:04X}: CPY ${:02X}{:02X} | {:02X} - {:02X} -> {:?}", high, low, self.cpu.y, val, self.cpu.status);
log!(
"{addr:04X}: CPY ${:02X}{:02X} | {:02X} - {:02X} -> {:?}",
high,
low,
self.cpu.y,
val,
self.cpu.status
);
}),
// Arithmetic
@@ -943,7 +1096,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: ADC ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ADC ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x7D => inst!("ADC abs,x", 0, |low, high| {
let val = self.read_abs_x(low, high);
@@ -956,7 +1114,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: ADC ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ADC ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0x79 => inst!("ADC abs,y", 0, |low, high| {
let val = self.read_abs_y(low, high);
@@ -969,7 +1132,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: ADC ${:02X}{:02X},y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ADC ${:02X}{:02X},y | {:02X}",
high,
low,
self.cpu.a
);
}),
0x61 => inst!("ADC (ind,x)", 0, |off| {
let low = self.read_abs(off, 0);
@@ -984,7 +1152,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: ADC (${:02X}{:02X},x) | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ADC (${:02X}{:02X},x) | {:02X}",
high,
low,
self.cpu.a
);
}),
0x71 => inst!("ADC (ind),y", 0, |off| {
let low = self.read_abs(off, 0);
@@ -999,7 +1172,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: ADC (${:02X}{:02X}),y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ADC (${:02X}{:02X}),y | {:02X}",
high,
low,
self.cpu.a
);
}),
0xE9 => inst!("SBC imm", 0, |val| {
let (a, carry_1) = self.cpu.a.overflowing_add(!val);
@@ -1050,7 +1228,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: SBC ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: SBC ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0xFD => inst!("SBC abs,x", 0, |low, high| {
let val = self.read_abs_x(low, high);
@@ -1063,7 +1246,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: SBC ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: SBC ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0xF9 => inst!("SBC abs,y", 0, |low, high| {
let val = self.read_abs_y(low, high);
@@ -1076,7 +1264,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: SBC ${:02X}{:02X},y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: SBC ${:02X}{:02X},y | {:02X}",
high,
low,
self.cpu.a
);
}),
0xE1 => inst!("SBC (ind,x)", 0, |off| {
let low = self.read_abs(off, 0);
@@ -1091,7 +1284,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: SBC (${:02X}{:02X},x) | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: SBC (${:02X}{:02X},x) | {:02X}",
high,
low,
self.cpu.a
);
}),
0xF1 => inst!("SBC (ind),y", 0, |off| {
let low = self.read_abs(off, 0);
@@ -1106,7 +1304,12 @@ impl NES {
self.cpu.status.set_carry(carry_1 | carry_2);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: SBC (${:02X}{:02X}),y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: SBC (${:02X}{:02X}),y | {:02X}",
high,
low,
self.cpu.a
);
}),
0xC6 => inst!("DEC zp", 3, |off| {
let val = self.read_abs(off, 0).wrapping_sub(1);
@@ -1127,14 +1330,24 @@ impl NES {
self.write_abs(low, high, val);
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(val & 0x80 == 0x80);
log!("{addr:04X}: DEC ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: DEC ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0xDE => inst!("DEC abs,x", 3, |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);
self.cpu.status.set_negative(val & 0x80 == 0x80);
log!("{addr:04X}: DEC ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: DEC ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0xCA => inst!("DEX", 1, || {
self.cpu.x = self.cpu.x.wrapping_sub(1);
@@ -1167,14 +1380,24 @@ impl NES {
self.write_abs(low, high, val);
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(val & 0x80 == 0x80);
log!("{addr:04X}: INC ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: INC ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0xFE => inst!("INC abs,x", 3, |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);
self.cpu.status.set_negative(val & 0x80 == 0x80);
log!("{addr:04X}: INC ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: INC ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0xE8 => inst!("INX", 1, || {
self.cpu.x = self.cpu.x.wrapping_add(1);
@@ -1212,19 +1435,34 @@ impl NES {
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);
log!("{addr:04X}: ORA ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ORA ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x1D => inst!("ORA abs,x", 2, |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);
log!("{addr:04X}: ORA ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ORA ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0x19 => inst!("ORA abs,y", 1, |low, high| {
self.cpu.a |= self.read_abs_y(low, high);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: ORA ${:02X}{:02X},y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ORA ${:02X}{:02X},y | {:02X}",
high,
low,
self.cpu.a
);
}),
0x01 => inst!("ORA (ind,x)", 4, |off| {
let low = self.read_zp_x(off);
@@ -1232,7 +1470,12 @@ impl NES {
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);
log!("{addr:04X}: ORA (${:02X}{:02X},x) | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ORA (${:02X}{:02X},x) | {:02X}",
high,
low,
self.cpu.a
);
}),
0x11 => inst!("ORA (ind),y", 4, |off| {
let low = self.read_abs(off, 0);
@@ -1240,7 +1483,12 @@ impl NES {
self.cpu.a |= self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: ORA (${:02X}{:02X}),y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ORA (${:02X}{:02X}),y | {:02X}",
high,
low,
self.cpu.a
);
}),
0x29 => inst!("AND imm", 0, |val| {
self.cpu.a &= val;
@@ -1264,19 +1512,34 @@ impl NES {
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);
log!("{addr:04X}: AND ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: AND ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x3D => inst!("AND abs,x", 2, |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);
log!("{addr:04X}: AND ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: AND ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0x39 => inst!("AND abs,y", 1, |low, high| {
self.cpu.a &= self.read_abs_y(low, high);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: AND ${:02X}{:02X},y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: AND ${:02X}{:02X},y | {:02X}",
high,
low,
self.cpu.a
);
}),
0x21 => inst!("AND (ind,x)", 4, |off| {
let low = self.read_zp_x(off);
@@ -1284,7 +1547,12 @@ impl NES {
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);
log!("{addr:04X}: AND (${:02X}{:02X},x) | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: AND (${:02X}{:02X},x) | {:02X}",
high,
low,
self.cpu.a
);
}),
0x31 => inst!("AND (ind),y", 4, |off| {
let low = self.read_abs(off, 0);
@@ -1292,7 +1560,12 @@ impl NES {
self.cpu.a &= self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: AND (${:02X}{:02X}),y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: AND (${:02X}{:02X}),y | {:02X}",
high,
low,
self.cpu.a
);
}),
0x49 => inst!("EOR imm", 0, |val| {
self.cpu.a ^= val;
@@ -1316,19 +1589,34 @@ impl NES {
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);
log!("{addr:04X}: EOR ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: EOR ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x5D => inst!("EOR 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);
log!("{addr:04X}: EOR ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: EOR ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0x59 => inst!("EOR abs,y", 1, |low, high| {
self.cpu.a ^= self.read_abs_y(low, high);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: EOR ${:02X}{:02X},y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: EOR ${:02X}{:02X},y | {:02X}",
high,
low,
self.cpu.a
);
}),
0x41 => inst!("EOR (ind,x)", 4, |off| {
let low = self.read_zp_x(off);
@@ -1336,7 +1624,12 @@ impl NES {
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);
log!("{addr:04X}: EOR (${:02X}{:02X},x) | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: EOR (${:02X}{:02X},x) | {:02X}",
high,
low,
self.cpu.a
);
}),
0x51 => inst!("EOR (ind),y", 3, |off| {
let low = self.read_abs(off, 0);
@@ -1344,21 +1637,31 @@ impl NES {
self.cpu.a ^= self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16);
self.cpu.status.set_zero(self.cpu.a == 0);
self.cpu.status.set_negative(self.cpu.a & 0x80 == 0x80);
log!("{addr:04X}: EOR (${:02X}{:02X}),y | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: EOR (${:02X}{:02X}),y | {:02X}",
high,
low,
self.cpu.a
);
}),
0x24 => inst!("BIT zp", 1, |off| {
let val = self.cpu.a & self.read_abs(off, 0);
let val = self.read_abs(off, 0);
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_overflow(val & 0x40 == 0x40);
self.cpu.status.set_negative(val & 0x80 == 0x80);
log!("{addr:04X}: BIT ${:02X} | {:02X}", off, self.cpu.a);
log!("{addr:04X}: BIT ${:02X} | {:02X}", off, val);
}),
0x2C => inst!("BIT abs", 1, |low, high| {
let val = self.cpu.a & self.read_abs(low, high);
let val = self.read_abs(low, high);
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_overflow(val & 0x40 == 0x40);
self.cpu.status.set_negative(val & 0x80 == 0x80);
log!("{addr:04X}: BIT ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: BIT ${:02X}{:02X} | {:02X}",
high,
low,
val
);
}),
// Shifts
@@ -1394,7 +1697,12 @@ impl NES {
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(false);
self.write_abs(low, high, val);
log!("{addr:04X}: LSR ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: LSR ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x5E => inst!("LSR abs,x", 4, |low, high| {
let val = self.read_abs_x(low, high);
@@ -1403,7 +1711,12 @@ impl NES {
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(false);
self.write_abs_x(low, high, val);
log!("{addr:04X}: LSR ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: LSR ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0x0A => inst!("ASL A", 1, || {
self.cpu.status.set_carry(self.cpu.a & 0x80 == 0x80);
@@ -1437,7 +1750,12 @@ impl NES {
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(false);
self.write_abs(low, high, val);
log!("{addr:04X}: ASL ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ASL ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x1E => inst!("ASL abs,x", 4, |low, high| {
let val = self.read_abs_x(low, high);
@@ -1446,7 +1764,12 @@ impl NES {
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(false);
self.write_abs_x(low, high, val);
log!("{addr:04X}: ASL ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ASL ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0x6A => inst!("ROR A", 1, || {
let old_carry = if self.cpu.status.carry() { 0x80 } else { 0x00 };
@@ -1484,7 +1807,12 @@ impl NES {
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(false);
self.write_abs(low, high, val);
log!("{addr:04X}: ROR ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ROR ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x7E => inst!("ROR abs,x", 4, |low, high| {
let old_carry = if self.cpu.status.carry() { 0x80 } else { 0x00 };
@@ -1494,7 +1822,12 @@ impl NES {
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(false);
self.write_abs_x(low, high, val);
log!("{addr:04X}: ROR ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ROR ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0x2A => inst!("ROL A", 1, || {
let old_carry = if self.cpu.status.carry() { 0x01 } else { 0x00 };
@@ -1532,7 +1865,12 @@ impl NES {
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(false);
self.write_abs(low, high, val);
log!("{addr:04X}: ROL ${:02X}{:02X} | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ROL ${:02X}{:02X} | {:02X}",
high,
low,
self.cpu.a
);
}),
0x3E => inst!("ROL abs,x", 4, |low, high| {
let old_carry = if self.cpu.status.carry() { 0x01 } else { 0x00 };
@@ -1542,7 +1880,12 @@ impl NES {
self.cpu.status.set_zero(val == 0);
self.cpu.status.set_negative(false);
self.write_abs_x(low, high, val);
log!("{addr:04X}: ROL ${:02X}{:02X},x | {:02X}", high, low, self.cpu.a);
log!(
"{addr:04X}: ROL ${:02X}{:02X},x | {:02X}",
high,
low,
self.cpu.a
);
}),
0xEA => inst!("NOP", 1, || {
@@ -1556,6 +1899,13 @@ impl NES {
self.peek(self.cpu.pc)
}
pub fn peek_nmi(&self) -> bool {
self.ppu.peek_nmi() || self.apu.peek_nmi()
}
pub fn peek_irq(&self) -> bool {
self.ppu.peek_irq() || self.apu.peek_irq()
}
fn clock_cpu(&mut self) {
self.cpu.clock_state = match self.cpu.clock_state {
ClockState::HoldNmi { cycles } => {