more debug messages, support non-standardly big ROMs

This commit is contained in:
Daniel Bulant 2023-01-26 22:09:33 +01:00
parent fe923d3df2
commit 0ee20edd71

View file

@ -1,6 +1,6 @@
use std::env::args; use std::env::args;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::{Read, Write};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use rand::prelude::*; use rand::prelude::*;
use debug_print::{debug_eprint, debug_eprintln}; use debug_print::{debug_eprint, debug_eprintln};
@ -12,10 +12,14 @@ fn main() {
Some(file_path) => { Some(file_path) => {
let mut file = File::open(file_path).unwrap(); let mut file = File::open(file_path).unwrap();
let mut data = Vec::new(); let mut data = Vec::new();
println!("read");
file.read_to_end(&mut data).unwrap(); file.read_to_end(&mut data).unwrap();
println!("init");
let mut chip8 = Chip8::new(); let mut chip8 = Chip8::new();
println!("loading");
chip8.load_rom(data); chip8.load_rom(data);
println!("loaded");
loop { loop {
chip8.run_next(); chip8.run_next();
} }
@ -24,12 +28,12 @@ fn main() {
} }
/// 12 bit address pointer /// 12 bit address pointer
type Address = u16; type Address = u32;
#[derive(Debug)] #[derive(Debug)]
struct Chip8 { struct Chip8 {
/// 4K memory /// 4K memory
memory: [u8; 262144], // 2^18 memory: Vec<u8>, // 2^18
/// registers /// registers
v: [u8; 16], v: [u8; 16],
/// current address /// current address
@ -54,7 +58,7 @@ const HEIGHT: usize = 32;
impl Chip8 { impl Chip8 {
fn new() -> Chip8 { fn new() -> Chip8 {
let mut c = Chip8 { let mut c = Chip8 {
memory: [0; 262144], memory: Vec::with_capacity(4096),
v: [0; 16], v: [0; 16],
i: 0, i: 0,
pc: 0x200, pc: 0x200,
@ -67,7 +71,7 @@ impl Chip8 {
}; };
// initialize font // initialize font
c.memory[0..80].clone_from_slice(&[ c.memory.write_all(&[
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
0x20, 0x60, 0x20, 0x20, 0x70, // 1 0x20, 0x60, 0x20, 0x20, 0x70, // 1
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
@ -84,13 +88,16 @@ impl Chip8 {
0xE0, 0x90, 0x90, 0x90, 0xE0, // D 0xE0, 0x90, 0x90, 0x90, 0xE0, // D
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
0xF0, 0x80, 0xF0, 0x80, 0x80 // F 0xF0, 0x80, 0xF0, 0x80, 0x80 // F
]); ]).expect("Failed to write font");
c.memory.resize(4096, 0);
c c
} }
fn load_rom(&mut self, rom: Vec<u8>) { fn load_rom(&mut self, rom: Vec<u8>) {
self.memory[0x200..0x200+rom.len()].clone_from_slice(&*rom); self.memory.resize(0x200, 0);
self.memory.extend_from_slice(&rom);
} }
fn run_next(&mut self) { fn run_next(&mut self) {
@ -104,13 +111,15 @@ impl Chip8 {
let fourth = (current & 0x000F) as u8; let fourth = (current & 0x000F) as u8;
let fourth_raw = (current & 0x000F) as u16; let fourth_raw = (current & 0x000F) as u16;
let last_two = (third_raw|fourth_raw) as u8; let last_two = (third_raw|fourth_raw) as u8;
let after_first = current ^ (first_raw as Address); let after_first = current ^ (first_raw as u16);
debug_eprint!("{:#x} ", self.pc); debug_eprint!("{:#x} ", self.pc);
if current == 0 { if current == 0 {
dbg!(&self); // dbg!(&self);
panic!("Null call {}", self.pc); let mut file = File::create("dump").unwrap();
file.write_all(&self.memory).unwrap();
panic!("Null call {:#x} ({})", self.pc, self.pc);
} }
// println!("{current:#04x} -> F{first_raw:#x} S{second_raw:#x} T{third_raw:#x} F{fourth_raw:#x} - !F={after_first:#x} {last_two:#x}"); // println!("{current:#04x} -> F{first_raw:#x} S{second_raw:#x} T{third_raw:#x} F{fourth_raw:#x} - !F={after_first:#x} {last_two:#x}");
@ -132,26 +141,26 @@ impl Chip8 {
} else if first == 1 { } else if first == 1 {
// jump // jump
debug_eprintln!("JP {after_first:#x} ({after_first})"); debug_eprintln!("JP {after_first:#x} ({after_first})");
if after_first == self.pc { if after_first == self.pc as u16 {
panic!("HALT! Jump to self (direct infinite loop)"); panic!("HALT! Jump to self (direct infinite loop)");
} }
self.pc = after_first; self.pc = after_first as Address;
return; return;
} else if first == 2 { } else if first == 2 {
// call // call
debug_eprintln!("CALL {after_first} {after_first:#02x}"); debug_eprintln!("CALL {after_first} {after_first:#02x}");
self.stack.push(self.pc); self.stack.push(self.pc);
self.pc = after_first; self.pc = after_first as Address;
return; return;
} else if first == 3 { } else if first == 3 {
// if eq // if eq
debug_eprintln!("SE IF V{second} == {} SKIP", last_two); debug_eprintln!("SE IF V{second} == {} SKIP (={})", last_two, self.v[second as usize]);
if self.v[second as usize] == last_two { if self.v[second as usize] == last_two {
self.pc += 2; self.pc += 2;
} }
} else if first == 4 { } else if first == 4 {
// if not eq // if not eq
debug_eprintln!("SNE IF V{second} != {} SKIP", last_two); debug_eprintln!("SNE IF V{second} != {} SKIP (={})", last_two, self.v[second as usize]);
if self.v[second as usize] != last_two { if self.v[second as usize] != last_two {
self.pc += 2; self.pc += 2;
} }
@ -203,10 +212,10 @@ impl Chip8 {
} else if first == 0xA { } else if first == 0xA {
// I=NNN // I=NNN
debug_eprintln!("LD I = {after_first:#x} ({after_first})"); debug_eprintln!("LD I = {after_first:#x} ({after_first})");
self.i = after_first; self.i = after_first as Address;
} else if first == 0xB { } else if first == 0xB {
debug_eprintln!("JP+ {} {after_first:#x} ({after_first})", self.v[0]); debug_eprintln!("JP+ {} {after_first:#x} ({after_first})", self.v[0]);
self.pc = (self.v[0] as Address) + after_first; self.pc = (self.v[0] as Address) + after_first as Address;
return; return;
} else if first == 0xC { } else if first == 0xC {
// I=rand() & NN // I=rand() & NN
@ -220,7 +229,7 @@ impl Chip8 {
// sprite (bit coded XOR (set bits flip the bit value)) from I // sprite (bit coded XOR (set bits flip the bit value)) from I
// VF set to 1 if any bit is set to 0 // VF set to 1 if any bit is set to 0
debug_eprintln!("DRW X=V{second} Y=V{third} W=16 H={fourth} I={:#x}", self.i); debug_eprintln!("DRW X=V{second} Y=V{third} W=16 H={fourth} I={:#x} ({})", self.i, self.i);
let x = self.v[second as usize] % (WIDTH as u8); let x = self.v[second as usize] % (WIDTH as u8);
let y = self.v[third as usize] % (HEIGHT as u8); let y = self.v[third as usize] % (HEIGHT as u8);
@ -272,21 +281,21 @@ impl Chip8 {
} else if first == 0xF { } else if first == 0xF {
if last_two == 0x07 { if last_two == 0x07 {
// Vx = get_delay() // Vx = get_delay()
debug_eprintln!("V{second} = delay()"); debug_eprintln!("V{second} = delay() => {:#x} ({})", self.delay_timer, self.delay_timer);
self.v[second as usize] = self.delay_timer; self.v[second as usize] = self.delay_timer;
} else if last_two == 0x0A { } else if last_two == 0x0A {
// Vx = get_key() // Vx = get_key()
debug_eprintln!("V{second} = key()"); debug_eprintln!("V{second} = key()");
self.v[second as usize] = 0; // TODO! implement keyboard self.v[second as usize] = 0; // TODO! implement keyboard
} else if last_two == 0x15 { } else if last_two == 0x15 {
debug_eprintln!("delay(V{second})"); debug_eprintln!("delay(V{second}) (V{second}={:#x}={})", self.v[second as usize], self.v[second as usize]);
self.delay_timer = self.v[second as usize]; self.delay_timer = self.v[second as usize];
} else if last_two == 0x18 { } else if last_two == 0x18 {
debug_eprintln!("sound({second})"); debug_eprintln!("sound({second})");
self.sound_timer = self.v[second as usize]; self.sound_timer = self.v[second as usize];
} else if last_two == 0x1E { } else if last_two == 0x1E {
debug_eprintln!("I += V{second} ({:#x}; {})", self.i + self.v[second as usize] as u16, self.i + self.v[second as usize] as u16); debug_eprintln!("I += V{second} ({:#x}; {})", self.i + self.v[second as usize] as Address, self.i + self.v[second as usize] as Address);
self.i += self.v[second as usize] as u16; self.i += self.v[second as usize] as Address;
} else if last_two == 0x29 { } else if last_two == 0x29 {
// I = sprite_addr[Vx] // I = sprite_addr[Vx]
// Characters 0x0-0xF are represented by a 8x5 font // Characters 0x0-0xF are represented by a 8x5 font
@ -302,14 +311,14 @@ impl Chip8 {
} else if last_two == 0x55 { } else if last_two == 0x55 {
// reg_dump(Vx, &I) // reg_dump(Vx, &I)
debug_eprintln!("reg_dump(V{second}, I)"); debug_eprintln!("reg_dump(V{second}, I)");
if (self.i+second as u16) as usize >= self.memory.len() { if (self.i+second as Address) as usize >= self.memory.len() {
panic!("overflow with reg_dump"); panic!("overflow with reg_dump");
} }
self.memory[self.i as usize..second as usize].clone_from_slice(&self.v[0..second as usize]) self.memory[self.i as usize..second as usize].clone_from_slice(&self.v[0..second as usize])
} else if last_two == 0x65 { } else if last_two == 0x65 {
// reg_load(Vx, &I) // reg_load(Vx, &I)
debug_eprintln!("reg_load(V{second}, I)"); debug_eprintln!("reg_load(V{second}, I)");
if (self.i+second as u16) as usize >= self.memory.len() { if (self.i+second as Address) as usize >= self.memory.len() {
panic!("overflow with reg_load"); panic!("overflow with reg_load");
} }
self.v[0..second as usize].clone_from_slice(&self.memory[self.i as usize..second as usize]); self.v[0..second as usize].clone_from_slice(&self.memory[self.i as usize..second as usize]);
@ -321,13 +330,17 @@ impl Chip8 {
} }
let now = Instant::now(); let now = Instant::now();
if now - self.last_processed_timers > Duration::from_millis(16) { if now - self.last_processed_timers > Duration::from_millis(16) {
// println!("Processing timers");
if self.sound_timer > 0 { if self.sound_timer > 0 {
print!("\x07"); print!("\x07");
self.sound_timer -= 1; self.sound_timer -= 1;
} }
if self.delay_timer > 0 { if self.delay_timer > 0 {
self.delay_timer -= 1; self.delay_timer -= 1;
// println!("delay_timer: {}", self.delay_timer);
} }
} else {
// println!("Skipping timers, duration: {:?}", now - self.last_processed_timers);
} }
} }
} }