use crate::chip8::delay_timer::DelayTimer; use crate::chip8::keypad::Keypad; use crate::chip8::quirk_modes::QuirkMode; use crate::chip8::registers::Chip8Registers; use crate::chip8::sound_timer::SoundTimer; use crate::chip8::stack::Chip8Stack; use log::debug; use serde::{Deserialize, Serialize}; use super::{ cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video, }; #[derive(Clone, Serialize, Deserialize, Debug)] pub struct Chip8Computer { pub num_cycles: i32, pub memory: Chip8SystemMemory, pub registers: Chip8Registers, pub sound_timer: SoundTimer, pub delay_timer: DelayTimer, pub video_memory: Chip8Video, pub state: Chip8CpuStates, pub keypad: Keypad, pub stack: Chip8Stack, pub quirk_mode: QuirkMode, } impl PartialEq for Chip8Computer { fn eq(&self, other: &Self) -> bool { self.video_memory.format_as_string() == other.video_memory.format_as_string() && self.keypad.format_as_string() == other.keypad.format_as_string() && self.num_cycles == other.num_cycles && self.memory == other.memory } } impl Default for Chip8Computer { fn default() -> Self { Self { num_cycles: 0, memory: Chip8SystemMemory::default(), video_memory: Chip8Video::default(), registers: Chip8Registers::default(), sound_timer: SoundTimer::new(), delay_timer: DelayTimer::new(), state: Chip8CpuStates::default(), keypad: Keypad::default(), stack: Chip8Stack::default(), quirk_mode: QuirkMode::default(), } } } impl Chip8Computer { pub fn reset(&mut self, quirk_mode: QuirkMode) { self.video_memory.reset(); self.num_cycles = 0; self.registers.reset(); self.delay_timer.reset(); self.sound_timer.reset(); self.stack.reset(); self.memory.reset(quirk_mode); self.quirk_mode = quirk_mode; } pub fn dump_keypad_to_string(&self) -> String { self.keypad.format_as_string() } pub fn dump_registers_to_string(&self) -> String { self.registers.format_as_string() } pub fn dump_video_to_string(&self) -> String { self.clone().video_memory.format_as_string() } pub fn new() -> Self { Chip8Computer::default() } pub fn load_bytes_to_memory(&mut self, offset: u16, to_load: &Vec) { let total_len = to_load.len() as u16; for current_index in 0..total_len { let new_value = to_load[current_index as usize]; let new_location = current_index + offset; self.memory.poke(new_location, new_value); } self.registers.set_pc(offset); } pub fn step_system(&mut self) -> &mut Chip8Computer { // println!("Stepping System 1 Step"); // read the next instruction let local_memory = &self.memory; // let mut working_instruction: u16 = 0b0000000000000000; let start_pc = self.registers.peek_pc(); let high_byte = (local_memory.peek(start_pc) as u16).rotate_left(8); let low_byte = local_memory.peek(start_pc + 1) as u16; let result = high_byte | low_byte; let decoded_instruction = Chip8CpuInstructions::decode(result, &self.quirk_mode); // todo: THIS IS BAD AND IS A SIDE EFFECT decoded_instruction.execute(self); match self.state { Chip8CpuStates::WaitingForInstruction => { // println!("Ticking sound, delay, video"); self.sound_timer.tick(); self.delay_timer.tick(); self.video_memory.tick(); self.num_cycles += 1; } Chip8CpuStates::WaitingForKey => { debug!("waiting for a key press..."); } _ => {} } self } }