diff --git a/crsn/src/asm/parse/arg_parser.rs b/crsn/src/asm/parse/arg_parser.rs index 6baf957..cc14fa2 100644 --- a/crsn/src/asm/parse/arg_parser.rs +++ b/crsn/src/asm/parse/arg_parser.rs @@ -29,6 +29,10 @@ impl ArgParser { } } + pub fn have_more(&self) -> bool { + self.len() > 0 + } + /// Get remaining items count pub fn len(&self) -> usize { self.args.len() diff --git a/crsn/src/lib.rs b/crsn/src/lib.rs index 8d154c1..d270bf3 100644 --- a/crsn/src/lib.rs +++ b/crsn/src/lib.rs @@ -7,4 +7,4 @@ pub mod asm; pub mod builtin; pub mod runtime; pub mod module; - +pub mod utils; diff --git a/crsn/src/utils/mod.rs b/crsn/src/utils/mod.rs new file mode 100644 index 0000000..b5e5989 --- /dev/null +++ b/crsn/src/utils/mod.rs @@ -0,0 +1,3 @@ +mod option_ext; + +pub use option_ext::UncheckedOptionExt; diff --git a/crsn/src/utils/option_ext.rs b/crsn/src/utils/option_ext.rs new file mode 100644 index 0000000..91ca7d0 --- /dev/null +++ b/crsn/src/utils/option_ext.rs @@ -0,0 +1,18 @@ +/// This is copied from parking_lot +/// +/// Copyright 2016 Amanieu d'Antras + +// Option::unchecked_unwrap +pub trait UncheckedOptionExt { + unsafe fn unchecked_unwrap(self) -> T; +} + +impl UncheckedOptionExt for Option { + #[inline] + unsafe fn unchecked_unwrap(self) -> T { + match self { + Some(x) => x, + None => core::hint::unreachable_unchecked(), + } + } +} diff --git a/crsn_screen/src/defs.rs b/crsn_screen/src/defs.rs index 3558e4a..66969a0 100644 --- a/crsn_screen/src/defs.rs +++ b/crsn_screen/src/defs.rs @@ -10,5 +10,12 @@ pub enum ScreenOp { x: Rd, y: Rd, color: Rd, - } + }, + Blit { + force: Rd, + }, + SetOpt { + opt: Rd, + val: Rd, + }, } diff --git a/crsn_screen/src/exec.rs b/crsn_screen/src/exec.rs index 0910294..5299af9 100644 --- a/crsn_screen/src/exec.rs +++ b/crsn_screen/src/exec.rs @@ -10,15 +10,45 @@ use crate::defs::ScreenOp; use minifb::{Window, WindowOptions, ScaleMode}; use parking_lot::Mutex; use std::sync::Arc; +use std::time::{Instant, Duration}; +use std::ops::Sub; +use crsn::utils::UncheckedOptionExt; + +#[derive(Debug)] +struct Opts { + auto_blit: bool, + frame_rate: Duration, +} -#[derive(Debug, Default)] +#[derive(Debug)] struct Backend { width: usize, height: usize, buffer: Vec, window: Option, + last_render: Instant, + opts: Opts } +impl Default for Backend { + fn default() -> Self { + Self { + width: 0, + height: 0, + buffer: vec![], + window: None, + last_render: Instant::now().sub(Duration::from_secs(1)), + opts: Opts { + auto_blit: true, + frame_rate: Duration::from_micros(16600), + } + } + } +} + +const OPT_AUTO_BLIT : u64 = 1; +const OPT_FRAME_RATE : u64 = 2; + // Hack for Window unsafe impl std::marker::Send for Backend { } @@ -31,12 +61,48 @@ impl OpTrait for ScreenOp { let h = state.read(*height)?; init(state, w, h)?; } + ScreenOp::SetOpt { opt, val } => { + let opt = state.read(*opt)?; + let val = state.read(*val)?; + let backend : &mut Backend = state.ext_mut(); + + match opt { + OPT_AUTO_BLIT => { + backend.opts.auto_blit = (val != 0); + debug!("Set auto blit to {:?}", backend.opts.auto_blit); + } + OPT_FRAME_RATE => { + backend.opts.frame_rate = Duration::from_micros(1_000_000 as u64 / val); + debug!("Set frame rate to {:?}", backend.opts.frame_rate); + } + other => { + warn!("Bad screen opt: {}", other); + state.set_flag(Cond::Invalid, true); + } + } + } + ScreenOp::Blit { force } => { + let force = state.read(*force)?; + let backend : &mut Backend = state.ext_mut(); + + if force != 0 { + blit(backend) + } else { + blit_maybe(backend) + } + } ScreenOp::SetPixel { x, y, color } => { let x = state.read(*x)?; let y = state.read(*y)?; let color = state.read(*color)?; let backend : &mut Backend = state.ext_mut(); + + if x >= backend.width as u64 || y >= backend.height as u64 { + state.set_flag(Cond::Overflow, true); + return Ok(eres); + } + match &mut backend.window { Some(w) => { let index = y * backend.width as u64 + x; @@ -46,9 +112,9 @@ impl OpTrait for ScreenOp { } else { backend.buffer[index as usize] = color as u32; - w - .update_with_buffer(&backend.buffer, backend.width, backend.height) - .expect("Update screen"); // TODO fault + if backend.opts.auto_blit { + blit_maybe(backend); + } } } None => { @@ -70,7 +136,7 @@ fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault> height as usize, WindowOptions { resize: true, - scale_mode: ScaleMode::AspectRatioStretch, + scale_mode: ScaleMode::UpperLeft, ..WindowOptions::default() }, ).expect("Unable to create window"); // TODO fault @@ -87,13 +153,25 @@ fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault> backend.buffer = vec![0; (width * height) as usize]; // window.limit_update_rate(Some(std::time::Duration::from_micros(16600))); - window.limit_update_rate(None); - - window - .update_with_buffer(&backend.buffer, backend.width, backend.height) - .expect("Update screen"); // TODO fault + // window.limit_update_rate(None); backend.window = Some(window); + blit_maybe(backend); + Ok(()) } + +fn blit_maybe(backend: &mut Backend) { + if backend.last_render.elapsed() >= backend.opts.frame_rate { + blit(backend); + } +} + +fn blit(backend: &mut Backend) { + backend.window.as_mut().unwrap() + .update_with_buffer(&backend.buffer, backend.width, backend.height) + .expect("Update screen"); // TODO fault + + backend.last_render = Instant::now(); +} diff --git a/crsn_screen/src/parse.rs b/crsn_screen/src/parse.rs index 440592f..6b896fb 100644 --- a/crsn_screen/src/parse.rs +++ b/crsn_screen/src/parse.rs @@ -1,8 +1,8 @@ - +use crsn::asm::data::Rd; use crsn::asm::error::CrsnError; use crsn::asm::instr::Op; use crsn::asm::parse::arg_parser::ArgParser; -use crsn::module::{ParseOpRes}; +use crsn::module::ParseOpRes; use crate::defs::ScreenOp; @@ -23,6 +23,23 @@ pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result } } + "sc-opt" => { + ScreenOp::SetOpt { + opt: args.next_rd()?, + val: args.next_rd()?, + } + } + + "sc-blit" => { + ScreenOp::Blit { + force: if args.have_more() { + args.next_rd()? + } else { + Rd::immediate(1) + }, + } + } + _other => { return Ok(ParseOpRes::Unknown(args)); } diff --git a/launcher/src/main.rs b/launcher/src/main.rs index 1e549f7..0e34b8d 100644 --- a/launcher/src/main.rs +++ b/launcher/src/main.rs @@ -78,6 +78,8 @@ fn main() { ( (main (sc-init 640 480) + (sc-opt 1 0) ; auto blit + (sc-opt 2 60) ; frame rate (ld r0 39) ; x (ld r1 0) ; y @@ -88,9 +90,10 @@ fn main() { (ld r5 0xffffff) (:loop) - (add r5 0x123456) + (add r5 0x010001) (and r5 0xffffff) (sc-px r0 r1 r5) + (sc-blit 0) (add r0 r2) (add r1 r3) (cmp r0 639 (eq? (ld r2 -1)))