Skip to content

Commit

Permalink
better CPU usage and color showcase
Browse files Browse the repository at this point in the history
  • Loading branch information
commonkestrel committed Jul 29, 2024
1 parent 848d7d2 commit dc265f6
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 35 deletions.
25 changes: 22 additions & 3 deletions examples/screen.asm
Original file line number Diff line number Diff line change
@@ -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
Binary file modified misc/screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/emulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
72 changes: 41 additions & 31 deletions src/emulator/display.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -31,12 +33,14 @@ const COLORS: [u32; 16] = [
pub struct TextBuffer {
chars: Pin<Box<[u8; 1 << 11]>>,
modifiers: Pin<Box<[u8; 1 << 11]>>,
modified: Arc<AtomicBool>,
handle: JoinHandle<()>,
}

struct BufferPtr{
struct BufferPtr {
chars: *const [u8; 1 << 11],
modifiers: *const [u8; 1 << 11],
modified: Arc<AtomicBool>,
}

unsafe impl Send for BufferPtr {}
Expand All @@ -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 {
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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<Icon> {
Expand Down

0 comments on commit dc265f6

Please sign in to comment.