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