forked from MightyPork/crsn
screen imrpvoements
This commit is contained in:
@@ -29,6 +29,10 @@ impl ArgParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn have_more(&self) -> bool {
|
||||||
|
self.len() > 0
|
||||||
|
}
|
||||||
|
|
||||||
/// Get remaining items count
|
/// Get remaining items count
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.args.len()
|
self.args.len()
|
||||||
|
|||||||
+1
-1
@@ -7,4 +7,4 @@ pub mod asm;
|
|||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
|
pub mod utils;
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mod option_ext;
|
||||||
|
|
||||||
|
pub use option_ext::UncheckedOptionExt;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/// This is copied from parking_lot
|
||||||
|
///
|
||||||
|
/// Copyright 2016 Amanieu d'Antras
|
||||||
|
|
||||||
|
// Option::unchecked_unwrap
|
||||||
|
pub trait UncheckedOptionExt<T> {
|
||||||
|
unsafe fn unchecked_unwrap(self) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UncheckedOptionExt<T> for Option<T> {
|
||||||
|
#[inline]
|
||||||
|
unsafe fn unchecked_unwrap(self) -> T {
|
||||||
|
match self {
|
||||||
|
Some(x) => x,
|
||||||
|
None => core::hint::unreachable_unchecked(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,5 +10,12 @@ pub enum ScreenOp {
|
|||||||
x: Rd,
|
x: Rd,
|
||||||
y: Rd,
|
y: Rd,
|
||||||
color: Rd,
|
color: Rd,
|
||||||
}
|
},
|
||||||
|
Blit {
|
||||||
|
force: Rd,
|
||||||
|
},
|
||||||
|
SetOpt {
|
||||||
|
opt: Rd,
|
||||||
|
val: Rd,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+88
-10
@@ -10,15 +10,45 @@ use crate::defs::ScreenOp;
|
|||||||
use minifb::{Window, WindowOptions, ScaleMode};
|
use minifb::{Window, WindowOptions, ScaleMode};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::{Instant, Duration};
|
||||||
|
use std::ops::Sub;
|
||||||
|
use crsn::utils::UncheckedOptionExt;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
|
struct Opts {
|
||||||
|
auto_blit: bool,
|
||||||
|
frame_rate: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Backend {
|
struct Backend {
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
buffer: Vec<u32>,
|
buffer: Vec<u32>,
|
||||||
window: Option<Window>,
|
window: Option<Window>,
|
||||||
|
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
|
// Hack for Window
|
||||||
unsafe impl std::marker::Send for Backend { }
|
unsafe impl std::marker::Send for Backend { }
|
||||||
|
|
||||||
@@ -31,12 +61,48 @@ impl OpTrait for ScreenOp {
|
|||||||
let h = state.read(*height)?;
|
let h = state.read(*height)?;
|
||||||
init(state, w, h)?;
|
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 } => {
|
ScreenOp::SetPixel { x, y, color } => {
|
||||||
let x = state.read(*x)?;
|
let x = state.read(*x)?;
|
||||||
let y = state.read(*y)?;
|
let y = state.read(*y)?;
|
||||||
let color = state.read(*color)?;
|
let color = state.read(*color)?;
|
||||||
|
|
||||||
let backend : &mut Backend = state.ext_mut();
|
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 {
|
match &mut backend.window {
|
||||||
Some(w) => {
|
Some(w) => {
|
||||||
let index = y * backend.width as u64 + x;
|
let index = y * backend.width as u64 + x;
|
||||||
@@ -46,9 +112,9 @@ impl OpTrait for ScreenOp {
|
|||||||
} else {
|
} else {
|
||||||
backend.buffer[index as usize] = color as u32;
|
backend.buffer[index as usize] = color as u32;
|
||||||
|
|
||||||
w
|
if backend.opts.auto_blit {
|
||||||
.update_with_buffer(&backend.buffer, backend.width, backend.height)
|
blit_maybe(backend);
|
||||||
.expect("Update screen"); // TODO fault
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@@ -70,7 +136,7 @@ fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault>
|
|||||||
height as usize,
|
height as usize,
|
||||||
WindowOptions {
|
WindowOptions {
|
||||||
resize: true,
|
resize: true,
|
||||||
scale_mode: ScaleMode::AspectRatioStretch,
|
scale_mode: ScaleMode::UpperLeft,
|
||||||
..WindowOptions::default()
|
..WindowOptions::default()
|
||||||
},
|
},
|
||||||
).expect("Unable to create window"); // TODO fault
|
).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];
|
backend.buffer = vec![0; (width * height) as usize];
|
||||||
|
|
||||||
// window.limit_update_rate(Some(std::time::Duration::from_micros(16600)));
|
// window.limit_update_rate(Some(std::time::Duration::from_micros(16600)));
|
||||||
window.limit_update_rate(None);
|
// window.limit_update_rate(None);
|
||||||
|
|
||||||
window
|
|
||||||
.update_with_buffer(&backend.buffer, backend.width, backend.height)
|
|
||||||
.expect("Update screen"); // TODO fault
|
|
||||||
|
|
||||||
backend.window = Some(window);
|
backend.window = Some(window);
|
||||||
|
|
||||||
|
blit_maybe(backend);
|
||||||
|
|
||||||
Ok(())
|
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();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
use crsn::asm::data::Rd;
|
||||||
use crsn::asm::error::CrsnError;
|
use crsn::asm::error::CrsnError;
|
||||||
use crsn::asm::instr::Op;
|
use crsn::asm::instr::Op;
|
||||||
use crsn::asm::parse::arg_parser::ArgParser;
|
use crsn::asm::parse::arg_parser::ArgParser;
|
||||||
use crsn::module::{ParseOpRes};
|
use crsn::module::ParseOpRes;
|
||||||
|
|
||||||
use crate::defs::ScreenOp;
|
use crate::defs::ScreenOp;
|
||||||
|
|
||||||
@@ -23,6 +23,23 @@ pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"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 => {
|
_other => {
|
||||||
return Ok(ParseOpRes::Unknown(args));
|
return Ok(ParseOpRes::Unknown(args));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ fn main() {
|
|||||||
(
|
(
|
||||||
(main
|
(main
|
||||||
(sc-init 640 480)
|
(sc-init 640 480)
|
||||||
|
(sc-opt 1 0) ; auto blit
|
||||||
|
(sc-opt 2 60) ; frame rate
|
||||||
|
|
||||||
(ld r0 39) ; x
|
(ld r0 39) ; x
|
||||||
(ld r1 0) ; y
|
(ld r1 0) ; y
|
||||||
@@ -88,9 +90,10 @@ fn main() {
|
|||||||
(ld r5 0xffffff)
|
(ld r5 0xffffff)
|
||||||
|
|
||||||
(:loop)
|
(:loop)
|
||||||
(add r5 0x123456)
|
(add r5 0x010001)
|
||||||
(and r5 0xffffff)
|
(and r5 0xffffff)
|
||||||
(sc-px r0 r1 r5)
|
(sc-px r0 r1 r5)
|
||||||
|
(sc-blit 0)
|
||||||
(add r0 r2)
|
(add r0 r2)
|
||||||
(add r1 r3)
|
(add r1 r3)
|
||||||
(cmp r0 639 (eq? (ld r2 -1)))
|
(cmp r0 639 (eq? (ld r2 -1)))
|
||||||
|
|||||||
Reference in New Issue
Block a user