chirp-minifb: Propagate errors up to main
This commit is contained in:
parent
c1f457814d
commit
627511282a
@ -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,16 +144,15 @@ 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)?;
|
||||||
let time = time.elapsed();
|
if self.perf {
|
||||||
let nspt = time.as_secs_f64() / ticks as f64;
|
let time = time.elapsed();
|
||||||
eprintln!(
|
let nspt = time.as_secs_f64() / ticks as f64;
|
||||||
"{ticks},\t{time:.05?},\t{:.4}nspt,\t{}ipf",
|
eprintln!(
|
||||||
nspt * 1_000_000_000.0,
|
"{ticks},\t{time:.05?},\t{:.4}nspt,\t{}ipf",
|
||||||
((1.0 / 60.0f64) / nspt).trunc(),
|
nspt * 1_000_000_000.0,
|
||||||
);
|
((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
|
||||||
|
@ -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();
|
||||||
|
@ -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>,
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user