more validation tests for gemma video rendering
Adds 'doom like' 3dviprmaze-vip for demo (VERY VERY SLOW) updates egui interface to let user select from files in resources/roms updates cargo to centralize dependencies 95 passing tests
This commit is contained in:
+5
-5
@@ -5,9 +5,9 @@ edition = "2021"
|
||||
autobenches = true
|
||||
|
||||
[dependencies]
|
||||
pretty_env_logger = "0.5.0"
|
||||
rand = "0.9.0-alpha.2"
|
||||
log = "0.4.22"
|
||||
pretty_env_logger.workspace = true
|
||||
rand.workspace = true
|
||||
log.workspace = true
|
||||
# beep = "0.3.0"
|
||||
chrono = "0.4.38"
|
||||
dimensioned = "0.8.0"
|
||||
chrono.workspace = true
|
||||
dimensioned.workspace = true
|
||||
|
||||
+13
-10
@@ -58,14 +58,15 @@ impl Chip8Computer {
|
||||
self.video_memory.format_as_string()
|
||||
}
|
||||
|
||||
pub fn new_with_program(new_program: Box<Vec<u16>>) -> Self {
|
||||
pub fn new_with_program(new_program: Vec<u16>) -> Self {
|
||||
let mut working = Chip8Computer::new();
|
||||
for i in 0..new_program.len() {
|
||||
let high_byte = (new_program[i as usize] >> 8) as u8;
|
||||
let low_byte = (new_program[i] & 0xff) as u8;
|
||||
let base_offset = i * 2;
|
||||
working.memory.poke(base_offset as u16, high_byte);
|
||||
working.memory.poke((base_offset + 1) as u16, low_byte);
|
||||
|
||||
for (i, &word) in new_program.iter().enumerate() {
|
||||
let high = (word >> 8) as u8;
|
||||
let low = (word & 0xff) as u8;
|
||||
let base_offset = (i * 2) as u16;
|
||||
working.memory.poke(base_offset, high);
|
||||
working.memory.poke(base_offset + 1, low);
|
||||
}
|
||||
working
|
||||
}
|
||||
@@ -85,11 +86,12 @@ impl Chip8Computer {
|
||||
pub fn step_system(&mut self) -> &mut Chip8Computer {
|
||||
debug!("Stepping System 1 Step");
|
||||
// read the next instruction
|
||||
let local_memory = &self.memory;
|
||||
|
||||
// let mut working_instruction: u16 = 0b0000000000000000;
|
||||
let start_pc = self.registers.peek_pc();
|
||||
let high_byte = (self.memory.clone().peek(start_pc) as u16).rotate_left(8);
|
||||
let low_byte = self.memory.clone().peek(start_pc + 1) as u16;
|
||||
let high_byte = (local_memory.peek(start_pc) as u16).rotate_left(8);
|
||||
let low_byte = local_memory.peek(start_pc + 1) as u16;
|
||||
let result = high_byte | low_byte;
|
||||
let decoded_instruction =
|
||||
Chip8CpuInstructions::decode(result);
|
||||
@@ -101,9 +103,10 @@ impl Chip8Computer {
|
||||
self.sound_timer.tick();
|
||||
self.delay_timer.tick();
|
||||
self.video_memory.tick();
|
||||
self.num_cycles += 1;
|
||||
}
|
||||
Chip8CpuStates::WaitingForKey => {
|
||||
println!("waiting for a key press...");
|
||||
debug!("waiting for a key press...");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::ops::{BitAnd, Shr};
|
||||
use std::time::Instant;
|
||||
use log::debug;
|
||||
use rand::{random, Rng};
|
||||
use crate::chip8::computer::{Chip8Computer};
|
||||
@@ -417,6 +418,8 @@ impl Chip8CpuInstructions {
|
||||
}
|
||||
|
||||
pub fn execute(&self, input: &mut Chip8Computer) -> Chip8Computer {
|
||||
print!("INSTRUCTION {:04x}", self.encode());
|
||||
let start_time = Instant::now();
|
||||
let start_pc = input.registers.peek_pc();
|
||||
input.registers.poke_pc(start_pc + 2);
|
||||
let _ = match self {
|
||||
@@ -681,19 +684,16 @@ impl Chip8CpuInstructions {
|
||||
|
||||
for byte_index in 0..num_bytes_to_read {
|
||||
let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset);
|
||||
let x_offset: u16 = (x_offset + byte_index) as u16 * 64;
|
||||
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 data_offset = x_offset + (y_offset as u16 + bit_index as u16);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if did_change {
|
||||
if input.video_memory.has_frame_changed {
|
||||
input.registers.poke(0xf, 1u8);
|
||||
} else {
|
||||
input.registers.poke(0xf, 0u8);
|
||||
@@ -827,7 +827,9 @@ impl Chip8CpuInstructions {
|
||||
}
|
||||
Chip8CpuInstructions::XXXXERRORINSTRUCTION => {}
|
||||
};
|
||||
input.clone()
|
||||
let cycle_time = Instant::now().duration_since(start_time).as_nanos();
|
||||
println!("Took {cycle_time}ms");
|
||||
input.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,7 @@ impl Chip8Video {
|
||||
}
|
||||
|
||||
pub fn cls(&mut self) {
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
self.memory[i] = false;
|
||||
}
|
||||
self.memory = [false; CHIP8_VIDEO_MEMORY];
|
||||
}
|
||||
|
||||
pub fn start_frame(&mut self) {
|
||||
|
||||
@@ -4,22 +4,12 @@ use gemma::constants::CHIP8_VIDEO_MEMORY;
|
||||
#[test]
|
||||
fn smoke() { assert!(true) }
|
||||
|
||||
#[test]
|
||||
fn test_rom_1_works() {
|
||||
let mut x = Chip8Computer::new();
|
||||
// Load the IBM rom and run it.
|
||||
// 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());
|
||||
fn load_result(to_load: &str) -> String {
|
||||
std::fs::read_to_string(format!("../resources/test/{}", to_load)).unwrap()
|
||||
}
|
||||
|
||||
for i in 0..40 {
|
||||
x.step_system();
|
||||
}
|
||||
// ...then verify that the current video memory of the chip-8
|
||||
// simulator matches what we expect it to be
|
||||
|
||||
assert_eq!(x.dump_video_to_string(), std::fs::read_to_string("../resources/test/gemma_integration_ibm_rom_output.asc").unwrap());
|
||||
fn load_rom(to_load: &str) -> Vec<u8> {
|
||||
std::fs::read(format!("../resources/roms/{}", to_load)).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -39,3 +29,75 @@ fn reset_clears_video() {
|
||||
assert!(!x.video_memory.peek(i as u16));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn level1_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
let level_1_rom = load_rom("1-chip8-logo.ch8");
|
||||
x.load_bytes_to_memory(0x200, (&level_1_rom).into());
|
||||
|
||||
// run for 0x40 cycles
|
||||
while x.num_cycles < 0x40 {
|
||||
x.step_system();
|
||||
}
|
||||
assert_eq!(x.dump_video_to_string(), load_result("gemma_integration_level_1_test.asc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn level2_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
// Load the IBM rom and run it.
|
||||
// it takes 39 cycles to get to the end so lets run it 40.
|
||||
|
||||
let test_rom_to_run = load_rom("2-ibm-logo.ch8");
|
||||
x.load_bytes_to_memory(0x200, (&test_rom_to_run).into());
|
||||
|
||||
for i in 0..40 {
|
||||
x.step_system();
|
||||
}
|
||||
// ...then verify that the current video memory of the chip-8
|
||||
// simulator matches what we expect it to be
|
||||
|
||||
assert_eq!(x.dump_video_to_string(), load_result("gemma_integration_ibm_rom_output.asc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn level3_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
|
||||
x.load_bytes_to_memory(
|
||||
0x200, (&load_rom("3-corax+.ch8")).into()
|
||||
);
|
||||
for i in 0..0x180 {
|
||||
x.step_system();
|
||||
}
|
||||
|
||||
assert_eq!(x.dump_video_to_string(), load_result("gemma_integration_corax_plus.asc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rps_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.load_bytes_to_memory(0x200, &load_rom("RPS.ch8").into());
|
||||
for i in 0..0xF0 {
|
||||
x.step_system();
|
||||
}
|
||||
assert_eq!(x.dump_video_to_string(), load_result("gemma_integration_rps_stage1.asc"));
|
||||
x.keypad.push_key(0x01);
|
||||
for i in 0..0x200 {
|
||||
x.step_system();
|
||||
}
|
||||
assert_eq!(x.dump_video_to_string(), load_result("gemma_integration_rps_stage2.asc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn level4_test() {
|
||||
// flags
|
||||
let mut x = Chip8Computer::new();
|
||||
x.load_bytes_to_memory(0x200, &load_rom("4-flags.ch8").into());
|
||||
for i in 0..0x400 {
|
||||
x.step_system();
|
||||
}
|
||||
|
||||
assert_eq!(x.dump_video_to_string(), load_result("gemma_integration_flags.asc"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user