more dump of "Emma" for Gemma
Video reset now tests ok gemma egui interface now implements stupid workaround for video reset
This commit is contained in:
+1
-9
@@ -5,17 +5,9 @@ edition = "2021"
|
||||
autobenches = true
|
||||
|
||||
[dependencies]
|
||||
ratatui = "0.28.0"
|
||||
glium = { version = "0.34.0", default-features = true }
|
||||
image = "0.23"
|
||||
imgui = { version ="0.12.0", features = ["tables-api"] }
|
||||
imgui-glium-renderer = { version = "0.12.0" }
|
||||
imgui-winit-support = { version = "0.12.0" }
|
||||
winit = { version = "0.27", features = ["x11", "mint"] }
|
||||
pretty_env_logger = "0.5.0"
|
||||
copypasta = "0.8"
|
||||
rand = "0.9.0-alpha.2"
|
||||
log = "0.4.22"
|
||||
beep = "0.3.0"
|
||||
# beep = "0.3.0"
|
||||
chrono = "0.4.38"
|
||||
dimensioned = "0.8.0"
|
||||
|
||||
@@ -37,7 +37,9 @@ impl Default for Chip8Computer {
|
||||
|
||||
impl Chip8Computer {
|
||||
pub fn reset(&mut self) -> Self{
|
||||
Self::default()
|
||||
let mut working = Chip8Computer::new();
|
||||
working.video_memory.reset();
|
||||
working
|
||||
}
|
||||
|
||||
pub fn dump_keypad_to_string(&self) -> String {
|
||||
@@ -67,7 +69,7 @@ impl Chip8Computer {
|
||||
Chip8Computer::default()
|
||||
}
|
||||
|
||||
pub fn load_bytes_to_memory(&mut self, offset: u16, to_load: Box<Vec<u8>>) {
|
||||
pub fn load_bytes_to_memory(&mut self, offset: u16, to_load: &Vec<u8>) {
|
||||
let total_len = to_load.len() as u16;
|
||||
for current_index in 0..total_len {
|
||||
let new_value = to_load[current_index as usize];
|
||||
@@ -103,17 +105,3 @@ impl Chip8Computer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::random;
|
||||
use crate::constants::CHIP8_VIDEO_MEMORY;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::ops::{BitAnd, Shl, Shr};
|
||||
use std::ops::{BitAnd, Shr};
|
||||
use log::debug;
|
||||
use rand::random;
|
||||
use crate::chip8::computer::{Chip8Computer};
|
||||
@@ -596,7 +596,7 @@ impl Chip8CpuInstructions {
|
||||
1
|
||||
};
|
||||
|
||||
println!("SUB CARRY -> REGISTER 1 = [0x{x:02x}] / [{x_register}] REGISTER 2 = [0x{y:02x}] / [{y_register}] SUB = {value_to_poke} CARRY = {new_value}");
|
||||
debug!("SUB CARRY -> REGISTER 1 = [0x{x:02x}] / [{x_register}] REGISTER 2 = [0x{y:02x}] / [{y_register}] SUB = {value_to_poke} CARRY = {new_value}");
|
||||
|
||||
input.registers.poke(*x, value_to_poke as u8);
|
||||
input.registers.poke(0xf, new_value);
|
||||
@@ -656,7 +656,7 @@ impl Chip8CpuInstructions {
|
||||
let new_value: u8 = random();
|
||||
let and_value: u8 = *byte;
|
||||
let result = new_value & and_value;
|
||||
println!("RANDOM: [{new_value:02x}] AND: [{and_value:02x} Result: [{result:02x}]");
|
||||
debug!("RANDOM: [{new_value:02x}] AND: [{and_value:02x} Result: [{result:02x}]");
|
||||
input.registers.poke(*x as u8, new_value & *byte as u8)
|
||||
}
|
||||
Chip8CpuInstructions::DrawVxVyNibble(y, x, n) => {
|
||||
@@ -837,9 +837,6 @@ impl Chip8CpuInstructions {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use dimensioned::typenum::assert_type;
|
||||
use ratatui::crossterm::execute;
|
||||
use crate::chip8::cpu_states::Chip8CpuStates;
|
||||
use crate::chip8::system_memory::{CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_9};
|
||||
use super::*;
|
||||
|
||||
@@ -1297,12 +1294,12 @@ mod test {
|
||||
x.registers.poke(0x1, 0x2);
|
||||
Chip8CpuInstructions::LdFVx(0x1).execute(&mut x);
|
||||
|
||||
assert_eq!(x.registers.peek_i(), 0x5);
|
||||
assert_eq!(x.registers.peek_i(), 10);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0x06);
|
||||
Chip8CpuInstructions::LdFVx(0x1).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_i(), 25);
|
||||
assert_eq!(x.registers.peek_i(), 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1444,8 +1441,8 @@ mod test {
|
||||
let real_bit_in_byte = 7 - bit_in_byte;
|
||||
let shifted_one = 0x01 << real_bit_in_byte;
|
||||
let one_shift_set = (shifted_one & row_data) > 0;
|
||||
println!("ROWDATA = \t\t[{row_data:08b}]\tBIT IN BYTE = \t[{bit_in_byte}]\tONE_SHIFT_SET = [{one_shift_set}]\tSHIFTED ONE = [{shifted_one:08b}]");
|
||||
println!("DATA_OFFSET FOR SOURCE DATA {}x{} is {} / offset by {}x{} and should be {} working with byte {:08b}",
|
||||
debug!("ROWDATA = \t\t[{row_data:08b}]\tBIT IN BYTE = \t[{bit_in_byte}]\tONE_SHIFT_SET = [{one_shift_set}]\tSHIFTED ONE = [{shifted_one:08b}]");
|
||||
debug!("DATA_OFFSET FOR SOURCE DATA {}x{} is {} / offset by {}x{} and should be {} working with byte {:08b}",
|
||||
bit_in_byte, row_in_sprite, data_offset, x_offset, y_offset, one_shift_set, row_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ impl Default for Chip8Stack {
|
||||
impl Chip8Stack {
|
||||
pub fn push(&mut self, new_value: &u16) {
|
||||
if self.depth() == 16 {
|
||||
println!("Deep deep stack?");
|
||||
// panic!("Stack Overflow");
|
||||
// println!("Deep deep stack?");
|
||||
panic!("Stack Overflow");
|
||||
}
|
||||
self.items.push(*new_value );
|
||||
}
|
||||
|
||||
+75
-46
@@ -1,14 +1,26 @@
|
||||
use log::{debug, trace};
|
||||
use crate::constants::CHIP8_VIDEO_MEMORY;
|
||||
use crate::constants::{CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Chip8Video {
|
||||
memory: [bool; CHIP8_VIDEO_MEMORY],
|
||||
pub has_frame_changed: bool
|
||||
pub has_frame_changed: bool,
|
||||
}
|
||||
|
||||
impl Chip8Video {
|
||||
pub fn cls(&mut self) {
|
||||
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 cls(&mut self) {
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
self.memory[i] = false;
|
||||
}
|
||||
@@ -21,7 +33,7 @@ impl Chip8Video {
|
||||
pub fn new(initial_configuration: [bool; CHIP8_VIDEO_MEMORY]) -> Self {
|
||||
Self {
|
||||
memory: initial_configuration,
|
||||
has_frame_changed: false
|
||||
has_frame_changed: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,13 +59,13 @@ impl Chip8Video {
|
||||
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) -> Self {
|
||||
for i in (0..8).rev() {
|
||||
let shifted = ((1 << i) & to_write) >> i;
|
||||
let shifted = ((1 << i) & to_write) >> i;
|
||||
//
|
||||
let target_address = first_address + (7 - i);
|
||||
let is_set = shifted == 1;
|
||||
self.poke(target_address, is_set);
|
||||
self.poke(target_address, is_set);
|
||||
}
|
||||
self.to_owned()
|
||||
}
|
||||
@@ -89,18 +101,38 @@ impl Chip8Video {
|
||||
|
||||
impl Default for Chip8Video {
|
||||
fn default() -> Self {
|
||||
Self { memory: [false; CHIP8_VIDEO_MEMORY as usize], has_frame_changed: false }
|
||||
debug!("DEFAULT VIDEO PREPARED");
|
||||
|
||||
let new_struct = Chip8Video { memory: [false; CHIP8_VIDEO_MEMORY], has_frame_changed: false };
|
||||
println!("NEW DEFAULT MEMORY : {}", new_struct.format_as_string());
|
||||
|
||||
new_struct
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use crate::chip8::system_memory::{CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7};
|
||||
use crate::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
|
||||
use super::*;
|
||||
|
||||
const TEST_OUTPUT_SAMPLE_DIR: &str = "../resources/test/";
|
||||
|
||||
fn build_checkerboard() -> Chip8Video {
|
||||
let mut r = Chip8Video::default();
|
||||
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
r.poke(i as u16, i % 2 == 0);
|
||||
}
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
fn read_test_result(suffix: &str) -> String {
|
||||
std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true) }
|
||||
|
||||
@@ -183,7 +215,7 @@ mod test {
|
||||
fn cls() {
|
||||
let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];
|
||||
let mut ws = String::new();
|
||||
// set our checkerboard
|
||||
|
||||
for cbr in 0..32 {
|
||||
for cbc in 0..64 {
|
||||
let dof = cbr * 64 + cbc;
|
||||
@@ -205,12 +237,12 @@ mod test {
|
||||
let mut v = Chip8Video::default();
|
||||
v.poke_byte(0x00, to_poke);
|
||||
assert!(v.peek(0x00));
|
||||
assert!(v.peek(0x02));
|
||||
assert!(v.peek(0x04));
|
||||
assert!(v.peek(0x06));
|
||||
assert!(!v.peek(0x01));
|
||||
assert!(v.peek(0x02));
|
||||
assert!(!v.peek(0x03));
|
||||
assert!(v.peek(0x04));
|
||||
assert!(!v.peek(0x05));
|
||||
assert!(v.peek(0x06));
|
||||
assert!(!v.peek(0x07));
|
||||
for i in 0x8..CHIP8_VIDEO_MEMORY {
|
||||
assert!(!v.peek(i as u16));
|
||||
@@ -229,7 +261,7 @@ mod test {
|
||||
|
||||
for (byte_in_set, byte_to_poke) in to_poke.iter().enumerate() {
|
||||
let base_offset = byte_in_set * 64;
|
||||
v.poke_byte(base_offset as u16, *byte_to_poke);
|
||||
v.poke_byte(base_offset as u16, *byte_to_poke);
|
||||
}
|
||||
|
||||
// row 2 column 1
|
||||
@@ -284,7 +316,7 @@ mod test {
|
||||
assert!(!v.peek(test_offset + 6));
|
||||
assert!(!v.peek(test_offset + 7));
|
||||
|
||||
let test_offset= test_offset + 0x40;
|
||||
let test_offset = test_offset + 0x40;
|
||||
assert!(v.peek(test_offset));
|
||||
assert!(v.peek(test_offset + 1));
|
||||
assert!(v.peek(test_offset + 2));
|
||||
@@ -339,53 +371,50 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn write_checkboard() {
|
||||
let mut v = Chip8Video::default();
|
||||
for current_row in 0..CHIP8_VIDEO_WIDTH {
|
||||
for current_col in 0..(CHIP8_VIDEO_HEIGHT / 8){
|
||||
let offset = current_row * CHIP8_VIDEO_HEIGHT + current_col;
|
||||
println!("CHECKBOARD OFFSET = {offset}");
|
||||
v.poke(offset as u16, offset % 2 == 0);
|
||||
}
|
||||
}
|
||||
println!("{}", v.format_as_string());
|
||||
println!("fsck is a cool tool");
|
||||
let mut v = build_checkerboard();
|
||||
|
||||
assert_eq!(v.format_as_string(), read_test_result("test_video_write_checkerboard.asc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_test() {
|
||||
let mut x = Chip8Video::default();
|
||||
|
||||
x.poke_byte(0x00, CHIP8FONT_0[0]);
|
||||
x.poke_byte(0x40, CHIP8FONT_0[1]);
|
||||
x.poke_byte(0x80, CHIP8FONT_0[2]);
|
||||
x.poke_byte(0xC0, CHIP8FONT_0[3]);
|
||||
x.poke_byte(0x100, CHIP8FONT_0[4]);
|
||||
for (byte_index, data_offset) in (0..=0x100).step_by(0x40).enumerate() {
|
||||
x.poke_byte(data_offset as u16, CHIP8FONT_0[byte_index]);
|
||||
}
|
||||
|
||||
assert_eq!(std::fs::read_to_string("../resources/test/test_video_zero.asc")
|
||||
.unwrap(),
|
||||
x.format_as_string());
|
||||
assert_eq!(read_test_result("test_video_zero.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_sprite_test() {
|
||||
let mut x = Chip8Video::default();
|
||||
// draw a row of digits 01234567
|
||||
|
||||
let start_offset = 0x00;
|
||||
let per_row_skip = 0x40;
|
||||
let to_draw = [CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7];
|
||||
for (index, sprite) in to_draw.iter().enumerate() {
|
||||
let data_base_offset = index * 0x8;
|
||||
println!("STARTING {index} at 0x{data_base_offset:04x} ({data_base_offset})");
|
||||
x.poke_byte(data_base_offset as u16, sprite[0]);
|
||||
x.poke_byte((data_base_offset + 0x40) as u16, sprite[1]);
|
||||
x.poke_byte((data_base_offset + 0x80) as u16, sprite[2]);
|
||||
x.poke_byte((data_base_offset + 0xC0) as u16, sprite[3]);
|
||||
x.poke_byte((data_base_offset + 0x100) as u16, sprite[4]);
|
||||
for (index, offset) in (0..=0x100).step_by(0x40).enumerate() {
|
||||
x.poke_byte((data_base_offset + offset) as u16, sprite[index]);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(read_test_result("test_multi_sprite.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
assert_eq!(std::fs::read_to_string("../resources/test/test_multi_sprite.asc")
|
||||
.unwrap(),
|
||||
x.format_as_string()); }
|
||||
#[test]
|
||||
fn reset_test() {
|
||||
let mut x = Chip8Video::default();
|
||||
|
||||
let to_draw = [CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7];
|
||||
for (index, sprite) in to_draw.iter().enumerate() {
|
||||
let data_base_offset = index * 0x8;
|
||||
for (index, offset) in (0..=0x100).step_by(0x40).enumerate() {
|
||||
x.poke_byte((data_base_offset + offset) as u16, sprite[index]);
|
||||
}
|
||||
}
|
||||
|
||||
x = x.reset();
|
||||
assert_eq!(x.format_as_string(), read_test_result("test_reset_clears_video.asc"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use gemma::chip8::computer::Chip8Computer;
|
||||
use gemma::constants::CHIP8_VIDEO_MEMORY;
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true) }
|
||||
@@ -10,7 +11,7 @@ fn test_rom_1_works() {
|
||||
// it takes 39 cycles to get to the end so lets run it 40.
|
||||
|
||||
let test_rom_to_run = std::fs::read("../resources/roms/2-ibm-logo.ch8").unwrap();
|
||||
x.load_bytes_to_memory(0x200, test_rom_to_run.into());
|
||||
x.load_bytes_to_memory(0x200, (&test_rom_to_run).into());
|
||||
|
||||
for i in 0..40 {
|
||||
x.step_system();
|
||||
@@ -20,3 +21,21 @@ fn test_rom_1_works() {
|
||||
|
||||
assert_eq!(x.dump_video_to_string(), std::fs::read_to_string("../resources/test/gemma_integration_ibm_rom_output.asc").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_clears_video() {
|
||||
let mut x = Chip8Computer::new();
|
||||
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
x.video_memory.poke(i as u16, i % 2 == 0);
|
||||
}
|
||||
|
||||
x.reset();
|
||||
x.video_memory = x.video_memory.reset();
|
||||
|
||||
assert_eq!(x.dump_video_to_string(), x.video_memory.format_as_string());
|
||||
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
assert!(!x.video_memory.peek(i as u16));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user