diff --git a/examples/screen.asm b/examples/screen.asm index 4fae336..4dc5cd5 100644 --- a/examples/screen.asm +++ b/examples/screen.asm @@ -1,12 +1,31 @@ @org 0x0000 -@define BUF_START 0xF800 +@define BUF_START 0xF000 +@define COLOR_START (BUF_START + 256*2) ; Start offset by 256 characters to not overwrite any of the char display _start: mv A, 0 -.loop: + mv B, 0x0F +.char_loop: lda [BUF_START] add16 H, L, 0x00, A + add16 H, L, 0x00, A ; double offset to account for modifier bytes st A + inc H, L ; increment to shift into modifier byte + st B + inc A - jnz A, [.loop] + jnz A, [.char_loop] + + mv A, 0 + mv B, 0x01 ; smiley face +.color_loop: + lda [COLOR_START] + add16 H, L, 0x00, A + add16 H, L, 0x00, A ; double offset to account for modifier bytes + st B + inc H, L ; increment to shift into modifier byte + st A + + inc A + jnz A, [.color_loop] halt diff --git a/misc/screen.png b/misc/screen.png index 4dc06e5..3f74c02 100644 Binary files a/misc/screen.png and b/misc/screen.png differ diff --git a/src/emulator.rs b/src/emulator.rs index 8952998..436ba74 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -1124,7 +1124,7 @@ pub async fn emulate(mut args: EmulatorArgs) -> Result<(), EmulatorError> { state.halt(); } } else { - async_std::task::sleep(Duration::from_millis(1)).await; + async_std::task::sleep(Duration::from_millis(10)).await; } } diff --git a/src/emulator/display.rs b/src/emulator/display.rs index 2562bf4..c24a877 100644 --- a/src/emulator/display.rs +++ b/src/emulator/display.rs @@ -1,4 +1,6 @@ -use std::pin::Pin; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::{pin::Pin, sync::atomic::AtomicBool}; use std::str::FromStr; use async_std::task::JoinHandle; @@ -31,12 +33,14 @@ const COLORS: [u32; 16] = [ pub struct TextBuffer { chars: Pin>, modifiers: Pin>, + modified: Arc, handle: JoinHandle<()>, } -struct BufferPtr{ +struct BufferPtr { chars: *const [u8; 1 << 11], modifiers: *const [u8; 1 << 11], + modified: Arc, } unsafe impl Send for BufferPtr {} @@ -45,13 +49,15 @@ impl TextBuffer { pub fn spawn() -> TextBuffer { let chars = Box::pin([0; 1 << 11]); let modifiers = Box::pin([0; 1 << 11]); + let modified = Arc::new(AtomicBool::new(true)); let handle = async_std::task::spawn(run_handle(BufferPtr{ chars: &*chars, modifiers: &*modifiers, + modified: modified.clone(), })); - TextBuffer { chars, modifiers, handle } + TextBuffer { chars, modifiers, modified, handle } } pub fn get(&self, addr: u16) -> u8 { @@ -65,7 +71,7 @@ impl TextBuffer { } pub fn set(&mut self, addr: u16, data: u8) { - println!("setting {addr} to {data}"); + self.modified.store(true, Ordering::Relaxed); if addr % 2 == 0 { let sub_index = (addr >> 1) as usize; @@ -90,7 +96,7 @@ async fn run_handle(buffer: BufferPtr) { let mut window = minifb::Window::new("f8ful", WIDTH, HEIGHT, opts).expect("should be able to create window"); - // match the VGA standard + // the actual VGA standard is 75, but this function is very resource intensive and should not run constantly window.set_target_fps(75); if let Some(icon) = get_icon() { window.set_icon(icon); @@ -99,35 +105,39 @@ async fn run_handle(buffer: BufferPtr) { let mut fb = [0x00000000; WIDTH * HEIGHT]; while window.is_open() { - for y in 0..HEIGHT { - for x in 0..WIDTH { - let font_x = x % 8; - let font_y = y % 16; - - let char_x = x / 8; - let char_y = y / 16; - let char_idx = char_x + char_y * WIDTH / 8; - let (character, modifier) = unsafe {( - (*buffer.chars)[char_idx], - (*buffer.modifiers)[char_idx] - )}; - - let font_addr = ((character as usize) << 4) + font_y; - let lit = FONT[font_addr] & (1 << (7 - font_x)) > 0; - - // This part isn't part of the actual CPU, - // the real value will be transmitted via VGA instead of stored. - let fg = COLORS[(modifier & 0xf) as usize]; - let bg = COLORS[(modifier >> 4) as usize]; - fb[x + y * WIDTH] = if lit { fg } else { bg }; + if buffer.modified.load(Ordering::Relaxed) { + buffer.modified.store(false, Ordering::Relaxed); + for y in 0..HEIGHT { + for x in 0..WIDTH { + let font_x = x % 8; + let font_y = y % 16; + + let char_x = x / 8; + let char_y = y / 16; + let char_idx = char_x + char_y * WIDTH / 8; + let (character, modifier) = unsafe {( + (*buffer.chars)[char_idx], + (*buffer.modifiers)[char_idx] + )}; + + let font_addr = ((character as usize) << 4) + font_y; + let lit = FONT[font_addr] & (1 << (7 - font_x)) > 0; + + // This part isn't part of the actual CPU, + // the real value will be transmitted via VGA instead of stored. + let fg = COLORS[(modifier & 0xf) as usize]; + let bg = COLORS[(modifier >> 4) as usize]; + fb[x + y * WIDTH] = if lit { fg } else { bg }; + } } - } - window - .update_with_buffer(&fb, WIDTH, HEIGHT) - .expect("unable to write to window"); + window + .update_with_buffer(&fb, WIDTH, HEIGHT) + .expect("unable to write to window"); + } else { + window.update(); + } } - } fn get_icon() -> Option {