Compare commits
4 Commits
13e4158b7b
...
b5e1d1a4c3
| Author | SHA1 | Date | |
|---|---|---|---|
|
b5e1d1a4c3
|
|||
|
2e5e2ed1e7
|
|||
|
42c3af28b4
|
|||
|
ac745f60e9
|
163
src/apu.rs
163
src/apu.rs
@@ -4,7 +4,7 @@ bitfield::bitfield! {
|
||||
pub struct DutyVol(u8);
|
||||
impl Debug;
|
||||
duty, set_duty: 7, 6;
|
||||
r#loop, set_loop: 5;
|
||||
length_counter_halt, set_length_counter_halt: 5;
|
||||
const_vol, set_const_vol: 4;
|
||||
volume, set_volume: 3, 0;
|
||||
}
|
||||
@@ -27,6 +27,62 @@ bitfield::bitfield! {
|
||||
|
||||
struct PulseChannel {
|
||||
enabled: bool,
|
||||
duty_vol: DutyVol,
|
||||
sweep: Sweep,
|
||||
timer_low: u8,
|
||||
length_timer_high: LengthTimerHigh,
|
||||
|
||||
cur_time: u16,
|
||||
cur_length: u8,
|
||||
}
|
||||
|
||||
impl PulseChannel {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
duty_vol: DutyVol(0),
|
||||
sweep: Sweep(0),
|
||||
timer_low: 0,
|
||||
length_timer_high: LengthTimerHigh(0),
|
||||
cur_time: 0,
|
||||
cur_length: 0,
|
||||
}
|
||||
}
|
||||
fn use_envelope(&self) -> bool {
|
||||
!self.duty_vol.const_vol()
|
||||
}
|
||||
fn volume(&self) -> u8 {
|
||||
self.duty_vol.volume()
|
||||
}
|
||||
fn timer(&self) -> u16 {
|
||||
self.timer_low as u16 | ((self.length_timer_high.timer_high() as u16) << 8)
|
||||
}
|
||||
fn length(&self) -> u8 {
|
||||
self.length_timer_high.length()
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
// TODO
|
||||
self.cur_time = self.timer();
|
||||
}
|
||||
pub fn clock(&mut self) {
|
||||
if self.cur_time == 0 {
|
||||
self.cur_time = self.timer();
|
||||
} else {
|
||||
self.cur_time -= 1;
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
pub fn q_frame_clock(&mut self) {
|
||||
if !self.duty_vol.length_counter_halt() && self.cur_length > 0 {
|
||||
self.cur_length -= 1;
|
||||
}
|
||||
}
|
||||
pub fn h_frame_clock(&mut self) {
|
||||
if !self.duty_vol.length_counter_halt() && self.cur_length > 0 {
|
||||
self.cur_length -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitfield::bitfield! {
|
||||
@@ -46,6 +102,12 @@ struct DeltaChannel {
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl DeltaChannel {
|
||||
pub fn int(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct FrameCounter {
|
||||
count: usize,
|
||||
mode_5_step: bool,
|
||||
@@ -76,8 +138,8 @@ impl std::fmt::Debug for APU {
|
||||
impl APU {
|
||||
pub fn init() -> Self {
|
||||
Self {
|
||||
pulse_1: PulseChannel { enabled: false },
|
||||
pulse_2: PulseChannel { enabled: false },
|
||||
pulse_1: PulseChannel::new(),
|
||||
pulse_2: PulseChannel::new(),
|
||||
triangle: TriangleChannel { enabled: false },
|
||||
noise: NoiseChannel { enabled: false },
|
||||
dmc: DeltaChannel { enabled: false },
|
||||
@@ -90,18 +152,38 @@ impl APU {
|
||||
}
|
||||
}
|
||||
pub fn read_reg(&mut self, offset: u16) -> u8 {
|
||||
// println!("APU read: {offset:02X}");
|
||||
match offset {
|
||||
0x15 => {
|
||||
let val = (u8::from(self.dmc.int()) << 7)
|
||||
| (u8::from(self.frame_counter.irq) << 6)
|
||||
| (u8::from(self.dmc.enabled) << 4)
|
||||
| (u8::from(self.noise.enabled) << 3)
|
||||
| (u8::from(self.triangle.enabled) << 2)
|
||||
| (u8::from(self.pulse_2.enabled) << 1)
|
||||
| (u8::from(self.pulse_1.enabled) << 0);
|
||||
self.frame_counter.irq = false;
|
||||
val
|
||||
}
|
||||
_ => panic!("No register at {:X}", offset),
|
||||
}
|
||||
}
|
||||
pub fn write_reg(&mut self, offset: u16, val: u8) {
|
||||
// println!("APU write: {offset:02X} <= {val:02X}");
|
||||
match offset {
|
||||
0x15 => {
|
||||
self.dmc.enabled = val & 0b0001_0000 != 0;
|
||||
self.noise.enabled = val & 0b0000_1000 != 0;
|
||||
self.triangle.enabled = val & 0b0000_0100 != 0;
|
||||
self.pulse_2.enabled = val & 0b0000_0010 != 0;
|
||||
self.pulse_1.enabled = val & 0b0000_0001 != 0;
|
||||
0x00 => self.pulse_1.duty_vol.0 = val,
|
||||
0x01 => self.pulse_1.sweep.0 = val,
|
||||
0x02 => self.pulse_1.timer_low = val,
|
||||
0x03 => {
|
||||
self.pulse_1.length_timer_high.0 = val;
|
||||
self.pulse_1.reset();
|
||||
}
|
||||
0x04 => self.pulse_2.duty_vol.0 = val,
|
||||
0x05 => self.pulse_2.sweep.0 = val,
|
||||
0x06 => self.pulse_2.timer_low = val,
|
||||
0x07 => {
|
||||
self.pulse_2.length_timer_high.0 = val;
|
||||
self.pulse_2.reset();
|
||||
}
|
||||
0x10 => {
|
||||
assert_eq!(val, 0x00);
|
||||
@@ -110,27 +192,60 @@ impl APU {
|
||||
0x11 => {
|
||||
// TODO: load dmc counter with (val & 7F)
|
||||
}
|
||||
_ => (),
|
||||
// _ => panic!("No register at {:X}", offset),
|
||||
0x15 => {
|
||||
self.dmc.enabled = val & 0b0001_0000 != 0;
|
||||
self.noise.enabled = val & 0b0000_1000 != 0;
|
||||
self.triangle.enabled = val & 0b0000_0100 != 0;
|
||||
self.pulse_2.enabled = val & 0b0000_0010 != 0;
|
||||
self.pulse_1.enabled = val & 0b0000_0001 != 0;
|
||||
}
|
||||
0x17 => {
|
||||
self.frame_counter.mode_5_step = val & 0b1000_0000 == 0;
|
||||
self.frame_counter.interrupt_enabled = val & 0b0100_0000 == 0;
|
||||
if !self.frame_counter.interrupt_enabled {
|
||||
self.frame_counter.irq = false;
|
||||
}
|
||||
}
|
||||
// _ => (),
|
||||
_ => panic!("No register at {:X}", offset),
|
||||
}
|
||||
}
|
||||
|
||||
fn q_frame_clock(&mut self) {
|
||||
self.pulse_1.q_frame_clock();
|
||||
self.pulse_2.q_frame_clock(); // TODO: clock all
|
||||
}
|
||||
fn h_frame_clock(&mut self) {
|
||||
self.pulse_1.q_frame_clock();
|
||||
self.pulse_1.h_frame_clock();
|
||||
self.pulse_2.q_frame_clock();
|
||||
self.pulse_2.h_frame_clock();
|
||||
}
|
||||
|
||||
pub fn run_one_clock_cycle(&mut self, ppu_cycle: usize) -> bool {
|
||||
if ppu_cycle % 6 == 1 {
|
||||
// APU Frame Counter clock cycle
|
||||
if !self.frame_counter.mode_5_step
|
||||
&& self.frame_counter.interrupt_enabled
|
||||
&& self.frame_counter.count == 14914
|
||||
{
|
||||
self.frame_counter.irq = true;
|
||||
} else if !self.frame_counter.mode_5_step
|
||||
&& self.frame_counter.interrupt_enabled
|
||||
&& self.frame_counter.count == 14915
|
||||
{
|
||||
self.frame_counter.irq = true;
|
||||
self.frame_counter.count = 0;
|
||||
if self.frame_counter.mode_5_step {
|
||||
todo!()
|
||||
} else {
|
||||
if self.frame_counter.count == 3728 {
|
||||
self.q_frame_clock();
|
||||
} else if self.frame_counter.count == 7456 {
|
||||
self.h_frame_clock();
|
||||
} else if self.frame_counter.count == 11185 {
|
||||
self.q_frame_clock();
|
||||
} else if self.frame_counter.count == 14914 {
|
||||
self.frame_counter.irq = self.frame_counter.interrupt_enabled;
|
||||
self.h_frame_clock();
|
||||
} else if self.frame_counter.count == 14915 {
|
||||
self.frame_counter.count = 0;
|
||||
self.frame_counter.irq = self.frame_counter.interrupt_enabled;
|
||||
}
|
||||
}
|
||||
self.frame_counter.count += 1;
|
||||
|
||||
self.pulse_1.clock();
|
||||
self.pulse_2.clock();
|
||||
}
|
||||
false
|
||||
}
|
||||
@@ -144,8 +259,6 @@ impl APU {
|
||||
self.frame_counter.irq
|
||||
}
|
||||
pub fn irq_waiting(&mut self) -> bool {
|
||||
let res = self.frame_counter.irq;
|
||||
self.frame_counter.irq = false;
|
||||
res
|
||||
self.frame_counter.irq
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use iced::{
|
||||
Element,
|
||||
Length::{self, Fill},
|
||||
Point, Renderer, Size, Theme,
|
||||
advanced::{
|
||||
layout::Node, widget::{
|
||||
tree::{State, Tag}, Tree
|
||||
}, Widget
|
||||
}, mouse, widget::{
|
||||
self, button, canvas::{Frame, Program}, checkbox, column, container::bordered_box, image, number_input, row, rule::horizontal, scrollable, text, Canvas, Text
|
||||
}, window::Event, Element, Length::{self, Fill}, Point, Renderer, Size, Theme
|
||||
Widget,
|
||||
layout::Node,
|
||||
widget::{
|
||||
Tree,
|
||||
tree::{State, Tag},
|
||||
},
|
||||
},
|
||||
mouse,
|
||||
widget::{
|
||||
self, Canvas, Text, button,
|
||||
canvas::{Frame, Program},
|
||||
checkbox, column,
|
||||
container::bordered_box,
|
||||
image, number_input, hex_input, row,
|
||||
rule::horizontal,
|
||||
scrollable, text,
|
||||
},
|
||||
window::Event,
|
||||
};
|
||||
|
||||
use crate::{CycleResult, NES, PPU};
|
||||
@@ -20,6 +35,7 @@ pub struct DebuggerState {
|
||||
scan_lines: usize,
|
||||
to_scan_line: usize,
|
||||
frames: usize,
|
||||
breakpoint: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -38,6 +54,8 @@ pub enum DebuggerMessage {
|
||||
RunToScanLine,
|
||||
SetFrames(usize),
|
||||
RunFrames,
|
||||
SetBreakpoint(usize),
|
||||
RunBreakpoint,
|
||||
}
|
||||
|
||||
pub fn hex16<'a, Theme, Renderer>(val: u16) -> Text<'a, Theme, Renderer>
|
||||
@@ -78,6 +96,7 @@ impl DebuggerState {
|
||||
scan_lines: 1,
|
||||
to_scan_line: 1,
|
||||
frames: 1,
|
||||
breakpoint: 0xEA5A,
|
||||
// cpu_cycles: 1,
|
||||
}
|
||||
}
|
||||
@@ -126,6 +145,7 @@ impl DebuggerState {
|
||||
labelled("Cycle", text(nes.ppu().pixel)),
|
||||
labelled("Scanline", text(nes.ppu().scanline)),
|
||||
labelled("PPU Cycle", text(nes.ppu().cycle)),
|
||||
labelled("Frame", text(nes.ppu().frame_count)),
|
||||
labelled("V:", hex16(nes.ppu().background.v)),
|
||||
labelled("T:", hex16(nes.ppu().background.t)),
|
||||
labelled("X:", hex8(nes.ppu().background.x)),
|
||||
@@ -205,6 +225,12 @@ impl DebuggerState {
|
||||
DebuggerMessage::SetFrames,
|
||||
DebuggerMessage::RunFrames
|
||||
),
|
||||
run_type_hex(
|
||||
"To Address:",
|
||||
self.breakpoint,
|
||||
DebuggerMessage::SetBreakpoint,
|
||||
DebuggerMessage::RunBreakpoint
|
||||
),
|
||||
],
|
||||
]
|
||||
.spacing(5.),
|
||||
@@ -257,6 +283,7 @@ impl DebuggerState {
|
||||
DebuggerMessage::SetScanLines(n) => self.scan_lines = n,
|
||||
DebuggerMessage::SetToScanLine(n) => self.to_scan_line = n,
|
||||
DebuggerMessage::SetFrames(n) => self.frames = n,
|
||||
DebuggerMessage::SetBreakpoint(n) => self.breakpoint = n,
|
||||
DebuggerMessage::RunPPUCycles => Self::run_n_clock_cycles(nes, self.ppu_cycles),
|
||||
DebuggerMessage::RunCPUCycles => Self::run_n_clock_cycles(nes, self.cpu_cycles * 3),
|
||||
DebuggerMessage::RunInstructions => {
|
||||
@@ -267,6 +294,7 @@ impl DebuggerState {
|
||||
Self::run_until(nes, |_, n| n.ppu.scanline == self.to_scan_line, 1)
|
||||
}
|
||||
DebuggerMessage::RunFrames => Self::run_n_clock_cycles(nes, self.frames * 341 * 262),
|
||||
DebuggerMessage::RunBreakpoint => Self::run_until(nes, |_, nes| nes.cpu.pc as usize == self.breakpoint, 1),
|
||||
DebuggerMessage::Run => Self::run_until(nes, |_, nes| nes.halted, 1),
|
||||
DebuggerMessage::Pause => todo!(),
|
||||
}
|
||||
@@ -288,6 +316,21 @@ fn run_type<'a, Message: Clone + 'a>(
|
||||
.spacing(1.)
|
||||
.into()
|
||||
}
|
||||
fn run_type_hex<'a, Message: Clone + 'a>(
|
||||
label: &'a str,
|
||||
val: usize,
|
||||
update: impl Fn(usize) -> Message + 'a,
|
||||
run: Message,
|
||||
) -> Element<'a, Message> {
|
||||
row![
|
||||
widget::container(text(label)).padding(2.),
|
||||
widget::container(hex_input(val).on_input(update).on_submit(run.clone())).padding(2.),
|
||||
widget::container(button(image("./images/ic_fluent_play_24_filled.png")).on_press(run))
|
||||
.padding(2.),
|
||||
]
|
||||
.spacing(1.)
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn labelled<'a, Message: 'a>(
|
||||
label: &'a str,
|
||||
|
||||
254
src/lib.rs
254
src/lib.rs
@@ -182,6 +182,12 @@ pub enum ClockState {
|
||||
count: u8,
|
||||
addr: u16,
|
||||
},
|
||||
Oops {
|
||||
instruction: u8,
|
||||
ops: [u8; 5],
|
||||
count: u8,
|
||||
addr: u16,
|
||||
},
|
||||
HoldNmi {
|
||||
cycles: u8,
|
||||
},
|
||||
@@ -224,6 +230,17 @@ impl std::fmt::Debug for ClockState {
|
||||
ClockState::HoldIrq { cycles } => {
|
||||
f.debug_struct("HoldIrq").field("cycles", cycles).finish()
|
||||
}
|
||||
ClockState::Oops {
|
||||
instruction,
|
||||
ops,
|
||||
count,
|
||||
addr,
|
||||
} => f
|
||||
.debug_struct("Oops")
|
||||
.field("instruction", instruction)
|
||||
.field("addr", addr)
|
||||
.field("ops", &&ops[..*count as usize])
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,6 +249,7 @@ enum ExecState {
|
||||
Done,
|
||||
MoreParams,
|
||||
Hold(u8),
|
||||
Oops,
|
||||
}
|
||||
|
||||
pub enum CPUMMRegisters {
|
||||
@@ -313,8 +331,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 +385,6 @@ impl NES {
|
||||
}
|
||||
}
|
||||
0x16 => self.controller.write_joy_strobe(val),
|
||||
0x17 => (), // TODO: frame counter control
|
||||
_ => self.apu.write_reg(offset, val),
|
||||
},
|
||||
});
|
||||
@@ -430,7 +454,14 @@ impl NES {
|
||||
}
|
||||
|
||||
/// Returns true if more bytes are needed
|
||||
fn exec_instruction(&mut self, ins: u8, mut params: &[u8], held: bool, addr: u16) -> ExecState {
|
||||
fn exec_instruction(
|
||||
&mut self,
|
||||
ins: u8,
|
||||
mut params: &[u8],
|
||||
held: bool,
|
||||
oops: bool,
|
||||
addr: u16,
|
||||
) -> ExecState {
|
||||
macro_rules! inst {
|
||||
($val:expr, $hold:expr, |$($name:pat_param),*| $eval:expr) => {{
|
||||
let hold_time: u8 = ($hold).into();
|
||||
@@ -582,6 +613,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0xBD => inst!("LDA abs,x", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.x).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -593,6 +625,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0xB9 => inst!("LDA abs,y", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -614,6 +647,7 @@ impl NES {
|
||||
0xB1 => inst!("LDA (ind),y", 3, |off| {
|
||||
let low = self.read_abs(off, 0);
|
||||
let high = self.read_abs(off.wrapping_add(1), 0);
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -631,7 +665,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);
|
||||
@@ -649,6 +683,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0xBE => inst!("LDX abs,y", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -671,7 +706,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);
|
||||
@@ -689,6 +724,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0xBC => inst!("LDX abs,x", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.x).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -718,7 +754,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 +763,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 +901,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
|
||||
@@ -950,6 +986,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0xDD => inst!("CMP abs,x", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.x).is_none() { return ExecState::Oops; }
|
||||
let val = self.read_abs_x(low, high);
|
||||
let v = self.cpu.a.wrapping_sub(val);
|
||||
self.cpu.status.set_zero(v == 0);
|
||||
@@ -965,6 +1002,42 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0xD9 => inst!("CMP abs,y", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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
|
||||
);
|
||||
}),
|
||||
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| {
|
||||
let low = self.read_abs(off, 0);
|
||||
let high = self.read_abs(off.wrapping_add(1), 0);
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
let val = self.read_abs_y(low, high);
|
||||
let v = self.cpu.a.wrapping_sub(val);
|
||||
self.cpu.status.set_zero(v == 0);
|
||||
@@ -1077,7 +1150,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 +1163,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 +1176,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 +1194,8 @@ impl NES {
|
||||
self.cpu.a
|
||||
);
|
||||
}),
|
||||
0x7D => inst!("ADC abs,x", 0, |low, high| {
|
||||
0x7D => inst!("ADC abs,x", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.x).is_none() { return ExecState::Oops; }
|
||||
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 +1213,8 @@ impl NES {
|
||||
self.cpu.a
|
||||
);
|
||||
}),
|
||||
0x79 => inst!("ADC abs,y", 0, |low, high| {
|
||||
0x79 => inst!("ADC abs,y", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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 +1232,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,9 +1252,10 @@ 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);
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
let val = self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16);
|
||||
let (a, carry_1) = self.cpu.a.overflowing_add(val);
|
||||
let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into());
|
||||
@@ -1210,7 +1286,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 +1298,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 +1311,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 +1329,8 @@ impl NES {
|
||||
self.cpu.a
|
||||
);
|
||||
}),
|
||||
0xFD => inst!("SBC abs,x", 0, |low, high| {
|
||||
0xFD => inst!("SBC abs,x", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.x).is_none() { return ExecState::Oops; }
|
||||
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 +1348,8 @@ impl NES {
|
||||
self.cpu.a
|
||||
);
|
||||
}),
|
||||
0xF9 => inst!("SBC abs,y", 0, |low, high| {
|
||||
0xF9 => inst!("SBC abs,y", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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 +1367,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,9 +1387,10 @@ 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);
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
let val = self.read(u16::from_le_bytes([low, high]) + self.cpu.y as u16);
|
||||
let (a, carry_1) = self.cpu.a.overflowing_add(!val);
|
||||
let (a, carry_2) = a.overflowing_add(self.cpu.status.carry().into());
|
||||
@@ -1355,7 +1434,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 +1484,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 +1539,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| {
|
||||
if !oops && low.checked_add(self.cpu.x).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -1472,6 +1552,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0x19 => inst!("ORA abs,y", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -1498,6 +1579,10 @@ impl NES {
|
||||
0x11 => inst!("ORA (ind),y", 3, |off| {
|
||||
let low = self.read_abs(off, 0);
|
||||
let high = self.read_abs(off.wrapping_add(1), 0);
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() {
|
||||
return ExecState::Oops;
|
||||
}
|
||||
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);
|
||||
@@ -1526,7 +1611,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 +1622,8 @@ impl NES {
|
||||
self.cpu.a
|
||||
);
|
||||
}),
|
||||
0x3D => inst!("AND abs,x", 2, |low, high| {
|
||||
0x3D => inst!("AND abs,x", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.x).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -1549,6 +1635,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0x39 => inst!("AND abs,y", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -1572,9 +1659,10 @@ 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);
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -1615,6 +1703,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0x5D => inst!("EOR abs,x", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.x).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -1626,6 +1715,7 @@ impl NES {
|
||||
);
|
||||
}),
|
||||
0x59 => inst!("EOR abs,y", 1, |low, high| {
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -1652,6 +1742,7 @@ impl NES {
|
||||
0x51 => inst!("EOR (ind),y", 3, |off| {
|
||||
let low = self.read_abs(off, 0);
|
||||
let high = self.read_abs(off.wrapping_add(1), 0);
|
||||
if !oops && low.checked_add(self.cpu.y).is_none() { return ExecState::Oops; }
|
||||
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);
|
||||
@@ -1931,39 +2022,32 @@ impl NES {
|
||||
}
|
||||
}
|
||||
ClockState::ReadInstruction => {
|
||||
// if self.cpu.nmi_pending {
|
||||
// self.cpu.nmi_pending = false;
|
||||
// writeln!(self.debug_log, "NMI detected").unwrap();
|
||||
// ClockState::HoldNmi { cycles: 5 }
|
||||
// } else if !self.cpu.status.interrupt_disable()
|
||||
// && (self.ppu.irq_waiting() || self.apu.irq_waiting())
|
||||
// {
|
||||
// // TODO: handle proper irq detection
|
||||
// writeln!(self.debug_log, "IRQ detected").unwrap();
|
||||
// ClockState::HoldIrq { cycles: 6 }
|
||||
// } else
|
||||
{
|
||||
let addr = self.cpu.pc;
|
||||
let instruction = self.read(self.cpu.pc);
|
||||
if instruction != 0x02 {
|
||||
self.cpu.pc = self.cpu.pc.wrapping_add(1);
|
||||
}
|
||||
match self.exec_instruction(instruction, &[], false, addr) {
|
||||
ExecState::Done => ClockState::ReadInstruction,
|
||||
ExecState::MoreParams => ClockState::ReadOperands {
|
||||
instruction,
|
||||
ops: [0u8; 5],
|
||||
count: 0,
|
||||
addr,
|
||||
},
|
||||
ExecState::Hold(cycles) => ClockState::Hold {
|
||||
cycles,
|
||||
instruction,
|
||||
ops: [0u8; 5],
|
||||
count: 0,
|
||||
addr,
|
||||
},
|
||||
}
|
||||
let addr = self.cpu.pc;
|
||||
let instruction = self.read(self.cpu.pc);
|
||||
if instruction != 0x02 {
|
||||
self.cpu.pc = self.cpu.pc.wrapping_add(1);
|
||||
}
|
||||
match self.exec_instruction(instruction, &[], false, false, addr) {
|
||||
ExecState::Done => ClockState::ReadInstruction,
|
||||
ExecState::MoreParams => ClockState::ReadOperands {
|
||||
instruction,
|
||||
ops: [0u8; 5],
|
||||
count: 0,
|
||||
addr,
|
||||
},
|
||||
ExecState::Hold(cycles) => ClockState::Hold {
|
||||
cycles,
|
||||
instruction,
|
||||
ops: [0u8; 5],
|
||||
count: 0,
|
||||
addr,
|
||||
},
|
||||
ExecState::Oops => ClockState::Oops {
|
||||
instruction,
|
||||
ops: [0u8; 5],
|
||||
count: 0,
|
||||
addr,
|
||||
},
|
||||
}
|
||||
}
|
||||
ClockState::ReadOperands {
|
||||
@@ -1977,7 +2061,13 @@ impl NES {
|
||||
}
|
||||
ops[count as usize] = self.read(self.cpu.pc);
|
||||
self.cpu.pc = self.cpu.pc.wrapping_add(1);
|
||||
match self.exec_instruction(instruction, &ops[..count as usize + 1], false, addr) {
|
||||
match self.exec_instruction(
|
||||
instruction,
|
||||
&ops[..count as usize + 1],
|
||||
false,
|
||||
false,
|
||||
addr,
|
||||
) {
|
||||
ExecState::Done => ClockState::ReadInstruction,
|
||||
ExecState::MoreParams => ClockState::ReadOperands {
|
||||
instruction,
|
||||
@@ -1992,6 +2082,12 @@ impl NES {
|
||||
count: count + 1,
|
||||
addr,
|
||||
},
|
||||
ExecState::Oops => ClockState::Oops {
|
||||
instruction,
|
||||
ops,
|
||||
count: count + 1,
|
||||
addr,
|
||||
},
|
||||
}
|
||||
}
|
||||
ClockState::Hold {
|
||||
@@ -2002,15 +2098,24 @@ impl NES {
|
||||
addr,
|
||||
} => {
|
||||
if cycles == 0 {
|
||||
match self.exec_instruction(instruction, &ops[..count as usize], true, addr) {
|
||||
match self.exec_instruction(
|
||||
instruction,
|
||||
&ops[..count as usize],
|
||||
true,
|
||||
false,
|
||||
addr,
|
||||
) {
|
||||
ExecState::Done => ClockState::ReadInstruction,
|
||||
ExecState::MoreParams => ClockState::ReadOperands {
|
||||
ExecState::MoreParams => {
|
||||
panic!("Should never return MoreParams after holding")
|
||||
}
|
||||
ExecState::Hold(_) => panic!("Should never return Hold after holding"),
|
||||
ExecState::Oops => ClockState::Oops {
|
||||
instruction,
|
||||
ops,
|
||||
count: count + 1,
|
||||
count,
|
||||
addr,
|
||||
},
|
||||
ExecState::Hold(_) => panic!("Should never return Hold after holding"),
|
||||
}
|
||||
} else {
|
||||
ClockState::Hold {
|
||||
@@ -2022,12 +2127,25 @@ impl NES {
|
||||
}
|
||||
}
|
||||
}
|
||||
ClockState::Oops {
|
||||
instruction,
|
||||
ops,
|
||||
count,
|
||||
addr,
|
||||
} => {
|
||||
match self.exec_instruction(instruction, &ops[..count as usize], true, true, addr) {
|
||||
ExecState::Done => ClockState::ReadInstruction,
|
||||
_ => panic!("Must execute after oops"),
|
||||
}
|
||||
}
|
||||
};
|
||||
if self.cpu.clock_state == ClockState::ReadInstruction {
|
||||
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 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ use tracing_subscriber::EnvFilter;
|
||||
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "ppu_fill_red.nes");
|
||||
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "ppu_fill_name_table.nes");
|
||||
// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "int_nmi_exit_timing.nes");
|
||||
const ROM_FILE: &str = "./Super Mario Bros. (World).nes";
|
||||
// const ROM_FILE: &str = "./cpu_timing_test.nes";
|
||||
// const ROM_FILE: &str = "./Super Mario Bros. (World).nes";
|
||||
const ROM_FILE: &str = "./cpu_timing_test.nes";
|
||||
|
||||
extern crate nes_emu;
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ impl Palette {
|
||||
|
||||
pub struct PPU {
|
||||
// registers: PPURegisters,
|
||||
frame_count: usize,
|
||||
pub frame_count: usize,
|
||||
nmi_enabled: bool,
|
||||
// nmi_waiting: bool,
|
||||
pub even: bool,
|
||||
|
||||
Reference in New Issue
Block a user