chirp-minifb: Propagate errors up to main

This commit is contained in:
John 2023-03-30 10:46:35 -05:00
parent c1f457814d
commit 627511282a
4 changed files with 39 additions and 22 deletions

View File

@ -6,6 +6,7 @@
use chirp::{error::Result, prelude::*}; use chirp::{error::Result, prelude::*};
use gumdrop::*; use gumdrop::*;
use owo_colors::OwoColorize;
use std::fs::read; use std::fs::read;
use std::{ use std::{
path::PathBuf, path::PathBuf,
@ -23,11 +24,12 @@ struct Arguments {
#[options(help = "Enable pause mode at startup.")] #[options(help = "Enable pause mode at startup.")]
pub pause: bool, pub pause: bool,
#[options(help = "Set the instructions-per-frame rate.")] #[options(help = "Set the instructions-per-delay rate, or use realtime.")]
pub speed: Option<usize>, pub speed: Option<usize>,
#[options(help = "Run the emulator as fast as possible for `step` instructions.")] #[options(help = "Set the instructions-per-frame rate.")]
pub step: Option<usize>, pub step: Option<usize>,
#[options(help = "Enable performance benchmarking on stderr (requires -S)")]
pub perf: bool,
#[options( #[options(
short = "z", short = "z",
help = "Disable setting vF to 0 after a bitwise operation." help = "Disable setting vF to 0 after a bitwise operation."
@ -77,6 +79,7 @@ struct State {
pub speed: usize, pub speed: usize,
pub step: Option<usize>, pub step: Option<usize>,
pub rate: u64, pub rate: u64,
pub perf: bool,
pub ch8: Chip8, pub ch8: Chip8,
pub ui: UI, pub ui: UI,
pub ft: Instant, pub ft: Instant,
@ -88,6 +91,7 @@ impl State {
speed: options.speed.unwrap_or(8), speed: options.speed.unwrap_or(8),
step: options.step, step: options.step,
rate: options.frame_rate, rate: options.frame_rate,
perf: options.perf,
ch8: Chip8 { ch8: Chip8 {
bus: bus! { bus: bus! {
// Load the charset into ROM // Load the charset into ROM
@ -140,6 +144,7 @@ impl State {
Some(ticks) => { Some(ticks) => {
let time = Instant::now(); let time = Instant::now();
self.ch8.cpu.multistep(&mut self.ch8.bus, ticks)?; self.ch8.cpu.multistep(&mut self.ch8.bus, ticks)?;
if self.perf {
let time = time.elapsed(); let time = time.elapsed();
let nspt = time.as_secs_f64() / ticks as f64; let nspt = time.as_secs_f64() / ticks as f64;
eprintln!( eprintln!(
@ -147,9 +152,7 @@ impl State {
nspt * 1_000_000_000.0, nspt * 1_000_000_000.0,
((1.0 / 60.0f64) / nspt).trunc(), ((1.0 / 60.0f64) / nspt).trunc(),
); );
// Pause the CPU and clear step }
//self.ch8.cpu.flags.pause = true;
//self.step = None;
} }
None => { None => {
self.ch8.cpu.multistep(&mut self.ch8.bus, rate)?; self.ch8.cpu.multistep(&mut self.ch8.bus, rate)?;
@ -166,21 +169,33 @@ impl State {
} }
impl Iterator for State { impl Iterator for State {
type Item = (); type Item = Result<()>;
/// Pretty heavily abusing iterators here, in an annoying way
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.wait_for_next_frame(); self.wait_for_next_frame();
self.keys().unwrap_or_else(|_| None)?; match self.keys() {
self.tick_cpu().ok()?; Ok(opt) => opt?,
self.frame(); Err(e) => return Some(Err(e)), // summary
Some(()) }
self.keys().unwrap_or(None)?;
if let Err(e) = self.tick_cpu() {
return Some(Err(e));
}
self.frame()?;
Some(Ok(()))
} }
} }
fn main() -> Result<()> { fn main() -> Result<()> {
let options = Arguments::parse_args_default_or_exit(); let options = Arguments::parse_args_default_or_exit();
let state = State::new(options)?; let state = State::new(options)?;
Ok(for _ in state {}) Ok(for result in state {
if let Err(e) = result {
eprintln!("{}", e.bold().red());
break;
}
})
} }
/// Parses a hexadecimal string into a u16 /// Parses a hexadecimal string into a u16

View File

@ -580,7 +580,6 @@ impl CPU {
}; };
// Print opcode disassembly: // Print opcode disassembly:
if self.flags.debug { if self.flags.debug {
println!("{:?}", self.timers.insn.elapsed().bright_black()); println!("{:?}", self.timers.insn.elapsed().bright_black());
self.timers.insn = Instant::now(); self.timers.insn = Instant::now();

View File

@ -15,7 +15,7 @@ pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Error { pub enum Error {
/// Represents an unimplemented operation /// Represents an unimplemented operation
#[error("Unrecognized opcode {word}")] #[error("Unrecognized opcode: {word:04x}")]
UnimplementedInstruction { UnimplementedInstruction {
/// The offending word /// The offending word
word: u16, word: u16,
@ -27,7 +27,7 @@ pub enum Error {
region: Region, region: Region,
}, },
/// Tried to fetch [Range] from bus, received nothing /// Tried to fetch [Range] from bus, received nothing
#[error("Invalid range {range:?} for bus")] #[error("Invalid range {range:04x?} for bus")]
InvalidBusRange { InvalidBusRange {
/// The offending [Range] /// The offending [Range]
range: Range<usize>, range: Range<usize>,

View File

@ -151,6 +151,9 @@ impl UI {
(1.0 / self.time.elapsed().as_secs_f64()).trunc() (1.0 / self.time.elapsed().as_secs_f64()).trunc()
)); ));
} }
if !self.window.is_open() {
std::process::exit(0);
}
self.time = Instant::now(); self.time = Instant::now();
// update framebuffer // update framebuffer
self.fb.render(&mut self.window, &mut ch8.bus); self.fb.render(&mut self.window, &mut ch8.bus);