emmagui isnt rendering correctly.

backend isnt writing a sprite correctly and attempting to poke outside memory
This commit is contained in:
Trevor Merritt 2024-10-07 13:33:35 -04:00
parent d4273dfb13
commit b4383436aa
9 changed files with 190 additions and 47 deletions

View File

@ -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()));
});
}

View File

@ -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);
}
}

View File

@ -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]

View File

@ -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);
}
}

49
emma/src/chip8/stack.rs Normal file
View File

@ -0,0 +1,49 @@
#[derive(Clone)]
pub struct Chip8Stack {
items: Vec<u16>
}
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);
}
}

View File

@ -47,6 +47,12 @@ 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());
self.memory[address as usize]
@ -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();
}
}

View File

@ -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<u8> = 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());
}
}

View File

@ -9,6 +9,8 @@ pub mod chip8 {
pub mod cpu_states;
pub mod util;
pub mod registers;
pub mod stack;
}
pub mod constants;

View File

@ -0,0 +1,32 @@
*****
* *
* *
* *
*****