mirror of
https://github.com/danbulant/chip8
synced 2026-05-19 03:48:32 +00:00
working function
This commit is contained in:
parent
953cc4aac6
commit
0d9850e0d4
4 changed files with 73 additions and 67 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
rand = "0.8.5"
|
||||
debug_print = "1.0.0"
|
||||
125
src/main.rs
125
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)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
pub enum Opcode {
|
||||
DisplayClear
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue