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:
parent
c8259157c5
commit
d6f7c73de3
BIN
1-chip8-logo.ch8
Normal file
BIN
1-chip8-logo.ch8
Normal file
Binary file not shown.
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -884,6 +884,7 @@ dependencies = [
|
||||
"imgui",
|
||||
"imgui-glium-renderer",
|
||||
"imgui-winit-support",
|
||||
"log",
|
||||
"pretty_env_logger",
|
||||
"rand 0.9.0-alpha.2",
|
||||
"ratatui",
|
||||
|
||||
@ -15,3 +15,4 @@ winit = { version = "0.27", features = ["x11", "mint"] }
|
||||
pretty_env_logger = "0.5.0"
|
||||
copypasta = "0.8"
|
||||
rand = "0.9.0-alpha.2"
|
||||
log = "0.4.22"
|
||||
|
||||
@ -37,13 +37,13 @@ fn hello_world_window(ui: &Ui) {
|
||||
|
||||
|
||||
fn main() {
|
||||
pretty_env_logger::init();
|
||||
let mut system = Chip8Computer::default();
|
||||
|
||||
support::simple_init(file!(), move |_, ui| {
|
||||
|
||||
// hello_world_window(ui);
|
||||
|
||||
|
||||
EmmaGui::system_controls(&mut system, ui);
|
||||
EmmaGui::registers_view(&system, ui);
|
||||
EmmaGui::hex_memory_display(system.memory.clone(), 0x100, 0x10,ui);
|
||||
|
||||
@ -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 emmaemu::chip8::computer::Chip8Computer;
|
||||
use emmaemu::chip8::system_memory::Chip8SystemMemory;
|
||||
@ -19,10 +24,12 @@ impl EmmaGui {
|
||||
system_to_control.step_system();
|
||||
};
|
||||
if ui.button("Load Program") {
|
||||
println!("Load a program to start at 0x200");
|
||||
}
|
||||
if ui.button("Clear System Memory") {
|
||||
println!("Clear Memory");
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
println!("PREPARING TO LOAD 1-chip8-logo.ch8");
|
||||
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]) {
|
||||
// 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_y_hover = current_row;
|
||||
|
||||
// Check if the left mouse button is clicked while hovering over the text
|
||||
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.
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use log::{debug, error};
|
||||
use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;
|
||||
use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT};
|
||||
|
||||
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 i_register: u16,
|
||||
pub video_memory: Chip8Video,
|
||||
pub state: Chip8CpuStates
|
||||
pub state: Chip8CpuStates,
|
||||
}
|
||||
|
||||
impl Default for Chip8Computer {
|
||||
@ -29,7 +31,7 @@ impl Default for Chip8Computer {
|
||||
sound_timer: 0xFF,
|
||||
delay_timer: 0xFF,
|
||||
i_register: 0x0000,
|
||||
state: Chip8CpuStates::WaitingForInstruction
|
||||
state: Chip8CpuStates::WaitingForInstruction,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -39,7 +41,16 @@ impl Chip8Computer {
|
||||
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
|
||||
|
||||
let mut working_instruction: u16 = 0b0000000000000000;
|
||||
@ -48,250 +59,294 @@ impl Chip8Computer {
|
||||
working_instruction = high_byte | low_byte;
|
||||
|
||||
let decoded_instruction =
|
||||
Chip8Computer::decode_instruction(self.clone(), working_instruction);
|
||||
Chip8Computer::decode_instruction(working_instruction);
|
||||
|
||||
println!("DECODED INSTRUCTION = {:?}", decoded_instruction);
|
||||
|
||||
match (self.state, decoded_instruction) {
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SysAddr(target_address)) => {
|
||||
debug!("INST: SYS: {target_address}");
|
||||
self.pc = target_address as u16;
|
||||
},
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CLS) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RET) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CallAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::OrVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AndVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::XorVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShrVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubnVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShlVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpV0Addr(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RndVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::DrawVxVyNibble(_, _, _)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SkpVx(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SnkpVx(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxDt(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxK(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdDtVx(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdStVx(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddIVx(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdFVu(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdBVx(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIVx(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxI(_)) => todo!(),
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::XXXXERRORINSTRUCTION) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SysAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::CLS) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::RET) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::JpAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::CallAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SeVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SneVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SeVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::AddVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::OrVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::AndVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::XorVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::AddVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SubVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::ShrVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SubnVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::ShlVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SneVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdIAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::JpV0Addr(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::RndVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::DrawVxVyNibble(_, _, _)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SkpVx(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::SnkpVx(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxDt(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxK(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdDtVx(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdStVx(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::AddIVx(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdFVu(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdBVx(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdIVx(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::LdVxI(_)) => todo!(),
|
||||
(Chip8CpuStates::ExecutingInstruction, Chip8CpuInstructions::XXXXERRORINSTRUCTION) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SysAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::CLS) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::RET) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::JpAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::CallAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SeVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SneVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SeVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::AddVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::OrVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::AndVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::XorVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::AddVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SubVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::ShrVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SubnVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::ShlVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SneVxVy(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdIAddr(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::JpV0Addr(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::RndVxByte(_, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::DrawVxVyNibble(_, _, _)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SkpVx(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::SnkpVx(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxDt(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxK(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdDtVx(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdStVx(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::AddIVx(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdFVu(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdBVx(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdIVx(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::LdVxI(_)) => todo!(),
|
||||
(Chip8CpuStates::Error, Chip8CpuInstructions::XXXXERRORINSTRUCTION) => todo!(),
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CLS) => {
|
||||
debug!("INST: CLS");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RET) => {
|
||||
debug!("INST: RET");
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpAddr(new_address)) => {
|
||||
debug!("INST: JP_ADDR: {new_address}");
|
||||
self.pc = new_address as u16;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::CallAddr(sub_address)) => {
|
||||
debug!("INST: CALL_ADDR: {sub_address}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxByte(vx_register, byte)) => {
|
||||
debug!("INST: SeVxByte: {vx_register}/{byte}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxByte(vx_register, byte)) => {
|
||||
debug!("INST: SneVxByte: {vx_register}/{byte}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SeVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: SeVxVy: {vx_register}/{vy_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxByte(vx_register, byte)) => {
|
||||
debug!("INST: LdVxByte: {vx_register}/{byte}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxByte(vx_register, byte)) => {
|
||||
debug!("INST: AddVxByte: {vx_register}/{byte}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: LdVxVy: {vx_register}/{vy_register}");
|
||||
self.registers[vx_register as usize] = self.registers[vy_register as usize];
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::OrVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: OrVxVy: {vx_register}/{vy_register}");
|
||||
self.registers[vx_register as usize] = self.registers[vx_register as usize] | self.registers[vy_register as usize];
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AndVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: AndVxVy: {vx_register}/{vy_register}");
|
||||
self.registers[vx_register as usize] = self.registers[vx_register as usize] & self.registers[vy_register as usize];
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::XorVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: XorVxVy: {vx_register}/{vy_register}");
|
||||
self.registers[vx_register as usize] = self.registers[vx_register as usize] ^ self.registers[vy_register as usize];
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::AddVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: AddVxVy: {vx_register}/{vy_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: SubVxVy: {vx_register}/{vy_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShrVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: ShrVxVy: {vx_register}/{vy_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SubnVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: SubnVxVy: {vx_register}/{vy_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::ShlVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: ShlVxVy: {vx_register}/{vy_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SneVxVy(vx_register, vy_register)) => {
|
||||
debug!("INST: SneVxVy: {vx_register}/{vy_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdIAddr(addr)) => {
|
||||
debug!("INST: LdIAddr: {addr}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::JpV0Addr(addr)) => {
|
||||
debug!("INST: JpV0Addr: {addr}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::RndVxByte(vx_register, byte)) => {
|
||||
debug!("INST: RndVxByte: {vx_register}/{byte}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::DrawVxVyNibble(vx_register, vy_register, nibble)) => {
|
||||
debug!("INST: DrawVxVyNibble: {vx_register}/{vy_register}/{nibble}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SkpVx(vx_register)) => {
|
||||
debug!("INST: SkpVx: {vx_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::SnkpVx(vx_register)) => {
|
||||
debug!("INST: SnkpVx: {vx_register}");
|
||||
self.pc += 0x2;
|
||||
}
|
||||
(Chip8CpuStates::WaitingForInstruction, Chip8CpuInstructions::LdVxDt(vx_register)) => {
|
||||
debug!("INST: LdVxDt: {vx_register}");
|
||||
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()
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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 x_param = self.read_x_from_instruction(to_read);
|
||||
let y_param = self.read_y_from_instruction(to_read);
|
||||
let addr_param = self.read_addr_from_instruction(to_read);
|
||||
let byte_param = self.read_byte_from_instruction(to_read);
|
||||
let nibble_param = self.read_nibble_from_instruction(to_read);
|
||||
// pull out the various possible parameters for use further along when we
|
||||
// acutally sort out what kind of instruction we have.
|
||||
let x_param = Chip8Computer::read_x_from_instruction(to_decode);
|
||||
let y_param = Chip8Computer::read_y_from_instruction(to_decode);
|
||||
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 => {
|
||||
// 00E0 - CLS
|
||||
// Clear the display.
|
||||
decoded_instruction = Chip8CpuInstructions::CLS;
|
||||
Chip8CpuInstructions::CLS
|
||||
}
|
||||
0x00EE => {
|
||||
// 00EE - RET
|
||||
// Return from a subroutine.
|
||||
|
||||
decoded_instruction = Chip8CpuInstructions::RET;
|
||||
Chip8CpuInstructions::RET
|
||||
}
|
||||
0x0000..=0x0FFF => {
|
||||
// 0nnn - SYS addr
|
||||
// Jump to a machine code routine at nnn.
|
||||
decoded_instruction = Chip8CpuInstructions::SysAddr(addr_param as i16);
|
||||
Chip8CpuInstructions::SysAddr(addr_param as i16)
|
||||
}
|
||||
0x1000..=0x1FFF => {
|
||||
// 1nnn - JP addr
|
||||
// Jump to location nnn.
|
||||
decoded_instruction = Chip8CpuInstructions::JpAddr(addr_param as i16);
|
||||
Chip8CpuInstructions::JpAddr(addr_param as i16)
|
||||
}
|
||||
0x2000..=0x2FFF => {
|
||||
// 2nnn - CALL addr
|
||||
// Call subroutine at nnn.
|
||||
decoded_instruction = Chip8CpuInstructions::CallAddr(addr_param as i16);
|
||||
Chip8CpuInstructions::CallAddr(addr_param as i16)
|
||||
}
|
||||
0x3000..=0x3FFF => {
|
||||
// 3xkk - SE Vx, byte
|
||||
// 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 => {
|
||||
// 4xkk - SNE Vx, byte
|
||||
// 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 => {
|
||||
// 5xy0 - SE Vx, Vy
|
||||
// Skip next instruction if Vx = Vy.
|
||||
decoded_instruction = Chip8CpuInstructions::SeVxVy(x_param, y_param)
|
||||
Chip8CpuInstructions::SeVxVy(x_param, y_param)
|
||||
}
|
||||
0x6000..=0x6FFF => {
|
||||
// 6xkk - LD Vx, byte
|
||||
// Set Vx = kk.
|
||||
decoded_instruction = Chip8CpuInstructions::LdVxVy(x_param, byte_param);
|
||||
Chip8CpuInstructions::LdVxByte(x_param, byte_param)
|
||||
}
|
||||
0x7000..=0x7FFF => {
|
||||
// ADD Vx, Byte
|
||||
decoded_instruction = Chip8CpuInstructions::AddVxByte(x_param, byte_param);
|
||||
Chip8CpuInstructions::AddVxByte(x_param, byte_param)
|
||||
}
|
||||
0x8000..=0x8FFE => {
|
||||
// 0x8000 Series
|
||||
let last_nibble = to_read | 0x8000;
|
||||
let last_nibble = to_decode & 0xF;
|
||||
match last_nibble {
|
||||
0x0 => {
|
||||
// LD Vx, Vy
|
||||
decoded_instruction = Chip8CpuInstructions::LdVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::LdVxVy(x_param, y_param)
|
||||
}
|
||||
0x1 => {
|
||||
// OR Vx, Vy
|
||||
decoded_instruction = Chip8CpuInstructions::OrVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::OrVxVy(x_param, y_param)
|
||||
}
|
||||
0x2 => {
|
||||
// AND Vx, Vy
|
||||
decoded_instruction = Chip8CpuInstructions::AndVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::AndVxVy(x_param, y_param)
|
||||
}
|
||||
0x3 => {
|
||||
// XOR Vx, Vy
|
||||
decoded_instruction = Chip8CpuInstructions::XorVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::XorVxVy(x_param, y_param)
|
||||
}
|
||||
0x4 => {
|
||||
// AND Vx, Vy
|
||||
decoded_instruction = Chip8CpuInstructions::AndVxVy(x_param, y_param);
|
||||
// ADD Vx, Vy
|
||||
Chip8CpuInstructions::AddVxVy(x_param, y_param)
|
||||
}
|
||||
0x5 => {
|
||||
// SUB Vx, Vy
|
||||
decoded_instruction = Chip8CpuInstructions::SubnVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::SubVxVy(x_param, y_param)
|
||||
}
|
||||
0x6 => {
|
||||
// SHR Vx, {, Vy }
|
||||
decoded_instruction = Chip8CpuInstructions::ShrVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::ShrVxVy(x_param, y_param)
|
||||
}
|
||||
0x7 => {
|
||||
// SUBN Vx, Vy
|
||||
decoded_instruction = Chip8CpuInstructions::SubnVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::SubnVxVy(x_param, y_param)
|
||||
}
|
||||
0xE => {
|
||||
// SHL Vx, {, Vy}
|
||||
decoded_instruction = Chip8CpuInstructions::ShlVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::ShlVxVy(x_param, y_param)
|
||||
}
|
||||
_ => {
|
||||
panic!("UNABLE TO DECODE 0x8000 SERIES INSTRUCTION");
|
||||
@ -300,31 +355,136 @@ impl Chip8Computer {
|
||||
}
|
||||
0x9000..=0x9FF0 => {
|
||||
// SNE Vx, Vy
|
||||
decoded_instruction = Chip8CpuInstructions::SneVxVy(x_param, y_param);
|
||||
Chip8CpuInstructions::SneVxVy(x_param, y_param)
|
||||
}
|
||||
0xA000..=0xAFFF => {
|
||||
// LD I, Addr
|
||||
decoded_instruction = Chip8CpuInstructions::LdIAddr(addr_param);
|
||||
Chip8CpuInstructions::LdIAddr(addr_param)
|
||||
}
|
||||
0xB000..=0xBFFF => {
|
||||
decoded_instruction = Chip8CpuInstructions::JpV0Addr(addr_param);
|
||||
Chip8CpuInstructions::JpV0Addr(addr_param)
|
||||
// JP V0, Addr
|
||||
}
|
||||
0xC000..=0xCFFF => {
|
||||
// RND Vx, byte
|
||||
decoded_instruction = Chip8CpuInstructions::RndVxByte(x_param, byte_param);
|
||||
Chip8CpuInstructions::RndVxByte(x_param, byte_param)
|
||||
}
|
||||
0xD000..0xDFFF => {
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ pub enum Chip8CpuInstructions {
|
||||
LdDtVx(u16), // 0xFx15 Set Delay Timer
|
||||
LdStVx(u16), // 0xFx18 Set Sount Timer
|
||||
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
|
||||
LdIVx(u16), // 0xFx55 Store 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(_) => {
|
||||
input
|
||||
}
|
||||
Chip8CpuInstructions::LdFVu(_) => {
|
||||
Chip8CpuInstructions::LdFVx(_) => {
|
||||
input
|
||||
}
|
||||
Chip8CpuInstructions::LdBVx(_) => {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use glium::RawUniformValue::Vec2;
|
||||
use image::load;
|
||||
use imgui::sys::ImColor;
|
||||
use imgui::{ImColor32, Ui};
|
||||
use log::{debug, trace};
|
||||
use ratatui::{style::Style, widgets::Widget};
|
||||
|
||||
use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
|
||||
@ -30,9 +32,13 @@ pub struct Chip8SystemMemory {
|
||||
|
||||
impl Default for Chip8SystemMemory {
|
||||
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;
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub fn load_program(to_load_into: [u8; CHIP8_MEMORY_SIZE as usize], program_data: Box<Vec<u8>>) -> [u8; CHIP8_MEMORY_SIZE as usize] {
|
||||
let mut load_target = to_load_into.clone();
|
||||
|
||||
// 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];
|
||||
pub fn load_program(&mut self, program_to_load: Box<Vec<u8>>) {
|
||||
for load_index in 0..program_to_load.len() {
|
||||
self.poke((load_index + 0x200) as u16, program_to_load[load_index]);
|
||||
}
|
||||
|
||||
load_target
|
||||
}
|
||||
|
||||
pub fn load_to_memory(
|
||||
to_load_into: [u8; CHIP8_MEMORY_SIZE as usize],
|
||||
) -> [u8; CHIP8_MEMORY_SIZE as usize] {
|
||||
let mut working = to_load_into.clone();
|
||||
pub fn load_fonts_to_memory(&mut self) {
|
||||
let all_font_characters = [
|
||||
CHIP8FONT_0,
|
||||
CHIP8FONT_1,
|
||||
@ -100,10 +108,42 @@ impl Chip8SystemMemory {
|
||||
for (font_index, current_font) in all_font_characters.iter().enumerate() {
|
||||
for font_mem_offset in 0..=4 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user