more efficient rendering, improved delay timers

This commit is contained in:
Daniel Bulant 2023-01-27 12:21:51 +01:00
parent 0ee20edd71
commit 41ed39f797
3 changed files with 95 additions and 21 deletions

39
Cargo.lock generated
View file

@ -14,6 +14,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"debug_print", "debug_print",
"rand", "rand",
"spin_sleep",
] ]
[[package]] [[package]]
@ -39,6 +40,12 @@ version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "once_cell"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.17"
@ -75,8 +82,40 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "spin_sleep"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cafa7900db085f4354dbc7025e25d7a839a14360ea13b5fc4fd717f2d3b23134"
dependencies = [
"once_cell",
"winapi",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -8,3 +8,4 @@ edition = "2021"
[dependencies] [dependencies]
rand = "0.8.5" rand = "0.8.5"
debug_print = "1.0.0" debug_print = "1.0.0"
spin_sleep = "1.1.1"

View file

@ -1,10 +1,16 @@
use std::env::args; use std::env::args;
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use rand::prelude::*; use rand::prelude::*;
use debug_print::{debug_eprint, debug_eprintln}; use debug_print::{debug_eprint, debug_eprintln};
enum Flags {
RenderOnClsOnly = 1,
DelayWait = 2
}
fn main() { fn main() {
let file_path = args().nth(1); let file_path = args().nth(1);
match file_path { match file_path {
@ -12,14 +18,18 @@ fn main() {
Some(file_path) => { Some(file_path) => {
let mut file = File::open(file_path).unwrap(); let mut file = File::open(file_path).unwrap();
let mut data = Vec::new(); let mut data = Vec::new();
println!("read");
file.read_to_end(&mut data).unwrap(); file.read_to_end(&mut data).unwrap();
println!("init");
let mut chip8 = Chip8::new(); let mut chip8 = Chip8::new();
println!("loading");
chip8.load_rom(data); chip8.load_rom(data);
println!("loaded");
if args().any(|x| x == "--render-on-cls-only") {
chip8.flags |= Flags::RenderOnClsOnly as u8;
}
if args().any(|x| x == "--delay-wait") {
chip8.flags |= Flags::DelayWait as u8;
}
loop { loop {
chip8.run_next(); chip8.run_next();
} }
@ -49,7 +59,11 @@ struct Chip8 {
/// graphics (64x32 black and white) /// graphics (64x32 black and white)
display: [[bool; HEIGHT]; WIDTH], display: [[bool; HEIGHT]; WIDTH],
// start_time: Instant, // start_time: Instant,
last_processed_timers: Instant last_processed_timers: Instant,
display_changed: bool,
flags: u8
} }
const WIDTH: usize = 64; const WIDTH: usize = 64;
@ -67,7 +81,9 @@ impl Chip8 {
sound_timer: 0, sound_timer: 0,
display: [[false; HEIGHT]; WIDTH], display: [[false; HEIGHT]; WIDTH],
// start_time: Instant::now(), // start_time: Instant::now(),
last_processed_timers: Instant::now() last_processed_timers: Instant::now(),
display_changed: false,
flags: 0
}; };
// initialize font // initialize font
@ -128,6 +144,9 @@ impl Chip8 {
// syscalls // syscalls
if current == 0x00e0 { if current == 0x00e0 {
debug_eprintln!("CLS"); debug_eprintln!("CLS");
if self.display_changed {
self.render();
}
self.display = [[false; HEIGHT]; WIDTH]; self.display = [[false; HEIGHT]; WIDTH];
} else if current == 0x00ee { } else if current == 0x00ee {
if self.stack.is_empty() { if self.stack.is_empty() {
@ -248,7 +267,7 @@ impl Chip8 {
let x = (x as usize + b as usize) % WIDTH; let x = (x as usize + b as usize) % WIDTH;
// println!("x{x} y{y}"); // println!("x{x} y{y}");
self.display[x][y] ^= (sprite_row & (1 << (7-b))) > 0; self.display[x][y] ^= (sprite_row & (1 << (7-b))) > 0;
// print!("{}", if (sprite_row & (1 << (7-b))) > 0 { "█" } else { " " }); // debug_eprint!("{}", if (sprite_row & (1 << (7-b))) > 0 { "█" } else { " " });
// println!(""); // println!("");
if self.v[0xF] == 0 { if self.v[0xF] == 0 {
self.v[0xF] = if self.display[x][y] && (sprite_row & (1 << (7-b))) > 0 { 1 } else { 0 }; self.v[0xF] = if self.display[x][y] && (sprite_row & (1 << (7-b))) > 0 { 1 } else { 0 };
@ -256,16 +275,7 @@ impl Chip8 {
} }
} }
debug_eprintln!("\n-----------------------------------\n"); self.display_changed = true;
for y in 0..HEIGHT {
for x in 0..WIDTH {
// println!("x{x} y{y}");
print!("{}", if self.display[x][y] { "" } else { " " });
}
println!();
}
debug_eprintln!("\n-----------------------------------\n");
} else if first == 0xE { } else if first == 0xE {
// Keyboard operations // Keyboard operations
@ -290,6 +300,10 @@ impl Chip8 {
} else if last_two == 0x15 { } else if last_two == 0x15 {
debug_eprintln!("delay(V{second}) (V{second}={:#x}={})", self.v[second as usize], self.v[second as usize]); debug_eprintln!("delay(V{second}) (V{second}={:#x}={})", self.v[second as usize], self.v[second as usize]);
self.delay_timer = self.v[second as usize]; self.delay_timer = self.v[second as usize];
if self.flags & Flags::DelayWait as u8 != 0 {
spin_sleep::sleep(Duration::from_millis((1000 / 60) * (self.v[second as usize] as u64)));
self.delay_timer = 0;
}
} else if last_two == 0x18 { } else if last_two == 0x18 {
debug_eprintln!("sound({second})"); debug_eprintln!("sound({second})");
self.sound_timer = self.v[second as usize]; self.sound_timer = self.v[second as usize];
@ -329,18 +343,38 @@ impl Chip8 {
panic!("Halted (Program counter over ROM length)"); panic!("Halted (Program counter over ROM length)");
} }
let now = Instant::now(); let now = Instant::now();
if now - self.last_processed_timers > Duration::from_millis(16) { if now - self.last_processed_timers >= Duration::from_millis(15) {
// println!("Processing timers"); debug_eprintln!("Processing timers (duration: {:?})", now - self.last_processed_timers);
if self.sound_timer > 0 { if self.sound_timer > 0 {
print!("\x07"); print!("\x07");
self.sound_timer -= 1; self.sound_timer -= 1;
} }
if self.delay_timer > 0 { if self.delay_timer > 0 {
debug_eprint!("delay_timer: {} - 1 => ", self.delay_timer);
self.delay_timer -= 1; self.delay_timer -= 1;
// println!("delay_timer: {}", self.delay_timer); debug_eprintln!("{}", self.delay_timer);
} }
self.last_processed_timers = now;
if self.display_changed && self.flags & Flags::RenderOnClsOnly as u8 == 0 { self.render(); }
} else { } else {
// println!("Skipping timers, duration: {:?}", now - self.last_processed_timers); // println!("Skipping timers, duration: {:?}", now - self.last_processed_timers);
} }
// thread::sleep(Duration::from_micros(50));
}
fn render(&mut self) {
debug_eprintln!("\n-----------------------------------\n");
for y in 0..HEIGHT {
for x in 0..WIDTH {
// println!("x{x} y{y}");
print!("{}", if self.display[x][y] { "" } else { " " });
}
println!();
}
debug_eprintln!("\n-----------------------------------\n");
self.display_changed = false;
} }
} }