diff --git a/src/chip8.rs b/src/chip8.rs index 29da353..a77d99b 100644 --- a/src/chip8.rs +++ b/src/chip8.rs @@ -1,5 +1,4 @@ mod cpu; -mod debug; mod gpu; mod input; mod memory; @@ -13,6 +12,7 @@ static VARIABLE_REGISTER_COUNT: u8 = 16; static TIMER_TICK_RATE: f32 = 60.0; static DESIRED_FPS: f32 = 60.0; static CYCLES_PER_FRAME: f32 = 10.0; +static INSTRUCTION_BYTE_SIZE: usize = 2; #[derive(Debug, Clone)] struct Chip8State { @@ -50,7 +50,7 @@ pub struct Chip8Quirks { pub jumping: bool, } -pub fn run>(chip8_executable_filepath: S, quirks: Chip8Quirks, debug_mode: bool) { +pub fn run>(chip8_executable_filepath: S, quirks: Chip8Quirks) { let mut state = Chip8State { eti_600_flag: false, vblank_waiting: false, @@ -76,10 +76,10 @@ pub fn run>(chip8_executable_filepath: S, quirks: Chip8Quirks, deb let _ = memory::load_file_to_memory(&mut state, chip8_executable_filepath.as_ref()); // Run Program - start(state, quirks, debug_mode); + start(state, quirks); } -fn start(mut state: Chip8State, quirks: Chip8Quirks, debug_mode: bool) { +fn start(mut state: Chip8State, quirks: Chip8Quirks) { // TODO rip out as much RL stuff from here and put into renderer // Init Rendering Pipeline let (mut rl, thread) = raylib::init() @@ -91,9 +91,7 @@ fn start(mut state: Chip8State, quirks: Chip8Quirks, debug_mode: bool) { .build(); #[allow(clippy::cast_sign_loss)] rl.set_target_fps(DESIRED_FPS as u32); // Should see if i can get the users hz - if !debug_mode { - rl.set_trace_log(raylib::ffi::TraceLogLevel::LOG_NONE); - } + rl.set_trace_log(raylib::ffi::TraceLogLevel::LOG_NONE); // initialize timer let mut timer_accumulator: f32 = 0.0f32; @@ -132,17 +130,17 @@ fn start(mut state: Chip8State, quirks: Chip8Quirks, debug_mode: bool) { state.vblank_waiting = false; for _ in 0..CYCLES_PER_FRAME as i32 { - let instruction_bytes = - memory::read_n_bytes(&state.mem, state.mem.len(), state.r_pc as usize, 2); + let instruction_bytes = memory::read_n_bytes( + &state.mem, + state.mem.len(), + state.r_pc as usize, + INSTRUCTION_BYTE_SIZE, + ); let instruction: u16 = (u16::from(instruction_bytes[0]) << 8) | u16::from(instruction_bytes[1]); state.r_pc += 2; - if debug_mode { - debug::print_debug(&state, instruction); - } - - cpu::execute_instruction(&mut state, instruction, &quirks); + cpu::execute_instruction(&mut state, instruction, quirks); if state.vblank_waiting { break; diff --git a/src/chip8/cpu.rs b/src/chip8/cpu.rs index 5082321..d1807e9 100644 --- a/src/chip8/cpu.rs +++ b/src/chip8/cpu.rs @@ -1,21 +1,22 @@ +#![allow(clippy::many_single_char_names)] use crate::chip8::{Chip8Quirks, gpu}; use super::Chip8State; use super::memory::read_n_bytes; // Need to come back and add good comments for each of the match patterns -pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: &Chip8Quirks) { +pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: Chip8Quirks) { let c = ((instruction & 0xF000) >> 12) as u8; let x = ((instruction & 0x0F00) >> 8) as u8; let y = ((instruction & 0x00F0) >> 4) as u8; let d = (instruction & 0x000F) as u8; let n = d; let kk = (instruction & 0x00FF) as u8; - let nnn = (instruction & 0x0FFF) as u16; + let nnn = instruction & 0x0FFF; match (c, x, y, d) { (0x0, _, 0xE, 0x0) => { - for row in state.display.iter_mut() { + for row in &mut state.display { for col in row { *col = false; } @@ -68,9 +69,9 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: &Ch } } (0x8, _, _, 0x4) => { - 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 { - state.r_v[x as usize] = (val & 0xFFFF) as u8; + let val: u16 = u16::from(state.r_v[x as usize]) + u16::from(state.r_v[y as usize]); + if val > u16::from(u8::MAX) { + state.r_v[x as usize] = val as u8; state.r_v[0xF] = 1; } else { state.r_v[x as usize] = val as u8; @@ -80,43 +81,44 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: &Ch (0x8, _, _, 0x5) => { let flag = state.r_v[x as usize] >= state.r_v[y as usize]; state.r_v[x as usize] = state.r_v[x as usize].wrapping_sub(state.r_v[y as usize]); - state.r_v[0xF] = if flag { 1 } else { 0 }; + state.r_v[0xF] = u8::from(flag); } (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; - state.r_v[x as usize] = state.r_v[x as usize] / 2; - state.r_v[0xF] = if flag { 1 } else { 0 }; + let flag = (state.r_v[x as usize] & 0b0000_0001) == 1; + state.r_v[x as usize] /= 2; + state.r_v[0xF] = u8::from(flag); } (0x8, _, _, 0x7) => { let flag = state.r_v[x as usize] <= state.r_v[y as usize]; state.r_v[x as usize] = state.r_v[y as usize].wrapping_sub(state.r_v[x as usize]); - state.r_v[0xF] = if flag { 1 } else { 0 }; + state.r_v[0xF] = u8::from(flag); } (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] & 0b1000_0000) >> 7) == 1; 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] = u8::from(flag); } (0x9, _, _, _) => { if state.r_v[x as usize] != state.r_v[y as usize] { - state.r_pc += 2 + state.r_pc += 2; } } (0xA, _, _, _) => state.r_i = nnn, (0xB, _, _, _) => { if quirks.jumping { - state.r_pc = nnn + state.r_v[x as usize] as u16; + state.r_pc = nnn + u16::from(state.r_v[x as usize]); } else { - state.r_pc = nnn + state.r_v[0] as u16; + state.r_pc = nnn + u16::from(state.r_v[0]); } } (0xC, _, _, _) => { + #[allow(clippy::cast_sign_loss)] let rng = rand::random_range(0..256) as u8; let result = rng & kk; state.r_v[x as usize] = result; @@ -161,15 +163,15 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: &Ch } (0xF, _, 0x1, 0x5) => state.r_dt = state.r_v[x as usize], (0xF, _, 0x1, 0x8) => state.r_st = state.r_v[x as usize], - (0xF, _, 0x1, 0xE) => state.r_i = state.r_i + state.r_v[x as usize] as u16, - (0xF, _, 0x2, 0x9) => state.r_i = gpu::get_builtin_sprite_addr(x) as u16, + (0xF, _, 0x1, 0xE) => state.r_i += u16::from(state.r_v[x as usize]), + (0xF, _, 0x2, 0x9) => state.r_i = u16::from(gpu::get_builtin_sprite_addr(x)), (0xF, _, 0x3, 0x3) => { let mut decimal = state.r_v[x as usize]; let mut i = 3; loop { - i = i - 1; + i -= 1; state.mem[(state.r_i + i) as usize] = decimal % 10; - decimal = decimal / 10; + decimal /= 10; if i == 0 { break; @@ -180,15 +182,15 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: &Ch let mut i = 0; while i <= x { match y { - 0x5 => state.mem[(state.r_i + i as u16) as usize] = state.r_v[i as usize], - 0x6 => state.r_v[i as usize] = state.mem[(state.r_i + i as u16) as usize], - _ => panic!("Unmatched OPCODE 0xFx{}5", y), + 0x5 => state.mem[(state.r_i + u16::from(i)) as usize] = state.r_v[i as usize], + 0x6 => state.r_v[i as usize] = state.mem[(state.r_i + u16::from(i)) as usize], + _ => panic!("Unmatched OPCODE 0xFx{y}5"), } - i = i + 1; + i += 1; } if quirks.memory { - state.r_i += i as u16; + state.r_i += u16::from(i); } } _ => {} diff --git a/src/chip8/debug.rs b/src/chip8/debug.rs deleted file mode 100644 index e31fab7..0000000 --- a/src/chip8/debug.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::io::{self, Read}; - -use super::Chip8State; - -pub fn print_debug(state: &Chip8State, current_instruction: u16) { - print!("\x1b[H\x1b[J"); - println!("---- DEBUG ----"); - println!("PC: {:04X}", state.r_pc - 2); // -2 because of where i put this log in the main loop - println!("SP: {}", state.r_sp); - println!("I: {:04X}", state.r_i); - println!("DT: {}", state.r_dt); - println!("ST: {}", state.r_st); - for x in 0..state.r_v.len() { - if state.r_v[x] > 0 { - println!("V{}: {}", x, state.r_v[x]); - } - } - for x in 0..state.input.len() { - if state.input[x] == true { - println!("Pressed: {}", x); - } - } - println!("Current Instruction: {:04X}", current_instruction); - println!("----------------"); - // println!("Press Enter to continue..."); - // let _ = io::stdin().read(&mut [0u8]).unwrap(); -} diff --git a/src/chip8/gpu.rs b/src/chip8/gpu.rs index 65262fd..ba1d45e 100644 --- a/src/chip8/gpu.rs +++ b/src/chip8/gpu.rs @@ -10,17 +10,17 @@ pub static SPRITE_WIDTH: u8 = 8; // 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) { 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 start_x = state.r_v[vx as usize] % CHIP8_DISPLAY_WIDTH; + let start_y = state.r_v[vy as usize] % CHIP8_DISPLAY_HEIGHT; let mut bytes_idx = 0; while bytes_idx < bytes_to_draw_len { // TODO: this should be a u8 for safety - let y: u8 = start_y.wrapping_add(bytes_idx) % CHIP8_DISPLAY_HEIGHT as u8; + let y: u8 = start_y.wrapping_add(bytes_idx) % CHIP8_DISPLAY_HEIGHT; let mut bit_idx = 0; while bit_idx < SPRITE_WIDTH { - let x: u8 = start_x.wrapping_add(bit_idx) % CHIP8_DISPLAY_WIDTH as u8; + let x: u8 = start_x.wrapping_add(bit_idx) % CHIP8_DISPLAY_WIDTH; let sprite_pixel = ((bytes_to_draw[bytes_idx as usize] >> (7 - bit_idx)) & 1) == 1; if sprite_pixel { @@ -48,21 +48,21 @@ pub fn clipping_draw( 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 start_x = state.r_v[vx as usize] % CHIP8_DISPLAY_WIDTH; + let start_y = state.r_v[vy as usize] % CHIP8_DISPLAY_HEIGHT; let mut bytes_idx = 0; while bytes_idx < bytes_to_draw_len { - let y: u16 = (start_y + bytes_idx) as u16; + let y: u16 = u16::from(start_y + bytes_idx); // TODO: general reminder to cleanup type casts to be consistent - if y >= CHIP8_DISPLAY_HEIGHT as u16 { + if y >= u16::from(CHIP8_DISPLAY_HEIGHT) { break; } let mut bit_idx = 0; while bit_idx < SPRITE_WIDTH { - let x = (start_x + bit_idx) as u16; - if x >= CHIP8_DISPLAY_WIDTH as u16 { + let x = u16::from(start_x + bit_idx); + if x >= u16::from(CHIP8_DISPLAY_WIDTH) { break; } @@ -94,7 +94,7 @@ pub fn load_builtin_sprites(state: &mut Chip8State) { } pub fn get_builtin_sprite_addr(sprite_index: u8) -> u8 { - return BUILTIN_SPRITES_ADDR + (sprite_index * BUILTIN_SPRITES_SIZE); + BUILTIN_SPRITES_ADDR + (sprite_index * BUILTIN_SPRITES_SIZE) } static BUILTIN_SPRITES_ADDR: u8 = 0; diff --git a/src/chip8/input.rs b/src/chip8/input.rs index 3a86ccb..0731ac0 100644 --- a/src/chip8/input.rs +++ b/src/chip8/input.rs @@ -23,56 +23,31 @@ static RL_KEY_LAYOUT: [KeyboardKey; 16] = [ pub fn handle_input(state: &mut Chip8State, rl_hdl: &mut RaylibHandle) { for key in RL_KEY_LAYOUT { - let mapped_key = qwerty_to_chip8(key); - // let chip8_input_index = chip8_to_index(mapped_key); - if rl_hdl.is_key_down(key) { - state.input[mapped_key as usize] = true; - } else { - state.input[mapped_key as usize] = false; - } + let Ok(mapped_key) = qwerty_to_chip8(key) else { + continue; + }; + state.input[mapped_key as usize] = rl_hdl.is_key_down(key); } } -fn qwerty_to_chip8(keycode: KeyboardKey) -> u8 { +fn qwerty_to_chip8(keycode: KeyboardKey) -> Result { match keycode { - KeyboardKey::KEY_ONE => return 0x1, - KeyboardKey::KEY_TWO => return 0x2, - KeyboardKey::KEY_THREE => return 0x3, - KeyboardKey::KEY_FOUR => return 0xC, - KeyboardKey::KEY_Q => return 0x4, - KeyboardKey::KEY_W => return 0x5, - KeyboardKey::KEY_E => return 0x6, - KeyboardKey::KEY_R => return 0xD, - KeyboardKey::KEY_A => return 0x7, - KeyboardKey::KEY_S => return 0x8, - KeyboardKey::KEY_D => return 0x9, - KeyboardKey::KEY_F => return 0xE, - KeyboardKey::KEY_Z => return 0xA, - KeyboardKey::KEY_X => return 0x0, - KeyboardKey::KEY_C => return 0xB, - KeyboardKey::KEY_V => return 0xF, - _ => return 0, + KeyboardKey::KEY_ONE => Ok(0x1), + KeyboardKey::KEY_TWO => Ok(0x2), + KeyboardKey::KEY_THREE => Ok(0x3), + KeyboardKey::KEY_FOUR => Ok(0xC), + KeyboardKey::KEY_Q => Ok(0x4), + KeyboardKey::KEY_W => Ok(0x5), + KeyboardKey::KEY_E => Ok(0x6), + KeyboardKey::KEY_R => Ok(0xD), + KeyboardKey::KEY_A => Ok(0x7), + KeyboardKey::KEY_S => Ok(0x8), + KeyboardKey::KEY_D => Ok(0x9), + KeyboardKey::KEY_F => Ok(0xE), + KeyboardKey::KEY_Z => Ok(0xA), + KeyboardKey::KEY_X => Ok(0x0), + KeyboardKey::KEY_C => Ok(0xB), + KeyboardKey::KEY_V => Ok(0xF), + _ => Err(format!("Un-mapped keycode {}", keycode as u8)), } } - -// fn chip8_to_index(chip8_key: u8) -> u8 { -// match chip8_key { -// 0x1 => return 0x0, -// 0x2 => return 0x1, -// 0x3 => return 0x2, -// 0xC => return 0x3, -// 0x4 => return 0x4, -// 0x5 => return 0x5, -// 0x6 => return 0x6, -// 0xD => return 0x7, -// 0x7 => return 0x8, -// 0x8 => return 0x9, -// 0x9 => return 0xA, -// 0xE => return 0xB, -// 0xA => return 0xC, -// 0x0 => return 0xD, -// 0xB => return 0xE, -// 0xF => return 0xF, -// _ => panic!("Unknown Chip8 Key {}", chip8_key), -// } -// } diff --git a/src/chip8/memory.rs b/src/chip8/memory.rs index 49093eb..4a3c5db 100644 --- a/src/chip8/memory.rs +++ b/src/chip8/memory.rs @@ -10,34 +10,30 @@ pub fn read_n_bytes( let mut addr = start_addr; let mut bytes = Vec::new(); while addr != start_addr + n_bytes { - if addr >= buffer_len { - panic!( - "Couldn't read from Address {} exceeds buffer length {}", - addr, buffer_len - ) // nice error handling - } + assert!( + addr >= buffer_len, + "Couldn't read from Address {addr} exceeds buffer length {buffer_len}" + ); bytes.push(buffer[addr]); addr += 1; } - return bytes as Vec; + bytes as Vec } pub fn load_bytes(state: &mut Chip8State, data: &[u8], data_len: usize, start_addr: usize) { - for i in 0..data_len { - state.mem[start_addr + i] = data[i]; - } + state.mem[start_addr..(data_len + start_addr)].copy_from_slice(&data[..data_len]); } pub fn load_file_to_memory>(state: &mut Chip8State, filepath: P) -> io::Result<()> { let fp = filepath.as_ref(); // read file to Vec(u8) - let program = std::fs::read(fp)?; + let bytes = std::fs::read(fp)?; - for i in 0..program.len() { - state.mem[state.r_pc as usize + i] = program[i]; + for (i, byte) in bytes.into_iter().enumerate() { + state.mem[state.r_pc as usize + i] = byte; } // Should return Ok or Err diff --git a/src/main.rs b/src/main.rs index 822989b..c983743 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,9 +8,6 @@ mod chip8; #[derive(Parser, Debug)] #[command(version, about = "Chip 8 Emulator")] struct Args { - /// Turn on debug mode - #[arg(short, long, action = clap::ArgAction::SetTrue)] - debug: bool, /// Set path for chip8 binary file to run #[arg(short, long)] file: Option, @@ -34,10 +31,6 @@ fn main() { }; if let Some(filepath) = args.file { - if args.debug { - chip8::run(filepath, quirks, true); - } else { - chip8::run(filepath, quirks, false); - } + chip8::run(filepath, quirks); } }