working function

This commit is contained in:
Daniel Bulant 2023-01-25 11:27:50 +01:00
parent 953cc4aac6
commit 0d9850e0d4
4 changed files with 73 additions and 67 deletions

7
Cargo.lock generated
View file

@ -12,9 +12,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
name = "chip8" name = "chip8"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"debug_print",
"rand", "rand",
] ]
[[package]]
name = "debug_print"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f215f9b7224f49fb73256115331f677d868b34d18b65dbe4db392e6021eea90"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.8" version = "0.2.8"

View file

@ -7,3 +7,4 @@ edition = "2021"
[dependencies] [dependencies]
rand = "0.8.5" rand = "0.8.5"
debug_print = "1.0.0"

View file

@ -3,9 +3,7 @@ use std::fs::File;
use std::io::Read; use std::io::Read;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use rand::prelude::*; use rand::prelude::*;
use debug_print::{debug_eprint, debug_eprintln};
mod opcodes;
fn main() { fn main() {
let file_path = args().nth(1); let file_path = args().nth(1);
@ -45,13 +43,13 @@ struct Chip8 {
/// sound timer (when non-zero, beeps, and decrements at 60Hz) /// sound timer (when non-zero, beeps, and decrements at 60Hz)
sound_timer: u8, sound_timer: u8,
/// graphics (64x32 black and white) /// graphics (64x32 black and white)
display: [bool; 64 * 32], display: [[bool; HEIGHT]; WIDTH],
start_time: Instant, start_time: Instant,
last_processed_timers: Instant last_processed_timers: Instant
} }
const WIDTH: usize = 32; const WIDTH: usize = 64;
const HEIGHT: usize = 64; const HEIGHT: usize = 32;
impl Chip8 { impl Chip8 {
fn new() -> Chip8 { fn new() -> Chip8 {
@ -59,11 +57,11 @@ impl Chip8 {
memory: [0; 4096], memory: [0; 4096],
v: [0; 16], v: [0; 16],
i: 0, i: 0,
pc: 0x100, pc: 0x200,
stack: Vec::new(), stack: Vec::new(),
delay_timer: 0, delay_timer: 0,
sound_timer: 0, sound_timer: 0,
display: [false; 64 * 32], display: [[false; HEIGHT]; WIDTH],
start_time: Instant::now(), start_time: Instant::now(),
last_processed_timers: Instant::now() last_processed_timers: Instant::now()
}; };
@ -96,7 +94,7 @@ impl Chip8 {
} }
fn run_next(&mut self) { 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 = ((current & 0xF000) as u16 >> 12) as u8;
let first_raw = (current & 0xF000) as u16; let first_raw = (current & 0xF000) as u16;
let second = ((current & 0x0F00 as u16) >> 8 as u16) as u8; 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 last_two = (third_raw|fourth_raw) as u8;
let after_first = current ^ (first_raw as Address); let after_first = current ^ (first_raw as Address);
print!("{:#x}", self.pc); debug_eprint!("{:#x} ", self.pc);
if current == 0 { if current == 0 {
dbg!(&self); dbg!(&self);
@ -120,8 +118,8 @@ impl Chip8 {
if first == 0 { if first == 0 {
// syscalls // syscalls
if current == 0x00e0 { if current == 0x00e0 {
println!("CLS"); debug_eprintln!("CLS");
self.display = [false; 64 * 32]; self.display = [[false; HEIGHT]; WIDTH];
} else if current == 0x00ee { } else if current == 0x00ee {
if self.stack.is_empty() { if self.stack.is_empty() {
panic!("Stack underflow"); panic!("Stack underflow");
@ -129,48 +127,48 @@ impl Chip8 {
self.pc = self.stack.pop().unwrap(); self.pc = self.stack.pop().unwrap();
return; return;
} else { } else {
println!("SYS {}", after_first); eprintln!("SYS {}", after_first);
} }
} else if first == 1 { } else if first == 1 {
// jump // jump
println!("JP {after_first:#x} ({after_first})"); debug_eprintln!("JP {after_first:#x} ({after_first})");
if after_first / 2 == self.pc { if after_first == self.pc {
panic!("HALT! Jump to self (direct infinite loop)"); panic!("HALT! Jump to self (direct infinite loop)");
} }
self.pc = after_first / 2; self.pc = after_first;
return; return;
} else if first == 2 { } else if first == 2 {
// call // call
println!("CALL {}", after_first); debug_eprintln!("CALL {}", after_first);
self.stack.push(self.pc); self.stack.push(self.pc);
self.pc = after_first; self.pc = after_first;
} else if first == 3 { } else if first == 3 {
// if eq // if eq
println!("SE IF V{second} == {}", last_two); debug_eprintln!("SE IF V{second} == {} SKIP", last_two);
if self.v[second as usize] != last_two { if self.v[second as usize] == last_two {
self.pc += 1; self.pc += 2;
} }
} else if first == 4 { } else if first == 4 {
// if not eq // if not eq
println!("SNE IF V{second} != {}", last_two); debug_eprintln!("SNE IF V{second} != {} SKIP", last_two);
if self.v[second as usize] == last_two { if self.v[second as usize] != last_two {
self.pc += 1; self.pc += 2;
} }
} else if first == 5 { } else if first == 5 {
// if Vx == Vy // if Vx == Vy
if self.v[second as usize] != self.v[third as usize] { if self.v[second as usize] != self.v[third as usize] {
self.pc += 1; self.pc += 2;
} }
} else if first == 6 { } else if first == 6 {
// LOAD; Vx = NN // 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; self.v[second as usize] = last_two;
} else if first == 7 { } else if first == 7 {
// ADD; Vx += NN // 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; self.v[second as usize] += last_two;
} else if first == 8 { } else if first == 8 {
println!("eights"); debug_eprintln!("eights");
if fourth == 0 { if fourth == 0 {
self.v[second as usize] = self.v[third as usize]; self.v[second as usize] = self.v[third as usize];
} else if fourth == 1 { } else if fourth == 1 {
@ -181,36 +179,37 @@ impl Chip8 {
self.v[second as usize] ^= self.v[third as usize]; self.v[second as usize] ^= self.v[third as usize];
} else if fourth == 4 { } else if fourth == 4 {
self.v[second as usize] += self.v[third as usize]; 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 { } else if fourth == 5 {
self.v[second as usize] -= self.v[third as usize]; 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 { } else if fourth == 6 {
self.v[0xF] = self.v[second as usize] & 1; self.v[0xF] = self.v[second as usize] & 1;
self.v[second as usize] >>= 1; self.v[second as usize] >>= 1;
} else if fourth == 7 { } else if fourth == 7 {
self.v[second as usize] = self.v[third as usize] - self.v[second as usize]; 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 { } else if fourth == 0xE {
self.v[0xF] = if (self.v[second as usize] & 0b10000000) != 0 { 1 } else { 0}; self.v[0xF] = if (self.v[second as usize] & 0b10000000) != 0 { 1 } else { 0};
self.v[second as usize] <<= 1; self.v[second as usize] <<= 1;
} }
} else if first == 9 { } else if first == 9 {
// if Vx != Vy // 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] { if self.v[second as usize] == self.v[third as usize] {
self.pc += 1; self.pc += 2;
} }
} else if first == 0xA { } else if first == 0xA {
// I=NNN // I=NNN
println!("I={after_first:#x} ({after_first})"); debug_eprintln!("LD I = {after_first:#x} ({after_first})");
self.i = after_first; self.i = after_first;
} else if first == 0xB { } 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; self.pc = (self.v[0] as Address) + after_first;
return; return;
} else if first == 0xC { } else if first == 0xC {
// I=rand() & NN // 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(); let random: u8 = random();
self.v[second as usize] = random & last_two; self.v[second as usize] = random & last_two;
} else if first == 0xD { } else if first == 0xD {
@ -220,39 +219,43 @@ 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
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 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);
let sprite_height = fourth as usize; let sprite_height = fourth as usize;
debug_eprintln!("X={x} Y={y}");
self.v[0xF] = 0; self.v[0xF] = 0;
for sprite_y in 1..sprite_height+1 { for sprite_y in 0..sprite_height {
let sprite_y = (sprite_height - sprite_y + y as usize) % (HEIGHT); let sprite_y = sprite_y;
let sprite_row = self.memory[self.i as usize + 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 { for b in 0..8 {
let mut pos: usize = (sprite_y as usize * WIDTH) + ((b as usize) + (x as usize) % WIDTH as usize); let x = (x as usize + b as usize) % WIDTH;
if (x as i16) + (b as i16) < 0 { pos += WIDTH - 1 } // println!("x{x} y{y}");
// let orig = self.display[pos]; self.display[x][y] ^= (sprite_row & (1 << (7-b))) > 0;
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))));
// print!("{}", if (sprite_row & (1 << (7-b))) > 0 { "█" } else { " " }); // print!("{}", if (sprite_row & (1 << (7-b))) > 0 { "█" } else { " " });
// println!(""); // println!("");
if self.v[0xF] == 0 { 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 { debug_eprintln!("\n-----------------------------------\n");
for y in 0..HEIGHT {
print!("{}", if self.display[y*WIDTH + x] { "" } else { " " }); for y in 0..HEIGHT {
for x in 0..WIDTH {
// println!("x{x} y{y}");
print!("{}", if self.display[x][y] { "" } else { " " });
} }
println!(); println!();
} }
debug_eprintln!("\n-----------------------------------\n");
} else if first == 0xE { } else if first == 0xE {
// Keyboard operations // Keyboard operations
@ -260,33 +263,33 @@ impl Chip8 {
if last_two == 0x9E { if last_two == 0x9E {
// if key() == Vx // if key() == Vx
println!("key() == V{last_two}"); debug_eprintln!("key() == V{last_two}");
} else if last_two == 0xA1 { } else if last_two == 0xA1 {
// if key() != Vx // if key() != Vx
println!("key() != V{last_two}"); debug_eprintln!("key() != V{last_two}");
} }
} else if first == 0xF { } else if first == 0xF {
if last_two == 0x07 { if last_two == 0x07 {
// Vx = get_delay() // Vx = get_delay()
println!("V{second} = delay()"); debug_eprintln!("V{second} = delay()");
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()
println!("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 {
println!("delay(V{second})"); debug_eprintln!("delay(V{second})");
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 {
println!("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 {
println!("I += V{second}"); debug_eprintln!("I += V{second}");
self.i += self.v[second as usize] as u16; self.i += self.v[second as usize] as u16;
} 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 4x5 font // Characters 0x0-0xF are represented by a 8x5 font
println!("I=sprite_addr[V{second}]"); debug_eprintln!("I=sprite_addr[V{second}]");
self.i = (4 * 5 * second) as Address; self.i = (4 * 5 * second) as Address;
} else if last_two == 0x33 { } 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 // 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] = num / 100;
self.memory[self.i as usize + 1] = num / 10 % 100; self.memory[self.i as usize + 1] = num / 10 % 100;
self.memory[self.i as usize + 2] = num % 10; 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 { } else if last_two == 0x55 {
// reg_dump(Vx, &I) // 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() { if (self.i+second as u16) 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)
println!("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 u16) 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]);
} }
} }
self.pc += 1; self.pc += 2;
if self.pc as usize > self.memory.len() { if self.pc as usize > self.memory.len() {
panic!("Halted (Program counter over ROM length)"); panic!("Halted (Program counter over ROM length)");
} }

View file

@ -1,5 +0,0 @@
pub enum Opcode {
DisplayClear
}