From fdea26ae7a1376fc9cb9d9bfe9620e11aab5f2fc Mon Sep 17 00:00:00 2001 From: JanNeuendorf Date: Thu, 20 Feb 2025 10:58:18 +0100 Subject: [PATCH] Added some comments and made some minor changes in preparation for extensions. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/engine.rs | 24 +++++++++++++++++++++--- src/main.rs | 19 +++++++++++++++---- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdd44bd..1bd5dc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -548,7 +548,7 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "svc16" -version = "1.0.0-beta2" +version = "1.0.0-beta3" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 03d8e69..a8083c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "svc16" -version = "1.0.0-beta2" +version = "1.0.0-beta3" edition = "2021" authors = ["Jan Neuendorf"] description = "An emulator for a simple virtual computer" diff --git a/src/engine.rs b/src/engine.rs index 5e66134..6d0a09b 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -20,11 +20,14 @@ const BAND: u16 = 13; const XOR: u16 = 14; const SYNC: u16 = 15; +// The goal is to eventually stabilize the api for the Engine so it can be easily reused in different emulators. +// This has to be postponed until the first expansions are implemented and tested. pub struct Engine { memory: Vec, screen_buffer: Vec, utility_buffer: Vec, instruction_pointer: u16, + //These are the addreses that the input should be written to (as requested by Sync). pos_code_dest: u16, key_code_dest: u16, sync_called: bool, @@ -44,6 +47,8 @@ impl Engine { pub fn new(state: T) -> Self where T: IntoIterator, + //The iterator can be shorter, in which case the rest of the memory is left as zeros. + //If it is longer, the end is never read. { let mut iter = state.into_iter(); let mut memory = vec![0; MEMSIZE]; @@ -75,17 +80,30 @@ impl Engine { self.set(self.pos_code_dest, pos_code); self.set(self.key_code_dest, key_code); } - pub fn perform_sync(&mut self, pos_code: u16, key_code: u16, buffer: &mut Vec) -> () { + pub fn perform_sync( + &mut self, + pos_code: u16, + key_code: u16, + screen_buffer_destination: &mut Vec, + ) -> Option> { self.sync_called = false; - *buffer = self.screen_buffer.clone(); + // The clone makes the API easier and doesn't seem to be to expensive in practice. + *screen_buffer_destination = self.screen_buffer.clone(); self.set_input(pos_code, key_code); + // Even if no expansion is active, triggering the mechanism must still clear the utility buffer. if self.expansion_triggered { self.expansion_triggered = false; - self.utility_buffer = vec![0; MEMSIZE]; + return Some(std::mem::replace( + &mut self.utility_buffer, + vec![0; MEMSIZE], + )); + } else { + return None; } } } impl Engine { + // Public for debugging. pub fn get(&self, index: u16) -> u16 { return self.memory[index as usize]; } diff --git a/src/main.rs b/src/main.rs index bb41f6b..8547599 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ mod cli; mod engine; mod ui; mod utils; -#[allow(unused)] +#[allow(unused)] // Usage depends on Gamepad feature use anyhow::{anyhow, Context, Result}; use clap::Parser; use cli::Cli; @@ -13,10 +13,12 @@ use macroquad::prelude::*; use std::time::{Duration, Instant}; use ui::Layout; use utils::*; -const MAX_IPF: usize = 3000000; +const MAX_IPF: usize = 3000000; // Maximum instruction can be changed here for easier testing. const FRAMETIME: Duration = Duration::from_nanos((1000000000. / 30.) as u64); fn window_conf() -> Conf { + // Both the scaling and the fullscreen options are only important for the initial launch of the window. + // You can still rescale or exit fullscreen mode. let cli = Cli::parse(); if cli.fullscreen {} @@ -34,15 +36,19 @@ async fn main() -> Result<()> { let mut cli = Cli::parse(); print_keybinds(); + // This is the raw image data. let mut buffer = vec![Color::from_rgba(255, 255, 255, 255); 256 * 256]; + let mut image = Image::gen_image_color(256, 256, Color::from_rgba(0, 0, 0, 255)); let texture = Texture2D::from_image(&image); + if cli.linear_filtering { texture.set_filter(FilterMode::Linear); } else { texture.set_filter(FilterMode::Nearest); } + // This is not the screen-buffer itself. It still needs to be synchronized. let mut raw_buffer = vec![0 as u16; 256 * 256]; let mut engine = Engine::new(read_u16s_from_file(&cli.program)?); let mut paused = false; @@ -63,6 +69,7 @@ async fn main() -> Result<()> { paused = !paused; } if is_key_pressed(KeyCode::R) { + // The current behavior is reloading the file and unpausing. engine = Engine::new(read_u16s_from_file(&cli.program)?); paused = false; } @@ -72,7 +79,9 @@ async fn main() -> Result<()> { if is_key_pressed(KeyCode::C) { cli.cursor = !cli.cursor; } - + // The size of the image in the window depends on the filtering. + // If it is linear, it is as big as it can be. + // If it is nearest, it is the largest possible integer scaling. let layout = Layout::generate(cli.linear_filtering); if !paused { ipf = 0; @@ -107,7 +116,7 @@ async fn main() -> Result<()> { if layout.cursor_in_window() { show_mouse(cli.cursor); } else { - show_mouse(true); + show_mouse(true); //The cursor is always shown when it is not on the virtual screen. } draw_texture_ex( @@ -122,6 +131,7 @@ async fn main() -> Result<()> { }, ); if cli.verbose { + // Background of the performance metrics. draw_rectangle( layout.rect_x, layout.rect_y, @@ -145,6 +155,7 @@ async fn main() -> Result<()> { std::thread::sleep(FRAMETIME - elapsed); } else { if cli.verbose { + // If you see this, the program is running too slow on your PC. println!("Frame was not processed in time"); } }