fix most clippy complaints

This commit is contained in:
2026-01-31 15:32:07 -06:00
parent 266c685d1b
commit 063ca15b37
7 changed files with 82 additions and 145 deletions

View File

@@ -1,5 +1,4 @@
mod cpu; mod cpu;
mod debug;
mod gpu; mod gpu;
mod input; mod input;
mod memory; mod memory;
@@ -13,6 +12,7 @@ static VARIABLE_REGISTER_COUNT: u8 = 16;
static TIMER_TICK_RATE: f32 = 60.0; static TIMER_TICK_RATE: f32 = 60.0;
static DESIRED_FPS: f32 = 60.0; static DESIRED_FPS: f32 = 60.0;
static CYCLES_PER_FRAME: f32 = 10.0; static CYCLES_PER_FRAME: f32 = 10.0;
static INSTRUCTION_BYTE_SIZE: usize = 2;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Chip8State { struct Chip8State {
@@ -50,7 +50,7 @@ pub struct Chip8Quirks {
pub jumping: bool, pub jumping: bool,
} }
pub fn run<S: AsRef<str>>(chip8_executable_filepath: S, quirks: Chip8Quirks, debug_mode: bool) { pub fn run<S: AsRef<str>>(chip8_executable_filepath: S, quirks: Chip8Quirks) {
let mut state = Chip8State { let mut state = Chip8State {
eti_600_flag: false, eti_600_flag: false,
vblank_waiting: false, vblank_waiting: false,
@@ -76,10 +76,10 @@ pub fn run<S: AsRef<str>>(chip8_executable_filepath: S, quirks: Chip8Quirks, deb
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(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 // 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()
@@ -91,9 +91,7 @@ fn start(mut state: Chip8State, quirks: Chip8Quirks, debug_mode: bool) {
.build(); .build();
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
rl.set_target_fps(DESIRED_FPS as u32); // Should see if i can get the users hz 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 // initialize timer
let mut timer_accumulator: f32 = 0.0f32; 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; state.vblank_waiting = false;
for _ in 0..CYCLES_PER_FRAME as i32 { for _ in 0..CYCLES_PER_FRAME as i32 {
let instruction_bytes = let instruction_bytes = memory::read_n_bytes(
memory::read_n_bytes(&state.mem, state.mem.len(), state.r_pc as usize, 2); &state.mem,
state.mem.len(),
state.r_pc as usize,
INSTRUCTION_BYTE_SIZE,
);
let instruction: u16 = let instruction: u16 =
(u16::from(instruction_bytes[0]) << 8) | u16::from(instruction_bytes[1]); (u16::from(instruction_bytes[0]) << 8) | u16::from(instruction_bytes[1]);
state.r_pc += 2; state.r_pc += 2;
if debug_mode { cpu::execute_instruction(&mut state, instruction, quirks);
debug::print_debug(&state, instruction);
}
cpu::execute_instruction(&mut state, instruction, &quirks);
if state.vblank_waiting { if state.vblank_waiting {
break; break;

View File

@@ -1,21 +1,22 @@
#![allow(clippy::many_single_char_names)]
use crate::chip8::{Chip8Quirks, 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, quirks: &Chip8Quirks) { 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;
let d = (instruction & 0x000F) as u8; let d = (instruction & 0x000F) as u8;
let n = d; let n = d;
let kk = (instruction & 0x00FF) as u8; let kk = (instruction & 0x00FF) as u8;
let nnn = (instruction & 0x0FFF) as u16; let nnn = instruction & 0x0FFF;
match (c, x, y, d) { match (c, x, y, d) {
(0x0, _, 0xE, 0x0) => { (0x0, _, 0xE, 0x0) => {
for row in state.display.iter_mut() { for row in &mut state.display {
for col in row { for col in row {
*col = false; *col = false;
} }
@@ -68,9 +69,9 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: &Ch
} }
} }
(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 = u16::from(state.r_v[x as usize]) + u16::from(state.r_v[y as usize]);
if val > u8::MAX as u16 { if val > u16::from(u8::MAX) {
state.r_v[x as usize] = (val & 0xFFFF) as u8; state.r_v[x as usize] = val as u8;
state.r_v[0xF] = 1; state.r_v[0xF] = 1;
} else { } else {
state.r_v[x as usize] = val as u8; 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) => { (0x8, _, _, 0x5) => {
let flag = state.r_v[x as usize] >= state.r_v[y as usize]; 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[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) => { (0x8, _, _, 0x6) => {
if !quirks.shifting { if !quirks.shifting {
state.r_v[x as usize] = state.r_v[y as usize]; 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] & 0b0000_0001) == 1;
state.r_v[x as usize] = state.r_v[x as usize] / 2; state.r_v[x as usize] /= 2;
state.r_v[0xF] = if flag { 1 } else { 0 }; state.r_v[0xF] = u8::from(flag);
} }
(0x8, _, _, 0x7) => { (0x8, _, _, 0x7) => {
let flag = state.r_v[x as usize] <= state.r_v[y as usize]; 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[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) => { (0x8, _, _, 0xE) => {
if !quirks.shifting { if !quirks.shifting {
state.r_v[x as usize] = state.r_v[y as usize]; 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[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, _, _, _) => { (0x9, _, _, _) => {
if state.r_v[x as usize] != state.r_v[y as usize] { 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, (0xA, _, _, _) => state.r_i = nnn,
(0xB, _, _, _) => { (0xB, _, _, _) => {
if quirks.jumping { 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 { } else {
state.r_pc = nnn + state.r_v[0] as u16; state.r_pc = nnn + u16::from(state.r_v[0]);
} }
} }
(0xC, _, _, _) => { (0xC, _, _, _) => {
#[allow(clippy::cast_sign_loss)]
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;
@@ -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, 0x5) => state.r_dt = state.r_v[x as usize],
(0xF, _, 0x1, 0x8) => state.r_st = 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, _, 0x1, 0xE) => state.r_i += u16::from(state.r_v[x as usize]),
(0xF, _, 0x2, 0x9) => state.r_i = gpu::get_builtin_sprite_addr(x) as u16, (0xF, _, 0x2, 0x9) => state.r_i = u16::from(gpu::get_builtin_sprite_addr(x)),
(0xF, _, 0x3, 0x3) => { (0xF, _, 0x3, 0x3) => {
let mut decimal = state.r_v[x as usize]; let mut decimal = state.r_v[x as usize];
let mut i = 3; let mut i = 3;
loop { loop {
i = i - 1; i -= 1;
state.mem[(state.r_i + i) as usize] = decimal % 10; state.mem[(state.r_i + i) as usize] = decimal % 10;
decimal = decimal / 10; decimal /= 10;
if i == 0 { if i == 0 {
break; break;
@@ -180,15 +182,15 @@ pub fn execute_instruction(state: &mut Chip8State, instruction: u16, quirks: &Ch
let mut i = 0; let mut i = 0;
while i <= x { while i <= x {
match y { match y {
0x5 => state.mem[(state.r_i + i as u16) as usize] = state.r_v[i as usize], 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 + i as u16) as usize], 0x6 => state.r_v[i as usize] = state.mem[(state.r_i + u16::from(i)) as usize],
_ => panic!("Unmatched OPCODE 0xFx{}5", y), _ => panic!("Unmatched OPCODE 0xFx{y}5"),
} }
i = i + 1; i += 1;
} }
if quirks.memory { if quirks.memory {
state.r_i += i as u16; state.r_i += u16::from(i);
} }
} }
_ => {} _ => {}

View File

@@ -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();
}

View File

@@ -10,17 +10,17 @@ pub static SPRITE_WIDTH: u8 = 8;
// 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; state.r_v[0xF] = 0;
let start_x = state.r_v[vx as usize] % CHIP8_DISPLAY_WIDTH 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 as u8; let start_y = state.r_v[vy as usize] % CHIP8_DISPLAY_HEIGHT;
let mut bytes_idx = 0; let mut bytes_idx = 0;
while bytes_idx < bytes_to_draw_len { while bytes_idx < bytes_to_draw_len {
// TODO: this should be a u8 for safety // 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; let mut bit_idx = 0;
while bit_idx < SPRITE_WIDTH { 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; let sprite_pixel = ((bytes_to_draw[bytes_idx as usize] >> (7 - bit_idx)) & 1) == 1;
if sprite_pixel { if sprite_pixel {
@@ -48,21 +48,21 @@ pub fn clipping_draw(
bytes_to_draw_len: u8, bytes_to_draw_len: u8,
) { ) {
state.r_v[0xF] = 0; state.r_v[0xF] = 0;
let start_x = state.r_v[vx as usize] % CHIP8_DISPLAY_WIDTH 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 as u8; let start_y = state.r_v[vy as usize] % CHIP8_DISPLAY_HEIGHT;
let mut bytes_idx = 0; let mut bytes_idx = 0;
while bytes_idx < bytes_to_draw_len { 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 // 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; break;
} }
let mut bit_idx = 0; let mut bit_idx = 0;
while bit_idx < SPRITE_WIDTH { while bit_idx < SPRITE_WIDTH {
let x = (start_x + bit_idx) as u16; let x = u16::from(start_x + bit_idx);
if x >= CHIP8_DISPLAY_WIDTH as u16 { if x >= u16::from(CHIP8_DISPLAY_WIDTH) {
break; break;
} }
@@ -94,7 +94,7 @@ pub fn load_builtin_sprites(state: &mut Chip8State) {
} }
pub fn get_builtin_sprite_addr(sprite_index: u8) -> u8 { 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; static BUILTIN_SPRITES_ADDR: u8 = 0;

View File

@@ -23,56 +23,31 @@ static RL_KEY_LAYOUT: [KeyboardKey; 16] = [
pub fn handle_input(state: &mut Chip8State, rl_hdl: &mut RaylibHandle) { pub fn handle_input(state: &mut Chip8State, rl_hdl: &mut RaylibHandle) {
for key in RL_KEY_LAYOUT { for key in RL_KEY_LAYOUT {
let mapped_key = qwerty_to_chip8(key); let Ok(mapped_key) = qwerty_to_chip8(key) else {
// let chip8_input_index = chip8_to_index(mapped_key); continue;
if rl_hdl.is_key_down(key) { };
state.input[mapped_key as usize] = true; state.input[mapped_key as usize] = rl_hdl.is_key_down(key);
} else {
state.input[mapped_key as usize] = false;
}
} }
} }
fn qwerty_to_chip8(keycode: KeyboardKey) -> u8 { fn qwerty_to_chip8(keycode: KeyboardKey) -> Result<u8, String> {
match keycode { match keycode {
KeyboardKey::KEY_ONE => return 0x1, KeyboardKey::KEY_ONE => Ok(0x1),
KeyboardKey::KEY_TWO => return 0x2, KeyboardKey::KEY_TWO => Ok(0x2),
KeyboardKey::KEY_THREE => return 0x3, KeyboardKey::KEY_THREE => Ok(0x3),
KeyboardKey::KEY_FOUR => return 0xC, KeyboardKey::KEY_FOUR => Ok(0xC),
KeyboardKey::KEY_Q => return 0x4, KeyboardKey::KEY_Q => Ok(0x4),
KeyboardKey::KEY_W => return 0x5, KeyboardKey::KEY_W => Ok(0x5),
KeyboardKey::KEY_E => return 0x6, KeyboardKey::KEY_E => Ok(0x6),
KeyboardKey::KEY_R => return 0xD, KeyboardKey::KEY_R => Ok(0xD),
KeyboardKey::KEY_A => return 0x7, KeyboardKey::KEY_A => Ok(0x7),
KeyboardKey::KEY_S => return 0x8, KeyboardKey::KEY_S => Ok(0x8),
KeyboardKey::KEY_D => return 0x9, KeyboardKey::KEY_D => Ok(0x9),
KeyboardKey::KEY_F => return 0xE, KeyboardKey::KEY_F => Ok(0xE),
KeyboardKey::KEY_Z => return 0xA, KeyboardKey::KEY_Z => Ok(0xA),
KeyboardKey::KEY_X => return 0x0, KeyboardKey::KEY_X => Ok(0x0),
KeyboardKey::KEY_C => return 0xB, KeyboardKey::KEY_C => Ok(0xB),
KeyboardKey::KEY_V => return 0xF, KeyboardKey::KEY_V => Ok(0xF),
_ => return 0, _ => 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),
// }
// }

View File

@@ -10,34 +10,30 @@ pub fn read_n_bytes(
let mut addr = start_addr; let mut addr = start_addr;
let mut bytes = Vec::new(); let mut bytes = Vec::new();
while addr != start_addr + n_bytes { while addr != start_addr + n_bytes {
if addr >= buffer_len { assert!(
panic!( addr >= buffer_len,
"Couldn't read from Address {} exceeds buffer length {}", "Couldn't read from Address {addr} exceeds buffer length {buffer_len}"
addr, buffer_len );
) // nice error handling
}
bytes.push(buffer[addr]); bytes.push(buffer[addr]);
addr += 1; addr += 1;
} }
return bytes as Vec<u8>; bytes as Vec<u8>
} }
pub fn load_bytes(state: &mut Chip8State, data: &[u8], data_len: usize, start_addr: usize) { 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..(data_len + start_addr)].copy_from_slice(&data[..data_len]);
state.mem[start_addr + i] = data[i];
}
} }
pub fn load_file_to_memory<P: AsRef<Path>>(state: &mut Chip8State, filepath: P) -> io::Result<()> { pub fn load_file_to_memory<P: AsRef<Path>>(state: &mut Chip8State, filepath: P) -> io::Result<()> {
let fp = filepath.as_ref(); let fp = filepath.as_ref();
// read file to Vec(u8) // read file to Vec(u8)
let program = std::fs::read(fp)?; let bytes = std::fs::read(fp)?;
for i in 0..program.len() { for (i, byte) in bytes.into_iter().enumerate() {
state.mem[state.r_pc as usize + i] = program[i]; state.mem[state.r_pc as usize + i] = byte;
} }
// Should return Ok or Err // Should return Ok or Err

View File

@@ -8,9 +8,6 @@ mod chip8;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about = "Chip 8 Emulator")] #[command(version, about = "Chip 8 Emulator")]
struct Args { struct Args {
/// Turn on debug mode
#[arg(short, long, action = clap::ArgAction::SetTrue)]
debug: bool,
/// 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>,
@@ -34,10 +31,6 @@ fn main() {
}; };
if let Some(filepath) = args.file { if let Some(filepath) = args.file {
if args.debug { chip8::run(filepath, quirks);
chip8::run(filepath, quirks, true);
} else {
chip8::run(filepath, quirks, false);
}
} }
} }