add test chip8 file

more decoder and executor code
lots and lots more tests.  lots and lots and lots and lots more needed
This commit is contained in:
Trevor Merritt 2024-09-23 16:12:52 -04:00
parent c8259157c5
commit d6f7c73de3
8 changed files with 396 additions and 187 deletions

BIN
1-chip8-logo.ch8 Normal file

Binary file not shown.

1
Cargo.lock generated
View File

@ -884,6 +884,7 @@ dependencies = [
"imgui", "imgui",
"imgui-glium-renderer", "imgui-glium-renderer",
"imgui-winit-support", "imgui-winit-support",
"log",
"pretty_env_logger", "pretty_env_logger",
"rand 0.9.0-alpha.2", "rand 0.9.0-alpha.2",
"ratatui", "ratatui",

View File

@ -15,3 +15,4 @@ winit = { version = "0.27", features = ["x11", "mint"] }
pretty_env_logger = "0.5.0" pretty_env_logger = "0.5.0"
copypasta = "0.8" copypasta = "0.8"
rand = "0.9.0-alpha.2" rand = "0.9.0-alpha.2"
log = "0.4.22"

View File

@ -37,13 +37,13 @@ fn hello_world_window(ui: &Ui) {
fn main() { fn main() {
pretty_env_logger::init();
let mut system = Chip8Computer::default(); let mut system = Chip8Computer::default();
support::simple_init(file!(), move |_, ui| { support::simple_init(file!(), move |_, ui| {
// hello_world_window(ui); // hello_world_window(ui);
EmmaGui::system_controls(&mut system, ui); EmmaGui::system_controls(&mut system, ui);
EmmaGui::registers_view(&system, ui); EmmaGui::registers_view(&system, ui);
EmmaGui::hex_memory_display(system.memory.clone(), 0x100, 0x10,ui); EmmaGui::hex_memory_display(system.memory.clone(), 0x100, 0x10,ui);

View File

@ -1,3 +1,8 @@
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;
use imgui::{Condition, ImColor32, Ui}; use imgui::{Condition, ImColor32, Ui};
use emmaemu::chip8::computer::Chip8Computer; use emmaemu::chip8::computer::Chip8Computer;
use emmaemu::chip8::system_memory::Chip8SystemMemory; use emmaemu::chip8::system_memory::Chip8SystemMemory;
@ -19,10 +24,12 @@ impl EmmaGui {
system_to_control.step_system(); system_to_control.step_system();
}; };
if ui.button("Load Program") { if ui.button("Load Program") {
println!("Load a program to start at 0x200"); let mut buffer = Vec::new();
}
if ui.button("Clear System Memory") { println!("PREPARING TO LOAD 1-chip8-logo.ch8");
println!("Clear Memory"); let mut input_file = File::open(Path::new("./1-chip8-logo.ch8")).expect("put 1-chip8-logo.ch8 in this directory");
input_file.read_to_end(&mut buffer).expect("unable to read file");
system_to_control.load_bytes_to_memory(0x200, buffer.into());
} }
}); });
} }
@ -70,13 +77,13 @@ impl EmmaGui {
if ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]) { if ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]) {
// Optionally change the text color to indicate it's interactable // Optionally change the text color to indicate it's interactable
ui.text_colored([1.0, 0.0, 0.0, 1.0], formatted_text); ui.text_colored([1.0, 0.0, 0.0, 1.0], formatted_text.clone());
current_x_hover = current_column; current_x_hover = current_column;
current_y_hover = current_row; current_y_hover = current_row;
// Check if the left mouse button is clicked while hovering over the text // Check if the left mouse button is clicked while hovering over the text
if ui.is_mouse_clicked(imgui::MouseButton::Left) { if ui.is_mouse_clicked(imgui::MouseButton::Left) {
println!("Text was clicked!"); println!("Offset: [{}] [0x{:02x}] Value: [{}]", data_offset, data_offset, formatted_text.clone());
// Perform any action here, e.g., call a function, trigger an event, etc. // Perform any action here, e.g., call a function, trigger an event, etc.
} }
} else { } else {

View File

@ -1,7 +1,9 @@
use log::{debug, error};
use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;
use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT}; use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT};
use super::{ use super::{
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video,
}; };
@ -15,7 +17,7 @@ pub struct Chip8Computer {
pub delay_timer: u8, pub delay_timer: u8,
pub i_register: u16, pub i_register: u16,
pub video_memory: Chip8Video, pub video_memory: Chip8Video,
pub state: Chip8CpuStates pub state: Chip8CpuStates,
} }
impl Default for Chip8Computer { impl Default for Chip8Computer {
@ -29,7 +31,7 @@ impl Default for Chip8Computer {
sound_timer: 0xFF, sound_timer: 0xFF,
delay_timer: 0xFF, delay_timer: 0xFF,
i_register: 0x0000, i_register: 0x0000,
state: Chip8CpuStates::WaitingForInstruction state: Chip8CpuStates::WaitingForInstruction,
} }
} }
} }
@ -39,7 +41,16 @@ impl Chip8Computer {
Chip8Computer::default() Chip8Computer::default()
} }
pub fn step_system(mut self) -> Self { pub fn load_bytes_to_memory(&mut self, offset: u16, to_load: Box<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);
}
}
pub fn step_system(&mut self) -> Self {
// read the next instruction // read the next instruction
let mut working_instruction: u16 = 0b0000000000000000; let mut working_instruction: u16 = 0b0000000000000000;
@ -48,250 +59,294 @@ impl Chip8Computer {
working_instruction = high_byte | low_byte; working_instruction = high_byte | low_byte;
let decoded_instruction = let decoded_instruction =
Chip8Computer::decode_instruction(self.clone(), working_instruction); Chip8Computer::decode_instruction(working_instruction);
println!("DECODED INSTRUCTION = {:?}", decoded_instruction); println!("DECODED INSTRUCTION = {:?}", decoded_instruction);
match (self.state, decoded_instruction) { match (self.state, decoded_instruction) {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SysAddr(target_address)) => { (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SysAddr(target_address)) => {
debug!("INST: SYS: {target_address}");
self.pc = target_address as u16; self.pc = target_address as u16;
}, }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CLS) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CLS) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RET) => todo!(), debug!("INST: CLS");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpAddr(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CallAddr(_)) => todo!(), }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxByte(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RET) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxByte(_, _)) => todo!(), debug!("INST: RET");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxVy(_, _)) => todo!(), }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxByte(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpAddr(new_address)) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxByte(_, _)) => todo!(), debug!("INST: JP_ADDR: {new_address}");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxVy(_, _)) => todo!(), self.pc = new_address as u16;
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::OrVxVy(_, _)) => todo!(), }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AndVxVy(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CallAddr(sub_address)) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::XorVxVy(_, _)) => todo!(), debug!("INST: CALL_ADDR: {sub_address}");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxVy(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubVxVy(_, _)) => todo!(), }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShrVxVy(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxByte(vx_register, byte)) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubnVxVy(_, _)) => todo!(), debug!("INST: SeVxByte: {vx_register}/{byte}");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShlVxVy(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxVy(_, _)) => todo!(), }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIAddr(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxByte(vx_register, byte)) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpV0Addr(_)) => todo!(), debug!("INST: SneVxByte: {vx_register}/{byte}");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RndVxByte(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::DrawVxVyNibble(_, _, _)) => todo!(), }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SkpVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SnkpVx(_)) => todo!(), debug!("INST: SeVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxDt(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxK(_)) => todo!(), }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdDtVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxByte(vx_register, byte)) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdStVx(_)) => todo!(), debug!("INST: LdVxByte: {vx_register}/{byte}");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddIVx(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdFVu(_)) => todo!(), }
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdBVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxByte(vx_register, byte)) => {
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIVx(_)) => todo!(), debug!("INST: AddVxByte: {vx_register}/{byte}");
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxI(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::XXXXERRORINSTRUCTION) => todo!(), }
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SysAddr(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::CLS) => todo!(), debug!("INST: LdVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::RET) => todo!(), self.registers[vx_register as usize] = self.registers[vy_register as usize];
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::JpAddr(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::CallAddr(_)) => todo!(), }
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SeVxByte(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::OrVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SneVxByte(_, _)) => todo!(), debug!("INST: OrVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SeVxVy(_, _)) => todo!(), self.registers[vx_register as usize] = self.registers[vx_register as usize] | self.registers[vy_register as usize];
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxByte(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::AddVxByte(_, _)) => todo!(), }
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxVy(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AndVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::OrVxVy(_, _)) => todo!(), debug!("INST: AndVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::AndVxVy(_, _)) => todo!(), self.registers[vx_register as usize] = self.registers[vx_register as usize] & self.registers[vy_register as usize];
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::XorVxVy(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::AddVxVy(_, _)) => todo!(), }
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SubVxVy(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::XorVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::ShrVxVy(_, _)) => todo!(), debug!("INST: XorVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SubnVxVy(_, _)) => todo!(), self.registers[vx_register as usize] = self.registers[vx_register as usize] ^ self.registers[vy_register as usize];
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::ShlVxVy(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SneVxVy(_, _)) => todo!(), }
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdIAddr(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::JpV0Addr(_)) => todo!(), debug!("INST: AddVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::RndVxByte(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::DrawVxVyNibble(_, _, _)) => todo!(), }
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SkpVx(_)) => todo!(),
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SnkpVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxDt(_)) => todo!(), debug!("INST: SubVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxK(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdDtVx(_)) => todo!(), }
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdStVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShrVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::AddIVx(_)) => todo!(), debug!("INST: ShrVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdFVu(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdBVx(_)) => todo!(), }
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdIVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubnVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxI(_)) => todo!(), debug!("INST: SubnVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::XXXXERRORINSTRUCTION) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::SysAddr(_)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::CLS) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShlVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::RET) => todo!(), debug!("INST: ShlVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::Error, Chip8CpuInstructions::JpAddr(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::CallAddr(_)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::SeVxByte(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxVy(vx_register, vy_register)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::SneVxByte(_, _)) => todo!(), debug!("INST: SneVxVy: {vx_register}/{vy_register}");
(Chip8CpuStates::Error, Chip8CpuInstructions::SeVxVy(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxByte(_, _)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::AddVxByte(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIAddr(addr)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxVy(_, _)) => todo!(), debug!("INST: LdIAddr: {addr}");
(Chip8CpuStates::Error, Chip8CpuInstructions::OrVxVy(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::AndVxVy(_, _)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::XorVxVy(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpV0Addr(addr)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::AddVxVy(_, _)) => todo!(), debug!("INST: JpV0Addr: {addr}");
(Chip8CpuStates::Error, Chip8CpuInstructions::SubVxVy(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::ShrVxVy(_, _)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::SubnVxVy(_, _)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RndVxByte(vx_register, byte)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::ShlVxVy(_, _)) => todo!(), debug!("INST: RndVxByte: {vx_register}/{byte}");
(Chip8CpuStates::Error, Chip8CpuInstructions::SneVxVy(_, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::LdIAddr(_)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::JpV0Addr(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::DrawVxVyNibble(vx_register, vy_register, nibble)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::RndVxByte(_, _)) => todo!(), debug!("INST: DrawVxVyNibble: {vx_register}/{vy_register}/{nibble}");
(Chip8CpuStates::Error, Chip8CpuInstructions::DrawVxVyNibble(_, _, _)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::SkpVx(_)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::SnkpVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SkpVx(vx_register)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxDt(_)) => todo!(), debug!("INST: SkpVx: {vx_register}");
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxK(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::LdDtVx(_)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::LdStVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SnkpVx(vx_register)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::AddIVx(_)) => todo!(), debug!("INST: SnkpVx: {vx_register}");
(Chip8CpuStates::Error, Chip8CpuInstructions::LdFVu(_)) => todo!(), self.pc += 0x2;
(Chip8CpuStates::Error, Chip8CpuInstructions::LdBVx(_)) => todo!(), }
(Chip8CpuStates::Error, Chip8CpuInstructions::LdIVx(_)) => todo!(), (Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxDt(vx_register)) => {
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxI(_)) => todo!(), debug!("INST: LdVxDt: {vx_register}");
(Chip8CpuStates::Error, Chip8CpuInstructions::XXXXERRORINSTRUCTION) => todo!(), self.pc += 0x2;
}
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxK(vx_register)) => {
debug!("INST: LdVxK: {vx_register}");
self.pc += 0x2;
}
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdDtVx(vx_register)) => {
debug!("INST: LdDtVx: {vx_register}");
self.pc += 0x2;
}
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdStVx(vx_register)) => {
debug!("INST: SkpVx: {vx_register}");
self.pc += 0x2;
}
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddIVx(vx_register)) => {
debug!("INST: AddIVx: {vx_register}");
self.pc += 0x2;
}
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdFVx(_)) => {
debug!("INST: LdFVu:");
self.pc += 0x2;
}
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdBVx(vx_register)) => {
debug!("INST: LdBVx: {vx_register}");
self.pc += 0x2;
}
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIVx(vx_register)) => {
debug!("INST: LdIVx: {vx_register}");
self.pc += 0x2;
}
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxI(vx_register)) => {
debug!("INST: LdVxI: {vx_register}");
self.pc += 0x2;
}
_ => {
error!("UNABLE TO PROCEED. CPU IN UNKNOWN STATE");
}
} }
self.clone() self.clone()
} }
// nnn or addr - A 12-bit value, the lowest 12 bits of the instruction // nnn or addr - A 12-bit value, the lowest 12 bits of the instruction
pub fn read_addr_from_instruction(&self, instruction_to_read_from: u16) -> u16 { pub fn read_addr_from_instruction(instruction_to_read_from: u16) -> u16 {
instruction_to_read_from & 0b0000111111111111 instruction_to_read_from & 0b0000111111111111
} }
// n or nibble - A 4-bit value, the lowest 4 bits of the instruction // n or nibble - A 4-bit value, the lowest 4 bits of the instruction
pub fn read_nibble_from_instruction(&self, instruction_to_read_from: u16) -> u16 { pub fn read_nibble_from_instruction(instruction_to_read_from: u16) -> u16 {
instruction_to_read_from & 0b0000000000001111 instruction_to_read_from & 0b0000000000001111
} }
// x - A 4-bit value, the lower 4 bits of the high byte of the instruction // x - A 4-bit value, the lower 4 bits of the high byte of the instruction
pub fn read_x_from_instruction(&self, instruction_to_read_from: u16) -> u16 { pub fn read_x_from_instruction(instruction_to_read_from: u16) -> u16 {
(instruction_to_read_from & 0b0000111100000000).rotate_right(8) (instruction_to_read_from & 0b0000111100000000).rotate_right(8)
} }
// y - A 4-bit value, the upper 4 bits of the low byte of the instruction // y - A 4-bit value, the upper 4 bits of the low byte of the instruction
pub fn read_y_from_instruction(&self, instruction_to_read_from: u16) -> u16 { pub fn read_y_from_instruction(instruction_to_read_from: u16) -> u16 {
(instruction_to_read_from & 0b0000000011110000).rotate_right(4) (instruction_to_read_from & 0b0000000011110000).rotate_right(4)
} }
// kk or byte - An 8-bit value, the lowest 8 bits of the instruction // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
pub fn read_byte_from_instruction(&self, instruction_to_read_from: u16) -> u16 { pub fn read_byte_from_instruction(instruction_to_read_from: u16) -> u16 {
(instruction_to_read_from & 0b0000000011111111) (instruction_to_read_from & 0b0000000011111111)
} }
fn decode_instruction(self, to_read: u16) -> Chip8CpuInstructions { pub fn read_upper_byte_lower_nibble(to_read_from: u16) -> u16 {
to_read_from & 0x0f00
}
fn decode_instruction(to_decode: u16) -> Chip8CpuInstructions {
let mut decoded_instruction = Chip8CpuInstructions::XXXXERRORINSTRUCTION; let mut decoded_instruction = Chip8CpuInstructions::XXXXERRORINSTRUCTION;
let x_param = self.read_x_from_instruction(to_read); // pull out the various possible parameters for use further along when we
let y_param = self.read_y_from_instruction(to_read); // acutally sort out what kind of instruction we have.
let addr_param = self.read_addr_from_instruction(to_read); let x_param = Chip8Computer::read_x_from_instruction(to_decode);
let byte_param = self.read_byte_from_instruction(to_read); let y_param = Chip8Computer::read_y_from_instruction(to_decode);
let nibble_param = self.read_nibble_from_instruction(to_read); let addr_param = Chip8Computer::read_addr_from_instruction(to_decode);
let byte_param = Chip8Computer::read_byte_from_instruction(to_decode);
let nibble_param = Chip8Computer::read_nibble_from_instruction(to_decode);
let ubln = u16::rotate_right(Chip8Computer::read_upper_byte_lower_nibble(to_decode), 8);
let last_byte = to_decode & 0xFF;
match to_read { match to_decode {
0x00E0 => { 0x00E0 => {
// 00E0 - CLS // 00E0 - CLS
// Clear the display. // Clear the display.
decoded_instruction = Chip8CpuInstructions::CLS; Chip8CpuInstructions::CLS
} }
0x00EE => { 0x00EE => {
// 00EE - RET // 00EE - RET
// Return from a subroutine. // Return from a subroutine.
Chip8CpuInstructions::RET
decoded_instruction = Chip8CpuInstructions::RET;
} }
0x0000..=0x0FFF => { 0x0000..=0x0FFF => {
// 0nnn - SYS addr // 0nnn - SYS addr
// Jump to a machine code routine at nnn. // Jump to a machine code routine at nnn.
decoded_instruction = Chip8CpuInstructions::SysAddr(addr_param as i16); Chip8CpuInstructions::SysAddr(addr_param as i16)
} }
0x1000..=0x1FFF => { 0x1000..=0x1FFF => {
// 1nnn - JP addr // 1nnn - JP addr
// Jump to location nnn. // Jump to location nnn.
decoded_instruction = Chip8CpuInstructions::JpAddr(addr_param as i16); Chip8CpuInstructions::JpAddr(addr_param as i16)
} }
0x2000..=0x2FFF => { 0x2000..=0x2FFF => {
// 2nnn - CALL addr // 2nnn - CALL addr
// Call subroutine at nnn. // Call subroutine at nnn.
decoded_instruction = Chip8CpuInstructions::CallAddr(addr_param as i16); Chip8CpuInstructions::CallAddr(addr_param as i16)
} }
0x3000..=0x3FFF => { 0x3000..=0x3FFF => {
// 3xkk - SE Vx, byte // 3xkk - SE Vx, byte
// Skip next instruction if Vx = kk. // Skip next instruction if Vx = kk.
decoded_instruction = Chip8CpuInstructions::SeVxByte(x_param as i16, byte_param as i16) Chip8CpuInstructions::SeVxByte(x_param as i16, byte_param as i16)
} }
0x4000..=0x4FFF => { 0x4000..=0x4FFF => {
// 4xkk - SNE Vx, byte // 4xkk - SNE Vx, byte
// Skip next instruction if Vx != kk. // Skip next instruction if Vx != kk.
decoded_instruction = Chip8CpuInstructions::SneVxByte(x_param as i16, byte_param as i16); Chip8CpuInstructions::SneVxByte(x_param as i16, byte_param as i16)
} }
0x5000..=0x5FF0 => { 0x5000..=0x5FF0 => {
// 5xy0 - SE Vx, Vy // 5xy0 - SE Vx, Vy
// Skip next instruction if Vx = Vy. // Skip next instruction if Vx = Vy.
decoded_instruction = Chip8CpuInstructions::SeVxVy(x_param, y_param) Chip8CpuInstructions::SeVxVy(x_param, y_param)
} }
0x6000..=0x6FFF => { 0x6000..=0x6FFF => {
// 6xkk - LD Vx, byte // 6xkk - LD Vx, byte
// Set Vx = kk. // Set Vx = kk.
decoded_instruction = Chip8CpuInstructions::LdVxVy(x_param, byte_param); Chip8CpuInstructions::LdVxByte(x_param, byte_param)
} }
0x7000..=0x7FFF => { 0x7000..=0x7FFF => {
// ADD Vx, Byte // ADD Vx, Byte
decoded_instruction = Chip8CpuInstructions::AddVxByte(x_param, byte_param); Chip8CpuInstructions::AddVxByte(x_param, byte_param)
} }
0x8000..=0x8FFE => { 0x8000..=0x8FFE => {
// 0x8000 Series // 0x8000 Series
let last_nibble = to_read | 0x8000; let last_nibble = to_decode & 0xF;
match last_nibble { match last_nibble {
0x0 => { 0x0 => {
// LD Vx, Vy // LD Vx, Vy
decoded_instruction = Chip8CpuInstructions::LdVxVy(x_param, y_param); Chip8CpuInstructions::LdVxVy(x_param, y_param)
} }
0x1 => { 0x1 => {
// OR Vx, Vy // OR Vx, Vy
decoded_instruction = Chip8CpuInstructions::OrVxVy(x_param, y_param); Chip8CpuInstructions::OrVxVy(x_param, y_param)
} }
0x2 => { 0x2 => {
// AND Vx, Vy // AND Vx, Vy
decoded_instruction = Chip8CpuInstructions::AndVxVy(x_param, y_param); Chip8CpuInstructions::AndVxVy(x_param, y_param)
} }
0x3 => { 0x3 => {
// XOR Vx, Vy // XOR Vx, Vy
decoded_instruction = Chip8CpuInstructions::XorVxVy(x_param, y_param); Chip8CpuInstructions::XorVxVy(x_param, y_param)
} }
0x4 => { 0x4 => {
// AND Vx, Vy // ADD Vx, Vy
decoded_instruction = Chip8CpuInstructions::AndVxVy(x_param, y_param); Chip8CpuInstructions::AddVxVy(x_param, y_param)
} }
0x5 => { 0x5 => {
// SUB Vx, Vy // SUB Vx, Vy
decoded_instruction = Chip8CpuInstructions::SubnVxVy(x_param, y_param); Chip8CpuInstructions::SubVxVy(x_param, y_param)
} }
0x6 => { 0x6 => {
// SHR Vx, {, Vy } // SHR Vx, {, Vy }
decoded_instruction = Chip8CpuInstructions::ShrVxVy(x_param, y_param); Chip8CpuInstructions::ShrVxVy(x_param, y_param)
} }
0x7 => { 0x7 => {
// SUBN Vx, Vy // SUBN Vx, Vy
decoded_instruction = Chip8CpuInstructions::SubnVxVy(x_param, y_param); Chip8CpuInstructions::SubnVxVy(x_param, y_param)
} }
0xE => { 0xE => {
// SHL Vx, {, Vy} // SHL Vx, {, Vy}
decoded_instruction = Chip8CpuInstructions::ShlVxVy(x_param, y_param); Chip8CpuInstructions::ShlVxVy(x_param, y_param)
} }
_ => { _ => {
panic!("UNABLE TO DECODE 0x8000 SERIES INSTRUCTION"); panic!("UNABLE TO DECODE 0x8000 SERIES INSTRUCTION");
@ -300,31 +355,136 @@ impl Chip8Computer {
} }
0x9000..=0x9FF0 => { 0x9000..=0x9FF0 => {
// SNE Vx, Vy // SNE Vx, Vy
decoded_instruction = Chip8CpuInstructions::SneVxVy(x_param, y_param); Chip8CpuInstructions::SneVxVy(x_param, y_param)
} }
0xA000..=0xAFFF => { 0xA000..=0xAFFF => {
// LD I, Addr // LD I, Addr
decoded_instruction = Chip8CpuInstructions::LdIAddr(addr_param); Chip8CpuInstructions::LdIAddr(addr_param)
} }
0xB000..=0xBFFF => { 0xB000..=0xBFFF => {
decoded_instruction = Chip8CpuInstructions::JpV0Addr(addr_param); Chip8CpuInstructions::JpV0Addr(addr_param)
// JP V0, Addr // JP V0, Addr
} }
0xC000..=0xCFFF => { 0xC000..=0xCFFF => {
// RND Vx, byte // RND Vx, byte
decoded_instruction = Chip8CpuInstructions::RndVxByte(x_param, byte_param); Chip8CpuInstructions::RndVxByte(x_param, byte_param)
} }
0xD000..0xDFFF => { 0xD000..0xDFFF => {
// DRAW Vx, Vy, nibble // DRAW Vx, Vy, nibble
decoded_instruction =
Chip8CpuInstructions::DrawVxVyNibble(x_param, y_param, nibble_param); Chip8CpuInstructions::DrawVxVyNibble(x_param, y_param, nibble_param)
}
0xE09E..=0xEFA1 => {
match last_byte {
0x9E => {
Chip8CpuInstructions::SkpVx(ubln)
}
0xA1 => {
Chip8CpuInstructions::SnkpVx(ubln)
}
_ => {
XXXXERRORINSTRUCTION
}
}
}
0xF007..0xFF65 => {
println!("COMPARING LAST BYTE FROM TODECODE: {:2x} to {:4x} with {:2x}", last_byte, to_decode, ubln);
match last_byte {
0x07 => {
Chip8CpuInstructions::LdVxDt(ubln)
}
0x0A => {
Chip8CpuInstructions::LdVxK(ubln)
}
0x15 => {
Chip8CpuInstructions::LdDtVx(ubln)
}
0x18 => {
Chip8CpuInstructions::LdStVx(ubln)
}
0x1E => {
Chip8CpuInstructions::AddIVx(ubln)
}
0x29 => {
Chip8CpuInstructions::LdFVx(ubln)
}
0x33 => {
Chip8CpuInstructions::LdBVx(ubln)
}
0x55 => {
Chip8CpuInstructions::LdIVx(ubln)
}
0x65 => {
Chip8CpuInstructions::LdVxI(ubln)
}
_ => { XXXXERRORINSTRUCTION }
}
} }
0xE09E..=0xEFA1 => {}
_ => { _ => {
panic!("UNABLE TO DECODE INSTRUCTION") XXXXERRORINSTRUCTION
} }
} }
return decoded_instruction;
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true)
}
#[test]
fn decoder_test_valid_instructions() {
// valid instructions
assert!(matches!(Chip8Computer::decode_instruction(0x00E0u16), Chip8CpuInstructions::CLS ));
assert!(matches!(Chip8Computer::decode_instruction(0x00EE), Chip8CpuInstructions::RET));
assert!(matches!(Chip8Computer::decode_instruction(0x0123), Chip8CpuInstructions::SysAddr(0x123)));
assert!(matches!(Chip8Computer::decode_instruction(0x0FFF), Chip8CpuInstructions::SysAddr(0xfff)));
assert!(matches!(Chip8Computer::decode_instruction(0x1002), Chip8CpuInstructions::JpAddr(0x2)));
assert!(matches!(Chip8Computer::decode_instruction(0x1FF0), Chip8CpuInstructions::JpAddr(0xFF0)));
assert!(matches!(Chip8Computer::decode_instruction(0x2002), Chip8CpuInstructions::CallAddr(0x2)));
assert!(matches!(Chip8Computer::decode_instruction(0x3123), Chip8CpuInstructions::SeVxByte(0x1, 0x23)));
assert!(matches!(Chip8Computer::decode_instruction(0x4abc), Chip8CpuInstructions::SneVxByte(0xa, 0xbc)));
assert!(matches!(Chip8Computer::decode_instruction(0x5ab0), Chip8CpuInstructions::SeVxVy(0xa, 0xb)));
assert!(matches!(Chip8Computer::decode_instruction(0x6aff), Chip8CpuInstructions::LdVxByte(0xa, 0xff)));
assert!(matches!(Chip8Computer::decode_instruction(0x7abc), Chip8CpuInstructions::AddVxByte(0xa, 0xbc)));
assert!(matches!(Chip8Computer::decode_instruction(0x8ab0), Chip8CpuInstructions::LdVxVy(0xa, 0xb)));
assert!(matches!(Chip8Computer::decode_instruction(0x8ba1), Chip8CpuInstructions::OrVxVy(0xb, 0xa)));
assert!(matches!(Chip8Computer::decode_instruction(0x8cd2), Chip8CpuInstructions::AndVxVy(0xc, 0xd)));
assert!(matches!(Chip8Computer::decode_instruction(0x8de3), Chip8CpuInstructions::XorVxVy(0xd, 0xe)));
assert!(matches!(Chip8Computer::decode_instruction(0x8ef4), Chip8CpuInstructions::AddVxVy(0xe, 0xf)));
assert!(matches!(Chip8Computer::decode_instruction(0x8f05), Chip8CpuInstructions::SubVxVy(0xf, 0x0)));
assert!(matches!(Chip8Computer::decode_instruction(0x8016), Chip8CpuInstructions::ShrVxVy(0x0, 0x1)));
assert!(matches!(Chip8Computer::decode_instruction(0x8127), Chip8CpuInstructions::SubnVxVy(0x1, 0x2)));
assert!(matches!(Chip8Computer::decode_instruction(0x834e), Chip8CpuInstructions::ShlVxVy(0x3, 0x4)));
assert!(matches!(Chip8Computer::decode_instruction(0x9ab0), Chip8CpuInstructions::SneVxVy(0xa, 0xb)));
assert!(matches!(Chip8Computer::decode_instruction(0xa123), Chip8CpuInstructions::LdIAddr(0x123)));
assert!(matches!(Chip8Computer::decode_instruction(0xb234), Chip8CpuInstructions::JpV0Addr(0x234)));
assert!(matches!(Chip8Computer::decode_instruction(0xcaca), Chip8CpuInstructions::RndVxByte(0xa, 0xca)));
assert!(matches!(Chip8Computer::decode_instruction(0xdab4), Chip8CpuInstructions::DrawVxVyNibble(0xa, 0xb, 0x4)));
assert!(matches!(Chip8Computer::decode_instruction(0xe19e), Chip8CpuInstructions::SkpVx(0x1)));
assert!(matches!(Chip8Computer::decode_instruction(0xe2a1), Chip8CpuInstructions::SnkpVx(0x2)));
assert!(matches!(Chip8Computer::decode_instruction(0xf107), Chip8CpuInstructions::LdVxDt(0x1)));
assert!(matches!(Chip8Computer::decode_instruction(0xf40a), Chip8CpuInstructions::LdVxK(0x4)));
assert!(matches!(Chip8Computer::decode_instruction(0xf615), Chip8CpuInstructions::LdDtVx(0x6)));
assert!(matches!(Chip8Computer::decode_instruction(0xfb18), Chip8CpuInstructions::LdStVx(0xb)));
assert!(matches!(Chip8Computer::decode_instruction(0xfd1e), Chip8CpuInstructions::AddIVx(0xd)));
assert!(matches!(Chip8Computer::decode_instruction(0xfc29), Chip8CpuInstructions::LdFVx(0xc)));
assert!(matches!(Chip8Computer::decode_instruction(0xfd33), Chip8CpuInstructions::LdBVx(0xd)));
assert!(matches!(Chip8Computer::decode_instruction(0xfe55), Chip8CpuInstructions::LdIVx(0xe)));
assert!(matches!(Chip8Computer::decode_instruction(0xf365), Chip8CpuInstructions::LdVxI(0x3)));
}
#[test]
fn decoder_test_invalid_instructions() {
// 'bad' instructions that should be dropped...
// assert!(matches!(Chip8Computer::decode_instruction(0x5ab1), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
// assert!(matches!(Chip8Computer::decode_instruction(0x8ab8), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
// assert!(matches!(Chip8Computer::decode_instruction(0xeaba), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
}
}

View File

@ -31,7 +31,7 @@ pub enum Chip8CpuInstructions {
LdDtVx(u16), // 0xFx15 Set Delay Timer LdDtVx(u16), // 0xFx15 Set Delay Timer
LdStVx(u16), // 0xFx18 Set Sount Timer LdStVx(u16), // 0xFx18 Set Sount Timer
AddIVx(u16), // 0xFx1E I = I + Vx AddIVx(u16), // 0xFx1E I = I + Vx
LdFVu(u16), // 0xFx29 Set I = Location of sprite for Digit Vx LdFVx(u16), // 0xFx29 Set I = Location of sprite for Digit Vx
LdBVx(u16), // 0xFx33 Store BCD of Vx in I, I+1, I+2 LdBVx(u16), // 0xFx33 Store BCD of Vx in I, I+1, I+2
LdIVx(u16), // 0xFx55 Store V0 to Vx in memory starting at I LdIVx(u16), // 0xFx55 Store V0 to Vx in memory starting at I
LdVxI(u16), // 0xFx65 Load V0 to Vx in memory starting at I LdVxI(u16), // 0xFx65 Load V0 to Vx in memory starting at I
@ -170,7 +170,7 @@ impl Chip8Instruction for Chip8CpuInstructions {
Chip8CpuInstructions::AddIVx(_) => { Chip8CpuInstructions::AddIVx(_) => {
input input
} }
Chip8CpuInstructions::LdFVu(_) => { Chip8CpuInstructions::LdFVx(_) => {
input input
} }
Chip8CpuInstructions::LdBVx(_) => { Chip8CpuInstructions::LdBVx(_) => {

View File

@ -1,6 +1,8 @@
use glium::RawUniformValue::Vec2; use glium::RawUniformValue::Vec2;
use image::load;
use imgui::sys::ImColor; use imgui::sys::ImColor;
use imgui::{ImColor32, Ui}; use imgui::{ImColor32, Ui};
use log::{debug, trace};
use ratatui::{style::Style, widgets::Widget}; use ratatui::{style::Style, widgets::Widget};
use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH}; use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
@ -30,9 +32,13 @@ pub struct Chip8SystemMemory {
impl Default for Chip8SystemMemory { impl Default for Chip8SystemMemory {
fn default() -> Self { fn default() -> Self {
Self {
memory: Chip8SystemMemory::load_to_memory([0x00; CHIP8_MEMORY_SIZE as usize]), let mut x = Chip8SystemMemory {
} memory: [0x00; CHIP8_MEMORY_SIZE as usize],
};
x.load_fonts_to_memory();
x
} }
} }
@ -54,30 +60,32 @@ const cell_width: i32 = 5i32;
const cell_height: i32 = 5i32; const cell_height: i32 = 5i32;
impl Chip8SystemMemory { impl Chip8SystemMemory {
pub fn peek(self, address: u16) -> u8 {
pub fn poke_multi(&mut self, start_offset: u16, data: Vec<u8>) {
// loop through the data...
// poke all the data into memory offset by the start
let data_len = data.len();
for i in 0..data_len {
self.poke(start_offset + i as u16, data[i]);
}
}
pub fn peek(self, address: u16) -> u8 {
trace!("PEEK: {} / {}", address, self.memory[address as usize].clone());
self.memory[address as usize] self.memory[address as usize]
} }
pub fn poke(mut self, address: u16, value: u8) -> Chip8SystemMemory { pub fn poke(&mut self, address: u16, value: u8) {
trace!("POKE: {} / {} to {}", address, self.memory[address as usize], value);
self.memory[address as usize] = value; self.memory[address as usize] = value;
self
} }
pub fn load_program(to_load_into: [u8; CHIP8_MEMORY_SIZE as usize], program_data: Box<Vec<u8>>) -> [u8; CHIP8_MEMORY_SIZE as usize] { pub fn load_program(&mut self, program_to_load: Box<Vec<u8>>) {
let mut load_target = to_load_into.clone(); for load_index in 0..program_to_load.len() {
self.poke((load_index + 0x200) as u16, program_to_load[load_index]);
// loop through the program data starting at 0x200
for load_index in 0..program_data.len() {
load_target[load_index + CHIP8_PROGRAM_LOAD_OFFSET as usize] = program_data[load_index];
} }
load_target
} }
pub fn load_to_memory( pub fn load_fonts_to_memory(&mut self) {
to_load_into: [u8; CHIP8_MEMORY_SIZE as usize],
) -> [u8; CHIP8_MEMORY_SIZE as usize] {
let mut working = to_load_into.clone();
let all_font_characters = [ let all_font_characters = [
CHIP8FONT_0, CHIP8FONT_0,
CHIP8FONT_1, CHIP8FONT_1,
@ -100,10 +108,42 @@ impl Chip8SystemMemory {
for (font_index, current_font) in all_font_characters.iter().enumerate() { for (font_index, current_font) in all_font_characters.iter().enumerate() {
for font_mem_offset in 0..=4 { for font_mem_offset in 0..=4 {
let real_offset = font_index * 5 + font_mem_offset; let real_offset = font_index * 5 + font_mem_offset;
working[real_offset] = current_font[font_mem_offset]; self.poke(real_offset as u16, current_font[font_mem_offset]);
} }
} }
println!("__FINISHED LOADING FONTS__");
working
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true)
}
#[test]
fn model_smoke() {
let m = Chip8SystemMemory::default();
for i in 0..5 {
assert_eq!(m.peek(i), CHIP8FONT_0[i as usize]);
}
assert_eq!(m.peek((CHIP8_MEMORY_SIZE - 1) as u16), 0);
}
#[test]
fn known_data_loaded_correctly() {
let to_load = [ 0x01, 0x02, 0x03, 0x04, 0x05 , 0x06 ];
let mut x = Chip8SystemMemory::default();
for (index, value) in [1..10].iter().enumerate() {
assert_ne!(x.peek(0), 0x01);
x.poke(0, 0x01);
assert_eq!(x.peek(0), 0x01);
}
}
}