From 448aeab1545fe463876382dbdbf2505ca58320e4 Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Mon, 14 Oct 2024 12:13:46 -0400 Subject: [PATCH] BUGFIX: Collision works better, not 100% BUGFIX: Video Reset works. --- gemma/src/chip8/instructions.rs | 21 +++++---- gemma/src/chip8/video.rs | 44 ++++++++++++------- gemma/tests/computer_tests.rs | 2 +- .../src/bin/support/gemma_egui_support.rs | 2 +- gemmaimgui/src/bin/support/emmagui_support.rs | 24 ++++++---- 5 files changed, 55 insertions(+), 38 deletions(-) diff --git a/gemma/src/chip8/instructions.rs b/gemma/src/chip8/instructions.rs index ee8bee7..8fbffe4 100644 --- a/gemma/src/chip8/instructions.rs +++ b/gemma/src/chip8/instructions.rs @@ -673,30 +673,29 @@ impl Chip8CpuInstructions { // it wraps around to the opposite side of the screen. let source_memory_offset = input.registers.peek_i(); - let x_offset = input.registers.peek(*x as u8); let y_offset = input.registers.peek(*y as u8); - debug!("X_OFFSET = {x_offset} / y_offset = {y_offset}"); - let target_memory_offset = x_offset as u16 * 64 + y_offset as u16; - debug!("CHIP8CPUINSTRUCTION:DRAWVXNIBBLE -> STARTING AT {source_memory_offset} WRITING TO {target_memory_offset}"); + // let target_memory_offset = x_offset as u16 * 64 + y_offset as u16; + let num_bytes_to_read = *n; - debug!("CHIP8CPUINSTRUCTION:DRAWVXNIBBLE -> PREPARING TO READ {num_bytes_to_read} BYTES FROM MEMORY TO VIDEO"); + let mut did_change = false; + for byte_index in 0..num_bytes_to_read { let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset); - debug!("CHIP8CPUINSTRUCTION:DRAWVXNIBBLE -> READ BYTE [0x{byte_index:2x}]\t{current_byte:02x}\t{current_byte:08b}"); for bit_index in 0..8 { let data_offset = ((x_offset as u16 + byte_index as u16) * 64) + (y_offset as u16 + bit_index as u16) as u16; - let current_bit = (current_byte.shr(7 - bit_index) & 0x1u8) == 0x1u8; + let current_bit = (current_byte & (0x80 >> bit_index)) != 0; + let previous_bit = input.video_memory.peek(data_offset); + let new_bit = previous_bit ^ current_bit; + if previous_bit && !new_bit { + did_change = true; + } input.video_memory.poke(data_offset, current_bit); } } - debug!("PPOOSSTT -> CHIP8CPUINSTRUCTION:DRAWVXNIBBLE -> {}", input.video_memory.format_as_string()); - - let mut did_change: bool = input.video_memory.has_frame_changed; - if did_change { input.registers.poke(0xf, 1u8); } else { diff --git a/gemma/src/chip8/video.rs b/gemma/src/chip8/video.rs index 29a1ba6..f50a6b9 100644 --- a/gemma/src/chip8/video.rs +++ b/gemma/src/chip8/video.rs @@ -8,16 +8,9 @@ pub struct Chip8Video { } impl Chip8Video { - fn int_cls(&self) -> Chip8Video { - let mut x = Chip8Video::default(); - for i in 0..CHIP8_VIDEO_WIDTH { - x.poke(i as u16, false); - } - x - } - - pub fn reset(&mut self) -> Self { - self.int_cls() + pub fn reset(&mut self) { + self.cls(); + self.start_frame(); } pub fn cls(&mut self) { @@ -38,10 +31,15 @@ impl Chip8Video { } pub fn peek(self, address: u16) -> bool { - self.memory[address as usize] + let effective_address = if address >= 2048 { + address - 2048 + } else { + address + }; + self.memory[effective_address as usize] } - pub fn poke(&mut self, address: u16, new_value: bool) -> Self { + pub fn poke(&mut self, address: u16, new_value: bool) { // println!("OFFSET: {address} - POKING {new_value}"); // Loop the address @@ -56,12 +54,14 @@ impl Chip8Video { let value_changed = old_value != xored_value; // From True to False is a change. self.has_frame_changed = if xored_value && value_changed { false } else { true }; + if value_changed { + self.has_frame_changed = true; + } self.memory[effective_address as usize] = xored_value; - self.to_owned() } - pub fn poke_byte(&mut self, first_address: u16, to_write: u8) -> Self { + pub fn poke_byte(&mut self, first_address: u16, to_write: u8) { for i in (0..8).rev() { let shifted = ((1 << i) & to_write) >> i; // @@ -69,7 +69,6 @@ impl Chip8Video { let is_set = shifted == 1; self.poke(target_address, is_set); } - self.to_owned() } pub fn poke_sprite(&mut self, first_address: u16, to_write: Vec) -> Self { @@ -421,7 +420,7 @@ mod test { } } - x = x.reset(); + x.reset(); assert_eq!(x.format_as_string(), read_test_result("test_reset_clears_video.asc")); } @@ -452,6 +451,17 @@ mod test { // now set a no-collision value x.poke_byte(0x00, 0b00001111); - assert_eq!(false, x.has_frame_changed); + assert_eq!(true, x.has_frame_changed); + } + + #[test] + fn peek_out_of_bounds_doesnt_panic() { + let x = Chip8Video::default(); + + let y = x.peek(2049); + let y = x.peek(0); + + // if we got here we didn't panic + assert!(true); } } diff --git a/gemma/tests/computer_tests.rs b/gemma/tests/computer_tests.rs index 3b90bf8..609352e 100644 --- a/gemma/tests/computer_tests.rs +++ b/gemma/tests/computer_tests.rs @@ -31,7 +31,7 @@ fn reset_clears_video() { } x.reset(); - x.video_memory = x.video_memory.reset(); + x.video_memory.reset(); assert_eq!(x.dump_video_to_string(), x.video_memory.format_as_string()); diff --git a/gemmaegui/src/bin/support/gemma_egui_support.rs b/gemmaegui/src/bin/support/gemma_egui_support.rs index 2b281bd..5a6f936 100644 --- a/gemmaegui/src/bin/support/gemma_egui_support.rs +++ b/gemmaegui/src/bin/support/gemma_egui_support.rs @@ -50,7 +50,7 @@ impl GemmaEguiSupport { } if ui.button("Reset").clicked() { system.reset(); - system.video_memory = system.video_memory.reset(); + system.video_memory.reset(); } if ui.button("Load initial rom").clicked() { diff --git a/gemmaimgui/src/bin/support/emmagui_support.rs b/gemmaimgui/src/bin/support/emmagui_support.rs index 745bc5f..d7cdee7 100644 --- a/gemmaimgui/src/bin/support/emmagui_support.rs +++ b/gemmaimgui/src/bin/support/emmagui_support.rs @@ -1,5 +1,6 @@ +use std::ffi::OsString; use gemma::constants::CHIP8_KEYBOARD; -use std::fs::File; +use std::fs::{File, read_dir}; use std::io::Read; use std::path::{Path, PathBuf}; use std::time::Duration; @@ -23,16 +24,23 @@ impl GuiFileList { pub fn display_path(root: PathBuf, selected_filename: &String, ui: &Ui) -> String { let mut working_filename = selected_filename.clone(); ui.text(format!("Displaying {}", root.to_str().unwrap_or("Unable to parse path"))); - for (index, entry) in std::fs::read_dir(root.as_path()).unwrap().enumerate() { - let filename = entry.unwrap().file_name(); - let filename = filename.to_str().unwrap(); - let mut working_select = ui.selectable_config(format!("{}", filename)); - if filename == selected_filename { + + let mut known_files: Vec = vec![]; + + for entry in read_dir(root.as_path()).unwrap() { + known_files.push(entry.unwrap().file_name()); + } + + known_files.sort(); + + for (index, entry) in known_files.iter().enumerate() { + let mut working_select = ui.selectable_config(format!("{}", entry.clone().into_string().unwrap())); + if entry.to_str().unwrap().to_string() == selected_filename.as_str().to_string() { working_select = working_select.selected(true); } if working_select.build() { - debug!("SELECTED {index} / {filename}"); - working_filename = filename.to_string(); + debug!("SELECTED {index} / {entry:?}"); + working_filename = entry.clone().into_string().unwrap(); }; } working_filename