Trevor Merritt 9b64a959f3 CLEANUP: cleans up dependencies to use workspace version
CLEANUP: standardizes on pretty_env_logger
NEWBIN: Adds gemmarat to use Ratatui as an interface
CLEANUP: removes debugging display from computer.rs
ENHANCEMENT: Constants for locations of test roms built from environment
BUGFIX: SoundTimer was using i32 internally when it needs to be u8
CLEANUP: removes commented code used during diagnostics
2025-05-29 13:27:10 -04:00

123 lines
3.9 KiB
Rust

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<u8>) {
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
}
}