Finally find (& fix) bug in BIT instructions
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 26s
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:
232
src/debugger.rs
Normal file
232
src/debugger.rs
Normal file
@@ -0,0 +1,232 @@
|
||||
use iced::{
|
||||
Element,
|
||||
Length::Fill,
|
||||
widget::{
|
||||
self, button, checkbox, column, container::bordered_box, image, number_input, row,
|
||||
scrollable, text,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{CycleResult, NES};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DebuggerState {
|
||||
ppu_cycles: usize,
|
||||
cpu_cycles: usize,
|
||||
instructions: usize,
|
||||
scan_lines: usize,
|
||||
to_scan_line: usize,
|
||||
frames: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DebuggerMessage {
|
||||
Run,
|
||||
Pause,
|
||||
SetPPUCycles(usize),
|
||||
RunPPUCycles,
|
||||
SetCPUCycles(usize),
|
||||
RunCPUCycles,
|
||||
SetInstructions(usize),
|
||||
RunInstructions,
|
||||
SetScanLines(usize),
|
||||
RunScanLines,
|
||||
SetToScanLine(usize),
|
||||
RunToScanLine,
|
||||
SetFrames(usize),
|
||||
RunFrames,
|
||||
}
|
||||
|
||||
impl DebuggerState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ppu_cycles: 1,
|
||||
cpu_cycles: 1,
|
||||
instructions: 1,
|
||||
scan_lines: 1,
|
||||
to_scan_line: 1,
|
||||
frames: 1,
|
||||
// cpu_cycles: 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view<'s>(&'s self, nes: &'s NES) -> Element<'s, DebuggerMessage> {
|
||||
column![
|
||||
row![
|
||||
button(image("./images/ic_fluent_play_24_filled.png"))
|
||||
.on_press(DebuggerMessage::Run),
|
||||
button(image("./images/ic_fluent_pause_24_filled.png"))
|
||||
.on_press(DebuggerMessage::Pause),
|
||||
],
|
||||
iced::widget::rule::horizontal(2.),
|
||||
row![column![
|
||||
text("Status"),
|
||||
row![
|
||||
labelled("A:", text(format!("{:02X}", nes.cpu.a))),
|
||||
labelled("X:", text(format!("{:02X}", nes.cpu.x))),
|
||||
labelled("Y:", text(format!("{:02X}", nes.cpu.y))),
|
||||
labelled("PC:", text(format!("{:04X}", nes.cpu.pc))),
|
||||
labelled("Cycle:", text(format!("{}", nes.cycle))),
|
||||
labelled("SP:", text(format!("{:02X}", nes.cpu.sp))),
|
||||
]
|
||||
.spacing(5.),
|
||||
row![
|
||||
labelled("P:", text(format!("{:02X}", nes.cpu.status.0))),
|
||||
labelled_box("Carry", nes.cpu.status.carry()),
|
||||
labelled_box("Zero", nes.cpu.status.zero()),
|
||||
labelled_box("Interrupt", nes.cpu.status.interrupt_disable()),
|
||||
labelled_box("--", false),
|
||||
labelled_box("--", false),
|
||||
labelled_box("Overflow", nes.cpu.status.overflow()),
|
||||
labelled_box("Negative", nes.cpu.status.negative()),
|
||||
]
|
||||
.spacing(5.),
|
||||
row![
|
||||
text("IRQs:"),
|
||||
labelled_box("NMI", nes.peek_nmi()),
|
||||
labelled_box("Cart", false),
|
||||
labelled_box("Frame Counter", false),
|
||||
labelled_box("DMC", false),
|
||||
]
|
||||
.spacing(5.),
|
||||
row![
|
||||
column![
|
||||
labelled("Cycle", text(nes.ppu.pixel)),
|
||||
labelled("Scanline", text(nes.ppu.scanline)),
|
||||
labelled("PPU Cycle", text(nes.ppu.cycle)),
|
||||
],
|
||||
column![
|
||||
labelled_box("Sprite 0 Hit", false),
|
||||
labelled_box("Sprite 0 Overflow", false),
|
||||
labelled_box("Vertical Blank", nes.ppu.vblank),
|
||||
labelled_box("Write Toggle", false),
|
||||
labelled_box("", false),
|
||||
labelled_box("Large Sprites", false),
|
||||
labelled_box("Vertical Write", false),
|
||||
labelled_box("NMI on VBlank", false),
|
||||
labelled_box("BG at $1000", false),
|
||||
labelled_box("Sprites at $1000", false),
|
||||
],
|
||||
column![
|
||||
run_type(
|
||||
"PPU Cycles:",
|
||||
self.ppu_cycles,
|
||||
DebuggerMessage::SetPPUCycles,
|
||||
DebuggerMessage::RunPPUCycles
|
||||
),
|
||||
run_type(
|
||||
"CPU Cycles:",
|
||||
self.cpu_cycles,
|
||||
DebuggerMessage::SetCPUCycles,
|
||||
DebuggerMessage::RunCPUCycles
|
||||
),
|
||||
run_type(
|
||||
"Instructions:",
|
||||
self.instructions,
|
||||
DebuggerMessage::SetInstructions,
|
||||
DebuggerMessage::RunInstructions
|
||||
),
|
||||
run_type(
|
||||
"Scanlines:",
|
||||
self.scan_lines,
|
||||
DebuggerMessage::SetScanLines,
|
||||
DebuggerMessage::RunScanLines
|
||||
),
|
||||
run_type(
|
||||
"To Scanline:",
|
||||
self.to_scan_line,
|
||||
DebuggerMessage::SetToScanLine,
|
||||
DebuggerMessage::RunToScanLine
|
||||
),
|
||||
run_type(
|
||||
"Frames:",
|
||||
self.frames,
|
||||
DebuggerMessage::SetFrames,
|
||||
DebuggerMessage::RunFrames
|
||||
),
|
||||
],
|
||||
]
|
||||
.spacing(5.),
|
||||
scrollable(column(
|
||||
nes.debug_log()
|
||||
.history()
|
||||
.into_iter()
|
||||
.rev()
|
||||
.map(|s| text(s).line_height(0.9).into())
|
||||
).spacing(0))
|
||||
.width(Fill),
|
||||
],],
|
||||
]
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn run_n_clock_cycles(nes: &mut NES, n: usize) {
|
||||
for _ in 0..n {
|
||||
nes.run_one_clock_cycle();
|
||||
}
|
||||
}
|
||||
fn run_until(nes: &mut NES, mut f: impl FnMut(CycleResult, &NES) -> bool) {
|
||||
loop {
|
||||
if f(nes.run_one_clock_cycle(), nes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, message: DebuggerMessage, nes: &mut NES) {
|
||||
match message {
|
||||
DebuggerMessage::SetPPUCycles(n) => self.ppu_cycles = n,
|
||||
DebuggerMessage::SetCPUCycles(n) => self.cpu_cycles = n,
|
||||
DebuggerMessage::SetInstructions(n) => self.instructions = n,
|
||||
DebuggerMessage::SetScanLines(n) => self.scan_lines = n,
|
||||
DebuggerMessage::SetToScanLine(n) => self.to_scan_line = n,
|
||||
DebuggerMessage::SetFrames(n) => self.frames = 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 => Self::run_until(nes, |c, _| c.cpu_exec),
|
||||
DebuggerMessage::RunScanLines => Self::run_n_clock_cycles(nes, self.scan_lines * 341),
|
||||
DebuggerMessage::RunToScanLine => {
|
||||
Self::run_until(nes, |_, n| n.ppu.scanline == self.to_scan_line)
|
||||
}
|
||||
DebuggerMessage::RunFrames => Self::run_n_clock_cycles(nes, self.frames * 341 * 261),
|
||||
DebuggerMessage::Run => todo!(),
|
||||
DebuggerMessage::Pause => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_type<'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(number_input(val).on_input(update)).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,
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
) -> Element<'a, Message> {
|
||||
row![
|
||||
widget::container(text(label)).padding(2.),
|
||||
widget::container(content).style(bordered_box).padding(2.),
|
||||
]
|
||||
.spacing(1.)
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn labelled_box<'a, Message: 'a>(label: &'a str, value: bool) -> Element<'a, Message> {
|
||||
row![checkbox(value), widget::container(text(label)),]
|
||||
.spacing(1.)
|
||||
.into()
|
||||
}
|
||||
Reference in New Issue
Block a user