a whole lotta quirk fixes
This commit is contained in:
17
src/chip8.rs
17
src/chip8.rs
@@ -38,7 +38,16 @@ struct Chip8State {
|
|||||||
input: [bool; 16],
|
input: [bool; 16],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<S: AsRef<str>>(chip8_executable_filepath: S, debug_mode: bool) {
|
pub struct Chip8Quirks {
|
||||||
|
pub vf_reset: bool,
|
||||||
|
pub memory: bool,
|
||||||
|
pub display_wait: bool, // TODO: Looks to be working, but not in quirks test file
|
||||||
|
pub clipping: bool, // TODO: Looks to be working, but not in quirks test file
|
||||||
|
pub shifting: bool,
|
||||||
|
pub jumping: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run<S: AsRef<str>>(chip8_executable_filepath: S, quirks: &Chip8Quirks, debug_mode: bool) {
|
||||||
let mut state = Chip8State {
|
let mut state = Chip8State {
|
||||||
eti_600_flag: false,
|
eti_600_flag: false,
|
||||||
mem: [0; 4096],
|
mem: [0; 4096],
|
||||||
@@ -63,10 +72,10 @@ pub fn run<S: AsRef<str>>(chip8_executable_filepath: S, debug_mode: bool) {
|
|||||||
let _ = memory::load_file_to_memory(&mut state, chip8_executable_filepath.as_ref());
|
let _ = memory::load_file_to_memory(&mut state, chip8_executable_filepath.as_ref());
|
||||||
|
|
||||||
// Run Program
|
// Run Program
|
||||||
start(&mut state, debug_mode);
|
start(&mut state, &quirks, debug_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(state: &mut Chip8State, debug_mode: bool) {
|
fn start(state: &mut Chip8State, quirks: &Chip8Quirks, debug_mode: bool) {
|
||||||
// TODO rip out as much RL stuff from here and put into renderer
|
// TODO rip out as much RL stuff from here and put into renderer
|
||||||
// Init Rendering Pipeline
|
// Init Rendering Pipeline
|
||||||
let (mut rl, thread) = raylib::init()
|
let (mut rl, thread) = raylib::init()
|
||||||
@@ -124,7 +133,7 @@ fn start(state: &mut Chip8State, debug_mode: bool) {
|
|||||||
debug::print_debug(state, instruction);
|
debug::print_debug(state, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu::execute_instruction(state, instruction);
|
cpu::execute_instruction(state, instruction, &quirks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// move to timers.rs
|
// move to timers.rs
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::chip8::gpu;
|
use crate::chip8::{Chip8Quirks, gpu};
|
||||||
|
|
||||||
use super::Chip8State;
|
use super::Chip8State;
|
||||||
use super::memory::read_n_bytes;
|
use super::memory::read_n_bytes;
|
||||||
|
|
||||||
// Need to come back and add good comments for each of the match patterns
|
// Need to come back and add good comments for each of the match patterns
|
||||||
pub fn execute_instruction(state: &mut Chip8State, instruction: u16) {
|
pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: &Chip8Quirks) {
|
||||||
let c = ((instruction & 0xF000) >> 12) as u8;
|
let c = ((instruction & 0xF000) >> 12) as u8;
|
||||||
let x = ((instruction & 0x0F00) >> 8) as u8;
|
let x = ((instruction & 0x0F00) >> 8) as u8;
|
||||||
let y = ((instruction & 0x00F0) >> 4) as u8;
|
let y = ((instruction & 0x00F0) >> 4) as u8;
|
||||||
@@ -49,9 +49,24 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16) {
|
|||||||
(0x6, _, _, _) => state.r_v[x as usize] = kk,
|
(0x6, _, _, _) => state.r_v[x as usize] = kk,
|
||||||
(0x7, _, _, _) => state.r_v[x as usize] = state.r_v[x as usize].wrapping_add(kk),
|
(0x7, _, _, _) => state.r_v[x as usize] = state.r_v[x as usize].wrapping_add(kk),
|
||||||
(0x8, _, _, 0x0) => state.r_v[x as usize] = state.r_v[y as usize],
|
(0x8, _, _, 0x0) => state.r_v[x as usize] = state.r_v[y as usize],
|
||||||
(0x8, _, _, 0x1) => state.r_v[x as usize] |= state.r_v[y as usize],
|
(0x8, _, _, 0x1) => {
|
||||||
(0x8, _, _, 0x2) => state.r_v[x as usize] &= state.r_v[y as usize],
|
state.r_v[x as usize] |= state.r_v[y as usize];
|
||||||
(0x8, _, _, 0x3) => state.r_v[x as usize] ^= state.r_v[y as usize],
|
if quirks.vf_reset {
|
||||||
|
state.r_v[0xF] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(0x8, _, _, 0x2) => {
|
||||||
|
state.r_v[x as usize] &= state.r_v[y as usize];
|
||||||
|
if quirks.vf_reset {
|
||||||
|
state.r_v[0xF] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(0x8, _, _, 0x3) => {
|
||||||
|
state.r_v[x as usize] ^= state.r_v[y as usize];
|
||||||
|
if quirks.vf_reset {
|
||||||
|
state.r_v[0xF] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
(0x8, _, _, 0x4) => {
|
(0x8, _, _, 0x4) => {
|
||||||
let val: u16 = state.r_v[x as usize] as u16 + state.r_v[y as usize] as u16;
|
let val: u16 = state.r_v[x as usize] as u16 + state.r_v[y as usize] as u16;
|
||||||
if val > u8::MAX as u16 {
|
if val > u8::MAX as u16 {
|
||||||
@@ -68,6 +83,9 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16) {
|
|||||||
state.r_v[0xF] = if flag { 1 } else { 0 };
|
state.r_v[0xF] = if flag { 1 } else { 0 };
|
||||||
}
|
}
|
||||||
(0x8, _, _, 0x6) => {
|
(0x8, _, _, 0x6) => {
|
||||||
|
if !quirks.shifting {
|
||||||
|
state.r_v[x as usize] = state.r_v[y as usize];
|
||||||
|
}
|
||||||
let flag = (state.r_v[x as usize] & 0b00000001) == 1;
|
let flag = (state.r_v[x as usize] & 0b00000001) == 1;
|
||||||
state.r_v[x as usize] = state.r_v[x as usize] / 2;
|
state.r_v[x as usize] = state.r_v[x as usize] / 2;
|
||||||
state.r_v[0xF] = if flag { 1 } else { 0 };
|
state.r_v[0xF] = if flag { 1 } else { 0 };
|
||||||
@@ -78,6 +96,9 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16) {
|
|||||||
state.r_v[0xF] = if flag { 1 } else { 0 };
|
state.r_v[0xF] = if flag { 1 } else { 0 };
|
||||||
}
|
}
|
||||||
(0x8, _, _, 0xE) => {
|
(0x8, _, _, 0xE) => {
|
||||||
|
if !quirks.shifting {
|
||||||
|
state.r_v[x as usize] = state.r_v[y as usize];
|
||||||
|
}
|
||||||
let flag = ((state.r_v[x as usize] & 0b10000000) >> 7) == 1;
|
let flag = ((state.r_v[x as usize] & 0b10000000) >> 7) == 1;
|
||||||
state.r_v[x as usize] = state.r_v[x as usize].wrapping_mul(2);
|
state.r_v[x as usize] = state.r_v[x as usize].wrapping_mul(2);
|
||||||
state.r_v[0xF] = if flag { 1 } else { 0 };
|
state.r_v[0xF] = if flag { 1 } else { 0 };
|
||||||
@@ -88,16 +109,25 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(0xA, _, _, _) => state.r_i = nnn,
|
(0xA, _, _, _) => state.r_i = nnn,
|
||||||
(0xB, _, _, _) => state.r_pc = nnn + state.r_v[0] as u16,
|
(0xB, _, _, _) => {
|
||||||
|
if quirks.jumping {
|
||||||
|
state.r_pc = nnn + state.r_v[x as usize] as u16;
|
||||||
|
} else {
|
||||||
|
state.r_pc = nnn + state.r_v[0] as u16;
|
||||||
|
}
|
||||||
|
}
|
||||||
(0xC, _, _, _) => {
|
(0xC, _, _, _) => {
|
||||||
let rng = rand::random_range(0..256) as u8;
|
let rng = rand::random_range(0..256) as u8;
|
||||||
let result = rng & kk;
|
let result = rng & kk;
|
||||||
state.r_v[x as usize] = result;
|
state.r_v[x as usize] = result;
|
||||||
}
|
}
|
||||||
(0xD, _, _, _) => {
|
(0xD, _, _, _) => {
|
||||||
state.r_v[0xF] = 0;
|
|
||||||
let bytes = read_n_bytes(&state.mem, state.mem.len(), state.r_i as usize, n as usize);
|
let bytes = read_n_bytes(&state.mem, state.mem.len(), state.r_i as usize, n as usize);
|
||||||
gpu::wrapping_draw(state, x, y, &bytes, n);
|
if quirks.clipping {
|
||||||
|
gpu::clipping_draw(state, x, y, &bytes, n);
|
||||||
|
} else {
|
||||||
|
gpu::draw(state, x, y, &bytes, n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(0xE, _, _, 0xE) => {
|
(0xE, _, _, 0xE) => {
|
||||||
let key_index = state.r_v[x as usize];
|
let key_index = state.r_v[x as usize];
|
||||||
@@ -153,6 +183,9 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16) {
|
|||||||
|
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
|
if quirks.memory {
|
||||||
|
state.r_i += i as u16;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,70 +9,74 @@ pub static SPRITE_WIDTH: u8 = 8;
|
|||||||
// I probably don't need state here
|
// I probably don't need state here
|
||||||
// refactor to just receive a mutatable buffer
|
// refactor to just receive a mutatable buffer
|
||||||
pub fn draw(state: &mut Chip8State, vx: u8, vy: u8, bytes_to_draw: &[u8], bytes_to_draw_len: u8) {
|
pub fn draw(state: &mut Chip8State, vx: u8, vy: u8, bytes_to_draw: &[u8], bytes_to_draw_len: u8) {
|
||||||
|
state.r_v[0xF] = 0;
|
||||||
|
let start_x = state.r_v[vx as usize] % CHIP8_DISPLAY_WIDTH as u8;
|
||||||
|
let start_y = state.r_v[vy as usize] % CHIP8_DISPLAY_HEIGHT as u8;
|
||||||
|
|
||||||
let mut bytes_idx = 0;
|
let mut bytes_idx = 0;
|
||||||
let start_x = state.r_v[vx as usize];
|
while bytes_idx < bytes_to_draw_len {
|
||||||
let start_y = state.r_v[vy as usize];
|
// TODO: this should be a u8 for safety
|
||||||
for y in start_y..start_y + bytes_to_draw_len {
|
let y: u8 = start_y.wrapping_add(bytes_idx) % CHIP8_DISPLAY_HEIGHT as u8;
|
||||||
println!("{}", bytes_idx);
|
|
||||||
if (y as i32) < CHIP8_DISPLAY_HEIGHT {
|
|
||||||
// 8 is the hardcoded sprite width, has to atleast have 1 8 bit value to display
|
|
||||||
let mut bit_idx = 0;
|
let mut bit_idx = 0;
|
||||||
for x in start_x..start_x + SPRITE_WIDTH {
|
while bit_idx < SPRITE_WIDTH {
|
||||||
println!("(X,Y): ({},{})", x, y);
|
let x: u8 = start_x.wrapping_add(bit_idx) % CHIP8_DISPLAY_WIDTH as u8;
|
||||||
if (x as i32) < CHIP8_DISPLAY_WIDTH {
|
|
||||||
let sprite_pixel = ((bytes_to_draw[bytes_idx] >> (7 - bit_idx)) & 1) == 1;
|
let sprite_pixel = ((bytes_to_draw[bytes_idx as usize] >> (7 - bit_idx)) & 1) == 1;
|
||||||
|
if sprite_pixel {
|
||||||
let current_pixel = state.display[y as usize][x as usize];
|
let current_pixel = state.display[y as usize][x as usize];
|
||||||
let new_pixel = current_pixel ^ sprite_pixel;
|
|
||||||
|
|
||||||
state.display[y as usize][x as usize] = new_pixel;
|
if current_pixel {
|
||||||
|
|
||||||
if new_pixel != current_pixel {
|
|
||||||
state.r_v[0xF] = 1;
|
state.r_v[0xF] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.display[y as usize][x as usize] ^= true;
|
||||||
|
}
|
||||||
|
|
||||||
bit_idx += 1;
|
bit_idx += 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
bytes_idx += 1;
|
bytes_idx += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wrapping_draw(
|
pub fn clipping_draw(
|
||||||
state: &mut Chip8State,
|
state: &mut Chip8State,
|
||||||
vx: u8,
|
vx: u8,
|
||||||
vy: u8,
|
vy: u8,
|
||||||
bytes_to_draw: &[u8],
|
bytes_to_draw: &[u8],
|
||||||
bytes_to_draw_len: u8,
|
bytes_to_draw_len: u8,
|
||||||
) {
|
) {
|
||||||
let mut bytes_idx = 0;
|
state.r_v[0xF] = 0;
|
||||||
let start_x = state.r_v[vx as usize];
|
let start_x = state.r_v[vx as usize] % CHIP8_DISPLAY_WIDTH as u8;
|
||||||
let start_y = state.r_v[vy as usize];
|
let start_y = state.r_v[vy as usize] % CHIP8_DISPLAY_HEIGHT as u8;
|
||||||
|
|
||||||
|
let mut bytes_idx = 0;
|
||||||
while bytes_idx < bytes_to_draw_len {
|
while bytes_idx < bytes_to_draw_len {
|
||||||
let mut y = start_y.wrapping_add(bytes_idx);
|
let y: u16 = (start_y + bytes_idx) as u16;
|
||||||
if y as i32 >= CHIP8_DISPLAY_HEIGHT {
|
// TODO: general reminder to cleanup type casts to be consistent
|
||||||
y = (y - CHIP8_DISPLAY_HEIGHT as u8) % CHIP8_DISPLAY_HEIGHT as u8;
|
if y >= CHIP8_DISPLAY_HEIGHT as u16 {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bit_idx = 0;
|
let mut bit_idx = 0;
|
||||||
|
|
||||||
while bit_idx < SPRITE_WIDTH {
|
while bit_idx < SPRITE_WIDTH {
|
||||||
let mut x = start_x.wrapping_add(bit_idx);
|
let x = (start_x + bit_idx) as u16;
|
||||||
if x as i32 >= CHIP8_DISPLAY_WIDTH {
|
if x >= CHIP8_DISPLAY_WIDTH as u16 {
|
||||||
x = (x - CHIP8_DISPLAY_WIDTH as u8) % CHIP8_DISPLAY_WIDTH as u8;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sprite_pixel = ((bytes_to_draw[bytes_idx as usize] >> (7 - bit_idx)) & 1) == 1;
|
let sprite_pixel = ((bytes_to_draw[bytes_idx as usize] >> (7 - bit_idx)) & 1) == 1;
|
||||||
|
if sprite_pixel {
|
||||||
let current_pixel = state.display[y as usize][x as usize];
|
let current_pixel = state.display[y as usize][x as usize];
|
||||||
let new_pixel = current_pixel ^ sprite_pixel;
|
|
||||||
|
|
||||||
state.display[y as usize][x as usize] = new_pixel;
|
if current_pixel {
|
||||||
|
|
||||||
if new_pixel != current_pixel {
|
|
||||||
state.r_v[0xF] = 1;
|
state.r_v[0xF] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.display[y as usize][x as usize] ^= true;
|
||||||
|
}
|
||||||
|
|
||||||
bit_idx += 1;
|
bit_idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
src/main.rs
18
src/main.rs
@@ -11,17 +11,29 @@ struct Args {
|
|||||||
/// Set path for chip8 binary file to run
|
/// Set path for chip8 binary file to run
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
file: Option<String>,
|
file: Option<String>,
|
||||||
|
#[arg(short = 'q', long = "quirks", value_delimiter = ',')]
|
||||||
|
quirks: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
// TODO: should define my raylib/sound/etc handles here eventually and pass them down
|
let quirks = chip8::Chip8Quirks {
|
||||||
|
vf_reset: args.quirks.contains(&String::from("vfreset"))
|
||||||
|
|| args.quirks.contains(&String::from("chip8")),
|
||||||
|
memory: args.quirks.contains(&String::from("memory"))
|
||||||
|
|| args.quirks.contains(&String::from("chip8")),
|
||||||
|
display_wait: args.quirks.contains(&String::from("displaywait")),
|
||||||
|
clipping: args.quirks.contains(&String::from("clipping"))
|
||||||
|
|| args.quirks.contains(&String::from("chip8")),
|
||||||
|
shifting: args.quirks.contains(&String::from("shifting")),
|
||||||
|
jumping: args.quirks.contains(&String::from("jumping")),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(filepath) = args.file {
|
if let Some(filepath) = args.file {
|
||||||
if args.debug {
|
if args.debug {
|
||||||
chip8::run(filepath, true);
|
chip8::run(filepath, &quirks, true);
|
||||||
} else {
|
} else {
|
||||||
chip8::run(filepath, false);
|
chip8::run(filepath, &quirks, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user