diff --git a/Cargo.lock b/Cargo.lock index 2f711e9..f5ed706 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,9 +12,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "chip8" version = "0.1.0" dependencies = [ + "debug_print", "rand", ] +[[package]] +name = "debug_print" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f215f9b7224f49fb73256115331f677d868b34d18b65dbe4db392e6021eea90" + [[package]] name = "getrandom" version = "0.2.8" diff --git a/Cargo.toml b/Cargo.toml index e955530..dd5a277 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.5" \ No newline at end of file +rand = "0.8.5" +debug_print = "1.0.0" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c19c3a9..73a2641 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,9 +3,7 @@ use std::fs::File; use std::io::Read; use std::time::{Duration, Instant}; use rand::prelude::*; - -mod opcodes; - +use debug_print::{debug_eprint, debug_eprintln}; fn main() { let file_path = args().nth(1); @@ -45,13 +43,13 @@ struct Chip8 { /// sound timer (when non-zero, beeps, and decrements at 60Hz) sound_timer: u8, /// graphics (64x32 black and white) - display: [bool; 64 * 32], + display: [[bool; HEIGHT]; WIDTH], start_time: Instant, last_processed_timers: Instant } -const WIDTH: usize = 32; -const HEIGHT: usize = 64; +const WIDTH: usize = 64; +const HEIGHT: usize = 32; impl Chip8 { fn new() -> Chip8 { @@ -59,11 +57,11 @@ impl Chip8 { memory: [0; 4096], v: [0; 16], i: 0, - pc: 0x100, + pc: 0x200, stack: Vec::new(), delay_timer: 0, sound_timer: 0, - display: [false; 64 * 32], + display: [[false; HEIGHT]; WIDTH], start_time: Instant::now(), last_processed_timers: Instant::now() }; @@ -96,7 +94,7 @@ impl Chip8 { } fn run_next(&mut self) { - let current = (self.memory[self.pc as usize * 2] as u16) << 8 | (self.memory[self.pc as usize * 2 + 1] as u16); + let current = (self.memory[self.pc as usize] as u16) << 8 | (self.memory[self.pc as usize + 1] as u16); let first = ((current & 0xF000) as u16 >> 12) as u8; let first_raw = (current & 0xF000) as u16; let second = ((current & 0x0F00 as u16) >> 8 as u16) as u8; @@ -108,7 +106,7 @@ impl Chip8 { let last_two = (third_raw|fourth_raw) as u8; let after_first = current ^ (first_raw as Address); - print!("{:#x}", self.pc); + debug_eprint!("{:#x} ", self.pc); if current == 0 { dbg!(&self); @@ -120,8 +118,8 @@ impl Chip8 { if first == 0 { // syscalls if current == 0x00e0 { - println!("CLS"); - self.display = [false; 64 * 32]; + debug_eprintln!("CLS"); + self.display = [[false; HEIGHT]; WIDTH]; } else if current == 0x00ee { if self.stack.is_empty() { panic!("Stack underflow"); @@ -129,48 +127,48 @@ impl Chip8 { self.pc = self.stack.pop().unwrap(); return; } else { - println!("SYS {}", after_first); + eprintln!("SYS {}", after_first); } } else if first == 1 { // jump - println!("JP {after_first:#x} ({after_first})"); - if after_first / 2 == self.pc { + debug_eprintln!("JP {after_first:#x} ({after_first})"); + if after_first == self.pc { panic!("HALT! Jump to self (direct infinite loop)"); } - self.pc = after_first / 2; + self.pc = after_first; return; } else if first == 2 { // call - println!("CALL {}", after_first); + debug_eprintln!("CALL {}", after_first); self.stack.push(self.pc); self.pc = after_first; } else if first == 3 { // if eq - println!("SE IF V{second} == {}", last_two); - if self.v[second as usize] != last_two { - self.pc += 1; + debug_eprintln!("SE IF V{second} == {} SKIP", last_two); + if self.v[second as usize] == last_two { + self.pc += 2; } } else if first == 4 { // if not eq - println!("SNE IF V{second} != {}", last_two); - if self.v[second as usize] == last_two { - self.pc += 1; + debug_eprintln!("SNE IF V{second} != {} SKIP", last_two); + if self.v[second as usize] != last_two { + self.pc += 2; } } else if first == 5 { // if Vx == Vy if self.v[second as usize] != self.v[third as usize] { - self.pc += 1; + self.pc += 2; } } else if first == 6 { // LOAD; Vx = NN - println!("LD V{second} = {last_two:#x} ({last_two})"); + debug_eprintln!("LD V{second} = {last_two:#02x} ({last_two})"); self.v[second as usize] = last_two; } else if first == 7 { // ADD; Vx += NN - println!("ADD V{second} += {last_two:#x} ({last_two})"); + debug_eprintln!("ADD V{second} += {last_two:#x} ({last_two})"); self.v[second as usize] += last_two; } else if first == 8 { - println!("eights"); + debug_eprintln!("eights"); if fourth == 0 { self.v[second as usize] = self.v[third as usize]; } else if fourth == 1 { @@ -181,36 +179,37 @@ impl Chip8 { self.v[second as usize] ^= self.v[third as usize]; } else if fourth == 4 { self.v[second as usize] += self.v[third as usize]; - // TODO! Carry implementation + self.v[0xF] = if self.v[second as usize] as u16 + self.v[third as usize] as u16 > 255 { 1 } else { 0 }; } else if fourth == 5 { self.v[second as usize] -= self.v[third as usize]; - // TODO! Borrow implementation + self.v[0xF] = if self.v[second as usize] > self.v[third as usize] { 1 } else { 0 } } else if fourth == 6 { self.v[0xF] = self.v[second as usize] & 1; self.v[second as usize] >>= 1; } else if fourth == 7 { self.v[second as usize] = self.v[third as usize] - self.v[second as usize]; + self.v[0xF] = if self.v[third as usize] > self.v[second as usize] { 1 } else { 0 } } else if fourth == 0xE { self.v[0xF] = if (self.v[second as usize] & 0b10000000) != 0 { 1 } else { 0}; self.v[second as usize] <<= 1; } } else if first == 9 { // if Vx != Vy - println!("IF V{second} != V{third}"); + debug_eprintln!("IF V{second} != V{third}"); if self.v[second as usize] == self.v[third as usize] { - self.pc += 1; + self.pc += 2; } } else if first == 0xA { // I=NNN - println!("I={after_first:#x} ({after_first})"); + debug_eprintln!("LD I = {after_first:#x} ({after_first})"); self.i = after_first; } else if first == 0xB { - println!("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; return; } else if first == 0xC { // I=rand() & NN - println!("RND V{second} = random & {last_two:#x} ({last_two} {last_two:#b})"); + debug_eprintln!("RND V{second} = random & {last_two:#x} ({last_two} {last_two:#b})"); let random: u8 = random(); self.v[second as usize] = random & last_two; } else if first == 0xD { @@ -220,39 +219,43 @@ impl Chip8 { // sprite (bit coded XOR (set bits flip the bit value)) from I // VF set to 1 if any bit is set to 0 - println!("DRW X=V{second} Y=V{third} W=16 H={fourth}"); + debug_eprintln!("DRW X=V{second} Y=V{third} W=16 H={fourth}"); let x = self.v[second as usize] % (WIDTH as u8); let y = self.v[third as usize] % (HEIGHT as u8); let sprite_height = fourth as usize; + debug_eprintln!("X={x} Y={y}"); + self.v[0xF] = 0; - for sprite_y in 1..sprite_height+1 { - let sprite_y = (sprite_height - sprite_y + y as usize) % (HEIGHT); + for sprite_y in 0..sprite_height { + let sprite_y = sprite_y; let sprite_row = self.memory[self.i as usize + sprite_y]; - println!("\n{:#b} ({:#x})", sprite_row, sprite_row); + let y = (sprite_y + y as usize) % HEIGHT; + debug_eprintln!("\n{:#b} ({:#x})", sprite_row, sprite_row); for b in 0..8 { - let mut pos: usize = (sprite_y as usize * WIDTH) + ((b as usize) + (x as usize) % WIDTH as usize); - if (x as i16) + (b as i16) < 0 { pos += WIDTH - 1 } - // let orig = self.display[pos]; - self.display[pos] ^= (sprite_row & (1 << (7-b))) > 0; - // println!("pos{} x{} y{}", pos, pos % WIDTH, pos / WIDTH); - // println!("x{x} + y{y}*16 + {b} = {pos} .. {:#010b} = {:#010b}", 1 << (7-b), (memory & (1 << (7-b)))); + let x = (x as usize + b as usize) % WIDTH; + // println!("x{x} y{y}"); + self.display[x][y] ^= (sprite_row & (1 << (7-b))) > 0; // print!("{}", if (sprite_row & (1 << (7-b))) > 0 { "█" } else { " " }); // println!(""); if self.v[0xF] == 0 { - self.v[0xF] = if self.display[pos] && (sprite_row & (1 << (7-b))) > 0 { 1 } else { 0 }; + self.v[0xF] = if self.display[x][y] && (sprite_row & (1 << (7-b))) > 0 { 1 } else { 0 }; } } } - for x in 0..WIDTH { - for y in 0..HEIGHT { - print!("{}", if self.display[y*WIDTH + x] { "█" } else { " " }); + debug_eprintln!("\n-----------------------------------\n"); + + for y in 0..HEIGHT { + for x in 0..WIDTH { + // println!("x{x} y{y}"); + print!("{}", if self.display[x][y] { "█" } else { " " }); } println!(); } + debug_eprintln!("\n-----------------------------------\n"); } else if first == 0xE { // Keyboard operations @@ -260,33 +263,33 @@ impl Chip8 { if last_two == 0x9E { // if key() == Vx - println!("key() == V{last_two}"); + debug_eprintln!("key() == V{last_two}"); } else if last_two == 0xA1 { // if key() != Vx - println!("key() != V{last_two}"); + debug_eprintln!("key() != V{last_two}"); } } else if first == 0xF { if last_two == 0x07 { // Vx = get_delay() - println!("V{second} = delay()"); + debug_eprintln!("V{second} = delay()"); self.v[second as usize] = self.delay_timer; } else if last_two == 0x0A { // Vx = get_key() - println!("V{second} = key()"); + debug_eprintln!("V{second} = key()"); self.v[second as usize] = 0; // TODO! implement keyboard } else if last_two == 0x15 { - println!("delay(V{second})"); + debug_eprintln!("delay(V{second})"); self.delay_timer = self.v[second as usize]; } else if last_two == 0x18 { - println!("sound({second})"); + debug_eprintln!("sound({second})"); self.sound_timer = self.v[second as usize]; } else if last_two == 0x1E { - println!("I += V{second}"); + debug_eprintln!("I += V{second}"); self.i += self.v[second as usize] as u16; } else if last_two == 0x29 { // I = sprite_addr[Vx] - // Characters 0x0-0xF are represented by a 4x5 font - println!("I=sprite_addr[V{second}]"); + // Characters 0x0-0xF are represented by a 8x5 font + debug_eprintln!("I=sprite_addr[V{second}]"); self.i = (4 * 5 * second) as Address; } else if last_two == 0x33 { // Stores binary-coded decimal representation of Vx, hundreds digit at I, tens digit at I+1 and ones digit at I+2 @@ -294,24 +297,24 @@ impl Chip8 { self.memory[self.i as usize] = num / 100; self.memory[self.i as usize + 1] = num / 10 % 100; self.memory[self.i as usize + 2] = num % 10; - println!("encoded I = V{second}"); + debug_eprintln!("encoded I = V{second}"); } else if last_two == 0x55 { // reg_dump(Vx, &I) - println!("reg_dump(V{second}, I)"); + debug_eprintln!("reg_dump(V{second}, I)"); if (self.i+second as u16) as usize >= self.memory.len() { panic!("overflow with reg_dump"); } self.memory[self.i as usize..second as usize].clone_from_slice(&self.v[0..second as usize]) } else if last_two == 0x65 { // reg_load(Vx, &I) - println!("reg_load(V{second}, I)"); + debug_eprintln!("reg_load(V{second}, I)"); if (self.i+second as u16) as usize >= self.memory.len() { panic!("overflow with reg_load"); } self.v[0..second as usize].clone_from_slice(&self.memory[self.i as usize..second as usize]); } } - self.pc += 1; + self.pc += 2; if self.pc as usize > self.memory.len() { panic!("Halted (Program counter over ROM length)"); } diff --git a/src/opcodes.rs b/src/opcodes.rs deleted file mode 100644 index 1b2e142..0000000 --- a/src/opcodes.rs +++ /dev/null @@ -1,5 +0,0 @@ - -pub enum Opcode { - DisplayClear -} -