From b4383436aa261695de64516d481c043886397085 Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Mon, 7 Oct 2024 13:33:35 -0400 Subject: [PATCH] emmagui isnt rendering correctly. backend isnt writing a sprite correctly and attempting to poke outside memory --- emma/src/bin/support/emmagui_support.rs | 17 ++++--- emma/src/chip8/computer.rs | 35 ++++----------- emma/src/chip8/instructions.rs | 18 +++++--- emma/src/chip8/registers.rs | 8 ++-- emma/src/chip8/stack.rs | 49 ++++++++++++++++++++ emma/src/chip8/system_memory.rs | 16 +++++++ emma/src/chip8/video.rs | 60 +++++++++++++++++++++++-- emma/src/lib.rs | 2 + resources/test/test_video_zero.asc | 32 +++++++++++++ 9 files changed, 190 insertions(+), 47 deletions(-) create mode 100644 emma/src/chip8/stack.rs create mode 100644 resources/test/test_video_zero.asc diff --git a/emma/src/bin/support/emmagui_support.rs b/emma/src/bin/support/emmagui_support.rs index 173d41d..d274f94 100644 --- a/emma/src/bin/support/emmagui_support.rs +++ b/emma/src/bin/support/emmagui_support.rs @@ -16,18 +16,23 @@ const CELL_HEIGHT: i32 = 5i32; impl EmmaGui { pub fn video_display(system_to_control: &Chip8Computer, ui: &Ui) { - ui.window("Display") + // draw area size + let draw_area_size = ui.window_size(); + let cell_width = draw_area_size[0] as i32 / 64; + let cell_height = draw_area_size[1] as i32 / 32; + + ui.window(format!("Display {cell_width}x{cell_height}")) .size([300.0, 300.0], Condition::FirstUseEver) .build(|| { let origin = ui.cursor_screen_pos(); let fg = ui.get_window_draw_list(); ui.text("This is the video display."); for current_row in 0..31 { - for current_column in 0..64 { - let x_offset = origin[0] as i32 + (current_column * 5); - let y_offset = origin[1] as i32 + (current_row * 5); + for current_column in 0..63 { + let x_offset = origin[0] as i32 + (current_column * cell_width); + let y_offset = origin[1] as i32 + (current_row * cell_height); let current_origin = [x_offset as f32, y_offset as f32]; - let current_limit = [(x_offset + 5) as f32, (y_offset + 5) as f32]; + let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32]; let memory_offset = (current_row * 64 + current_column) as u16; let to_render = system_to_control.video_memory.peek(memory_offset); let color: ImColor32 = if to_render { @@ -82,7 +87,7 @@ impl EmmaGui { ui.same_line(); ui.text(format!("DT: {:02X}", system.delay_timer.current())); ui.text(format!("PC: {:02X}", system.registers.peek_pc())); - ui.text(format!("SP: {:02X}", system.sp)); + ui.text(format!("SP: {:02X}", system.stack.depth())); }); } diff --git a/emma/src/chip8/computer.rs b/emma/src/chip8/computer.rs index bba629c..8cad874 100644 --- a/emma/src/chip8/computer.rs +++ b/emma/src/chip8/computer.rs @@ -4,6 +4,7 @@ use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION; use crate::chip8::keypad::Keypad; use crate::chip8::registers::Chip8Registers; use crate::chip8::sound_timer::SoundTimer; +use crate::chip8::stack::Chip8Stack; use crate::chip8::util::InstructionUtil; use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT}; @@ -11,28 +12,30 @@ use super::{ cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video, }; -#[derive(Clone, Copy)] +const STACK_POINTER_DEFAULT: i16 = 0x100; + +#[derive(Clone)] pub struct Chip8Computer { - pub sp: u8, pub memory: Chip8SystemMemory, pub registers: Chip8Registers, pub sound_timer: SoundTimer, pub delay_timer: DelayTimer, pub video_memory: Chip8Video, pub state: Chip8CpuStates, - pub keypad: Keypad + pub keypad: Keypad, + pub stack: Chip8Stack } impl Default for Chip8Computer { fn default() -> Self { Self { - sp: 0x00, memory: Chip8SystemMemory::default(), video_memory: Chip8Video::default(), registers: Chip8Registers::default(), sound_timer: SoundTimer::new(), delay_timer: DelayTimer::new(), - state: Chip8CpuStates::WaitingForInstruction, - keypad: Keypad::default() + state: Chip8CpuStates::default(), + keypad: Keypad::default(), + stack: Chip8Stack::default() } } } @@ -86,10 +89,8 @@ impl Chip8Computer { } _ => {} } - self } - } #[cfg(test)] @@ -103,23 +104,5 @@ mod test { assert!(true) } - - #[test] - fn new_with_program() { - // set a known program that sets some registers... - let new_program = Box::new(vec![ - Chip8CpuInstructions::LdVxI(0x10).encode(), - Chip8CpuInstructions::LdVxVy(0x1, 0x1).encode(), - Chip8CpuInstructions::LdStVx(0xff).encode() - ]); - - // ...then load it... - let test_computer = Chip8Computer::new_with_program(new_program); - - // ...and check the registers -// let (high, low) = InstructionUtil::split_bytes(Chip8CpuInstructions::LdVxI(0x10).encode()); -// assert_eq!(test_computer.memory.peek(0x200), high); - // assert_eq!(test_computer.memory.peek(0x201), low); - } } diff --git a/emma/src/chip8/instructions.rs b/emma/src/chip8/instructions.rs index 503f916..c6482ee 100644 --- a/emma/src/chip8/instructions.rs +++ b/emma/src/chip8/instructions.rs @@ -613,7 +613,8 @@ impl Chip8CpuInstructions { let x_offset = input.registers.peek(*x as u8); let y_offset = input.registers.peek(*y as u8); - let target_memory_offset = x_offset * 64 + y_offset; + println!("X_OFFSET = {x_offset} / y_offset = {y_offset}"); + let target_memory_offset = x_offset as u16 * 64 + y_offset as u16; println!("CHIP8CPUINSTRUCTION:DRAWVXNIBBLE -> STARTING AT {source_memory_offset} WRITING TO {target_memory_offset}"); let num_bytes_to_read = *n; @@ -644,6 +645,10 @@ impl Chip8CpuInstructions { // // Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2. let key_to_check = input.registers.peek(*x as u8); + let is_pressed = input.keypad.pressed(key_to_check); + if is_pressed { + input.registers.advance_pc(); + } } Chip8CpuInstructions::SnkpVx(x) => { // ExA1 - SKNP Vx @@ -656,7 +661,7 @@ impl Chip8CpuInstructions { let target_key = input.registers.peek(*x as u8); let is_pressed = input.keypad.pressed(target_key); debug!("SnKpVx [{x:1x}]"); - if is_pressed { + if !is_pressed { input.registers.advance_pc(); } } @@ -760,11 +765,10 @@ impl Chip8CpuInstructions { } Chip8CpuInstructions::XXXXERRORINSTRUCTION => {} }; - *input + input.clone() } } - #[cfg(test)] mod test { use dimensioned::typenum::assert_type; @@ -1367,7 +1371,7 @@ mod test { x.keypad.push_key(0x5); x.registers.poke(0x1, 0x5); Chip8CpuInstructions::SnkpVx(0x1).execute(&mut x); - assert_eq!(x.registers.peek_pc(), 0x204); + assert_eq!(x.registers.peek_pc(), 0x202); x.keypad.release_key(0x5); Chip8CpuInstructions::SnkpVx(0x1).execute(&mut x); @@ -1384,11 +1388,11 @@ mod test { x.keypad.push_key(0x5); x.registers.poke(0x1, 0x5); Chip8CpuInstructions::SkpVx(0x1).execute(&mut x); - assert_eq!(x.registers.peek_pc(), 0x202); + assert_eq!(x.registers.peek_pc(), 0x204); x.keypad.release_key(0x5); Chip8CpuInstructions::SkpVx(0x1).execute(&mut x); - assert_eq!(x.registers.peek_pc(), 0x204); + assert_eq!(x.registers.peek_pc(), 0x206); } #[test] diff --git a/emma/src/chip8/registers.rs b/emma/src/chip8/registers.rs index 1abd641..611b9ad 100644 --- a/emma/src/chip8/registers.rs +++ b/emma/src/chip8/registers.rs @@ -6,7 +6,8 @@ use log::debug; pub struct Chip8Registers { registers: [u8; 16], i_register: u16, - pc: u16 + pc: u16, + sp: u16 } impl Chip8Registers { @@ -20,7 +21,8 @@ impl Default for Chip8Registers { Chip8Registers { registers: [0x00; 16], i_register: 0x00, - pc: 0x200 + pc: 0x200, + sp: 0x100 } } } @@ -53,7 +55,6 @@ impl Chip8Registers { } } - #[cfg(test)] mod test { use crate::chip8::registers::Chip8Registers; @@ -77,5 +78,4 @@ mod test { x.set_pc(0x300); assert_eq!(x.peek_pc(), 0x300); } - } \ No newline at end of file diff --git a/emma/src/chip8/stack.rs b/emma/src/chip8/stack.rs new file mode 100644 index 0000000..9794da0 --- /dev/null +++ b/emma/src/chip8/stack.rs @@ -0,0 +1,49 @@ +#[derive(Clone)] +pub struct Chip8Stack { + items: Vec +} + +impl Default for Chip8Stack { + fn default() -> Self { + Chip8Stack { + items: vec![], + } + } +} + +impl Chip8Stack { + pub fn push(&mut self, new_value: &u16) { + self.items.push(*new_value ); + } + pub fn pop(&mut self) -> u16 { + self.items.pop().unwrap_or(0) + } + pub fn depth(&self) -> u16 { + self.items.len() as u16 + } + + pub fn new() -> Self { + Chip8Stack { + items: vec![] + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn smoke() { assert!(true) } + + #[test] + fn push_pop_test() { + let mut x = Chip8Stack::new(); + + // lets see if we can push and pop a bunch + x.push(&0xabcu16); + x.push(&0xcdeu16); + x.pop(); + assert_eq!(x.depth(), 1); + } +} \ No newline at end of file diff --git a/emma/src/chip8/system_memory.rs b/emma/src/chip8/system_memory.rs index a4599d7..1629d51 100644 --- a/emma/src/chip8/system_memory.rs +++ b/emma/src/chip8/system_memory.rs @@ -46,6 +46,12 @@ const cell_width: i32 = 5i32; const cell_height: i32 = 5i32; impl Chip8SystemMemory { + + pub fn new() -> Self { + Chip8SystemMemory { + memory: [0x00; CHIP8_MEMORY_SIZE as usize], + } + } pub fn peek(self, address: u16) -> u8 { trace!("PEEK: {} / {}", address, self.memory[address as usize].clone()); @@ -122,4 +128,14 @@ mod test { assert_eq!(x.peek(0), 0x01); } } + + #[test] + fn verify_load_program() { + // first line of 1-chip-logo.ch8 + let program_to_load = [0x00e0, 0x6101, 0x6008, 0xa250, 0xd01f, 0x6010, 0xa25f, 0xd01f]; + + let mut x = Chip8SystemMemory::new(); + + + } } diff --git a/emma/src/chip8/video.rs b/emma/src/chip8/video.rs index 1b5bab5..a64d864 100644 --- a/emma/src/chip8/video.rs +++ b/emma/src/chip8/video.rs @@ -6,20 +6,25 @@ use crate::constants::CHIP8_VIDEO_MEMORY; #[derive(Clone, Copy)] pub struct Chip8Video { - memory: [bool; CHIP8_VIDEO_MEMORY] + memory: [bool; CHIP8_VIDEO_MEMORY], + pub has_frame_changed: bool } impl Chip8Video { - pub fn cls(&mut self) { for i in 0..CHIP8_VIDEO_MEMORY { self.memory[i] = false; } } + pub fn start_frame(&mut self) { + self.has_frame_changed = false; + } + pub fn new(initial_configuration: [bool; CHIP8_VIDEO_MEMORY]) -> Self { Self { - memory: initial_configuration + memory: initial_configuration, + has_frame_changed: false } } @@ -30,9 +35,12 @@ impl Chip8Video { pub fn poke(&mut self, address: u16, new_value: bool) -> Self { let col = address % 64; let row = address / 32; + let offset = col * 64 + row; + println!("OFFSET: {offset} - POKING {new_value} to {address} at {col} x {row}"); let old_value = self.memory[address as usize]; if old_value != new_value { println!("**VIDEO** TOGGLING {new_value} TO {address} / {col}x{row}"); + self.has_frame_changed = true; } self.memory[address as usize] = new_value; self.to_owned() @@ -81,12 +89,15 @@ impl Chip8Video { impl Default for Chip8Video { fn default() -> Self { - Self { memory: [false; CHIP8_VIDEO_MEMORY as usize] } + Self { memory: [false; CHIP8_VIDEO_MEMORY as usize], has_frame_changed: false } } } #[cfg(test)] mod test { + use std::fs::File; + use std::io::Read; + use crate::chip8::system_memory::CHIP8FONT_0; use super::*; #[test] @@ -314,4 +325,45 @@ mod test { assert!(!v.peek(0xC6)); assert!(v.peek(0xC7)); } + + #[test] + fn verify_change_registered() { + let mut v = Chip8Video::default(); + v.poke(0x01, true); + assert!(v.has_frame_changed); + + v.start_frame(); + assert!(!v.has_frame_changed); + } + + #[test] + fn write_checkboard() { + let mut v = Chip8Video::default(); + for i in 0..(CHIP8_VIDEO_MEMORY / 8) { + v.poke_byte((i * 8) as u16, 0b10101010); + } + + println!("{}", v.format_as_string()); + println!("fsck is a cool tool"); + } + + #[test] + fn zero_test() { + let mut x = Chip8Video::default(); + + x.poke_byte(0x00, CHIP8FONT_0[0]); + x.poke_byte(0x08, CHIP8FONT_0[1]); + x.poke_byte(0x10, CHIP8FONT_0[2]); + x.poke_byte(0x18, CHIP8FONT_0[3]); + x.poke_byte(0x20, CHIP8FONT_0[4]); + + println!("SHOULD HAVE 0 AT ORIGIN"); + println!("{}", x.format_as_string()); + + let mut buf: Vec = vec![]; + // let read_file_size = File::open("../resources/test/test_video_zero.asc").unwrap().read_to_end(&mut buf).unwrap(); + + // println!("READ {read_file_size} bytes."); + // assert_eq!(String::from_utf8_lossy(&buf), x.format_as_string()); + } } diff --git a/emma/src/lib.rs b/emma/src/lib.rs index d6e4c0e..233b207 100644 --- a/emma/src/lib.rs +++ b/emma/src/lib.rs @@ -9,6 +9,8 @@ pub mod chip8 { pub mod cpu_states; pub mod util; pub mod registers; + + pub mod stack; } pub mod constants; \ No newline at end of file diff --git a/resources/test/test_video_zero.asc b/resources/test/test_video_zero.asc new file mode 100644 index 0000000..9776375 --- /dev/null +++ b/resources/test/test_video_zero.asc @@ -0,0 +1,32 @@ +***** +* * +* * +* * +***** + + + + + + + + + + + + + + + + + + + + + + + + + + +