Skip to content

Commit dc265f6

Browse files
committed
better CPU usage and color showcase
1 parent 848d7d2 commit dc265f6

File tree

4 files changed

+64
-35
lines changed

4 files changed

+64
-35
lines changed

examples/screen.asm

+22-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
11
@org 0x0000
2-
@define BUF_START 0xF800
2+
@define BUF_START 0xF000
3+
@define COLOR_START (BUF_START + 256*2) ; Start offset by 256 characters to not overwrite any of the char display
34

45
_start:
56
mv A, 0
6-
.loop:
7+
mv B, 0x0F
8+
.char_loop:
79
lda [BUF_START]
810
add16 H, L, 0x00, A
11+
add16 H, L, 0x00, A ; double offset to account for modifier bytes
912
st A
13+
inc H, L ; increment to shift into modifier byte
14+
st B
15+
1016
inc A
11-
jnz A, [.loop]
17+
jnz A, [.char_loop]
18+
19+
mv A, 0
20+
mv B, 0x01 ; smiley face
21+
.color_loop:
22+
lda [COLOR_START]
23+
add16 H, L, 0x00, A
24+
add16 H, L, 0x00, A ; double offset to account for modifier bytes
25+
st B
26+
inc H, L ; increment to shift into modifier byte
27+
st A
28+
29+
inc A
30+
jnz A, [.color_loop]
1231
halt

misc/screen.png

16.8 KB
Loading

src/emulator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,7 @@ pub async fn emulate(mut args: EmulatorArgs) -> Result<(), EmulatorError> {
11241124
state.halt();
11251125
}
11261126
} else {
1127-
async_std::task::sleep(Duration::from_millis(1)).await;
1127+
async_std::task::sleep(Duration::from_millis(10)).await;
11281128
}
11291129
}
11301130

src/emulator/display.rs

+41-31
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use std::pin::Pin;
1+
use std::sync::atomic::Ordering;
2+
use std::sync::Arc;
3+
use std::{pin::Pin, sync::atomic::AtomicBool};
24
use std::str::FromStr;
35

46
use async_std::task::JoinHandle;
@@ -31,12 +33,14 @@ const COLORS: [u32; 16] = [
3133
pub struct TextBuffer {
3234
chars: Pin<Box<[u8; 1 << 11]>>,
3335
modifiers: Pin<Box<[u8; 1 << 11]>>,
36+
modified: Arc<AtomicBool>,
3437
handle: JoinHandle<()>,
3538
}
3639

37-
struct BufferPtr{
40+
struct BufferPtr {
3841
chars: *const [u8; 1 << 11],
3942
modifiers: *const [u8; 1 << 11],
43+
modified: Arc<AtomicBool>,
4044
}
4145

4246
unsafe impl Send for BufferPtr {}
@@ -45,13 +49,15 @@ impl TextBuffer {
4549
pub fn spawn() -> TextBuffer {
4650
let chars = Box::pin([0; 1 << 11]);
4751
let modifiers = Box::pin([0; 1 << 11]);
52+
let modified = Arc::new(AtomicBool::new(true));
4853

4954
let handle = async_std::task::spawn(run_handle(BufferPtr{
5055
chars: &*chars,
5156
modifiers: &*modifiers,
57+
modified: modified.clone(),
5258
}));
5359

54-
TextBuffer { chars, modifiers, handle }
60+
TextBuffer { chars, modifiers, modified, handle }
5561
}
5662

5763
pub fn get(&self, addr: u16) -> u8 {
@@ -65,7 +71,7 @@ impl TextBuffer {
6571
}
6672

6773
pub fn set(&mut self, addr: u16, data: u8) {
68-
println!("setting {addr} to {data}");
74+
self.modified.store(true, Ordering::Relaxed);
6975

7076
if addr % 2 == 0 {
7177
let sub_index = (addr >> 1) as usize;
@@ -90,7 +96,7 @@ async fn run_handle(buffer: BufferPtr) {
9096

9197
let mut window =
9298
minifb::Window::new("f8ful", WIDTH, HEIGHT, opts).expect("should be able to create window");
93-
// match the VGA standard
99+
// the actual VGA standard is 75, but this function is very resource intensive and should not run constantly
94100
window.set_target_fps(75);
95101
if let Some(icon) = get_icon() {
96102
window.set_icon(icon);
@@ -99,35 +105,39 @@ async fn run_handle(buffer: BufferPtr) {
99105
let mut fb = [0x00000000; WIDTH * HEIGHT];
100106

101107
while window.is_open() {
102-
for y in 0..HEIGHT {
103-
for x in 0..WIDTH {
104-
let font_x = x % 8;
105-
let font_y = y % 16;
106-
107-
let char_x = x / 8;
108-
let char_y = y / 16;
109-
let char_idx = char_x + char_y * WIDTH / 8;
110-
let (character, modifier) = unsafe {(
111-
(*buffer.chars)[char_idx],
112-
(*buffer.modifiers)[char_idx]
113-
)};
114-
115-
let font_addr = ((character as usize) << 4) + font_y;
116-
let lit = FONT[font_addr] & (1 << (7 - font_x)) > 0;
117-
118-
// This part isn't part of the actual CPU,
119-
// the real value will be transmitted via VGA instead of stored.
120-
let fg = COLORS[(modifier & 0xf) as usize];
121-
let bg = COLORS[(modifier >> 4) as usize];
122-
fb[x + y * WIDTH] = if lit { fg } else { bg };
108+
if buffer.modified.load(Ordering::Relaxed) {
109+
buffer.modified.store(false, Ordering::Relaxed);
110+
for y in 0..HEIGHT {
111+
for x in 0..WIDTH {
112+
let font_x = x % 8;
113+
let font_y = y % 16;
114+
115+
let char_x = x / 8;
116+
let char_y = y / 16;
117+
let char_idx = char_x + char_y * WIDTH / 8;
118+
let (character, modifier) = unsafe {(
119+
(*buffer.chars)[char_idx],
120+
(*buffer.modifiers)[char_idx]
121+
)};
122+
123+
let font_addr = ((character as usize) << 4) + font_y;
124+
let lit = FONT[font_addr] & (1 << (7 - font_x)) > 0;
125+
126+
// This part isn't part of the actual CPU,
127+
// the real value will be transmitted via VGA instead of stored.
128+
let fg = COLORS[(modifier & 0xf) as usize];
129+
let bg = COLORS[(modifier >> 4) as usize];
130+
fb[x + y * WIDTH] = if lit { fg } else { bg };
131+
}
123132
}
124-
}
125133

126-
window
127-
.update_with_buffer(&fb, WIDTH, HEIGHT)
128-
.expect("unable to write to window");
134+
window
135+
.update_with_buffer(&fb, WIDTH, HEIGHT)
136+
.expect("unable to write to window");
137+
} else {
138+
window.update();
139+
}
129140
}
130-
131141
}
132142

133143
fn get_icon() -> Option<Icon> {

0 commit comments

Comments
 (0)