emmagui isnt rendering correctly.
backend isnt writing a sprite correctly and attempting to poke outside memory
This commit is contained in:
parent
d4273dfb13
commit
b4383436aa
@ -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()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
49
emma/src/chip8/stack.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ pub mod chip8 {
|
||||
pub mod cpu_states;
|
||||
pub mod util;
|
||||
pub mod registers;
|
||||
|
||||
pub mod stack;
|
||||
}
|
||||
|
||||
pub mod constants;
|
||||
32
resources/test/test_video_zero.asc
Normal file
32
resources/test/test_video_zero.asc
Normal file
@ -0,0 +1,32 @@
|
||||
*****
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
*****
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user