[feat] add arg to delete if invalid

This commit is contained in:
2024-08-10 10:26:27 +05:30
parent ca09e30a3d
commit 462a447489
4 changed files with 126 additions and 121 deletions

View File

@@ -1,12 +1,24 @@
use clap::Parser; use clap::Parser;
#[derive(Parser,Debug,Clone)] #[derive(Parser, Debug, Clone)]
#[command(version,about,author)] #[command(version, about, author)]
pub struct Porcel8ProgramArgs { pub struct Porcel8ProgramArgs {
#[arg(short,long,help = "Filename of ROM to load.")] #[arg(short, long, help = "Filename of ROM to load.")]
pub filename:Option<String>, pub filename: Option<String>,
#[arg(short,long,help = "Draw scale of window",default_value_t=8f32)] #[arg(short, long, help = "Draw scale of window", default_value_t = 8f32)]
pub draw_scale: f32, pub draw_scale: f32,
#[arg(short,long,help = "Emulate new behaviour of instructions (As seen in Chip-48 and SuperChip8)",default_value_t=true)] #[arg(
pub new_chip8_behaviour: bool short,
long,
help = "Emulate new behaviour of instructions (As seen in Chip-48 and SuperChip8)",
default_value_t = true
)]
pub new_chip8_behaviour: bool,
#[arg(
short='i',
long,
help = "Halt on invalid instruction",
default_value_t = false
)]
pub halt_on_invalid: bool,
} }

View File

@@ -1,10 +1,9 @@
use std::sync::{Arc, Mutex}; use crate::{device::instruction::Instruction, util::EmulatorError};
use rand::random;
use crate::device::instruction::Instruction;
use crate::device::keyboard::Keyboard; use crate::device::keyboard::Keyboard;
use crate::device::timer::DeviceTimerManager; use crate::device::timer::DeviceTimerManager;
use crate::util::EmulatorResult; use crate::util::EmulatorResult;
use rand::random;
use std::sync::{Arc, Mutex};
pub struct Device { pub struct Device {
pub registers: RegisterFile, pub registers: RegisterFile,
@@ -13,6 +12,7 @@ pub struct Device {
pub stack: Vec<u16>, pub stack: Vec<u16>,
pub frame_buffer: Arc<Mutex<Box<[bool; 64 * 32]>>>, pub frame_buffer: Arc<Mutex<Box<[bool; 64 * 32]>>>,
pub new_chip8_mode: bool, pub new_chip8_mode: bool,
pub halt_on_invalid: bool,
pub device_keyboard: Keyboard, pub device_keyboard: Keyboard,
} }
@@ -21,14 +21,24 @@ impl Device {
pub const FRAME_BUFFER_WIDTH: usize = 64; pub const FRAME_BUFFER_WIDTH: usize = 64;
pub const FRAME_BUFFER_HEIGHT: usize = 32; pub const FRAME_BUFFER_HEIGHT: usize = 32;
pub const FRAME_BUFFER_SIZE: usize = Self::FRAME_BUFFER_WIDTH * Self::FRAME_BUFFER_HEIGHT; pub const FRAME_BUFFER_SIZE: usize = Self::FRAME_BUFFER_WIDTH * Self::FRAME_BUFFER_HEIGHT;
pub fn new(timer: DeviceTimerManager, fb: Arc<Mutex<Box<[bool; Device::FRAME_BUFFER_SIZE]>>>, device_keyboard: Keyboard, new_chip8_mode: bool) -> Device { pub fn new(
let memory = vec![0u8; Self::DEVICE_MEMORY_SIZE].into_boxed_slice().try_into().unwrap(); timer: DeviceTimerManager,
fb: Arc<Mutex<Box<[bool; Device::FRAME_BUFFER_SIZE]>>>,
device_keyboard: Keyboard,
new_chip8_mode: bool,
halt_on_invalid: bool
) -> Device {
let memory = vec![0u8; Self::DEVICE_MEMORY_SIZE]
.into_boxed_slice()
.try_into()
.unwrap();
log::trace!("Successfully initiated device memory"); log::trace!("Successfully initiated device memory");
Device { Device {
registers: RegisterFile::new(), registers: RegisterFile::new(),
memory, memory,
frame_buffer: fb, frame_buffer: fb,
stack: Vec::with_capacity(16), stack: Vec::with_capacity(16),
halt_on_invalid,
timer, timer,
new_chip8_mode, new_chip8_mode,
device_keyboard, device_keyboard,
@@ -42,8 +52,6 @@ impl Device {
const FONT_DEFAULT_MEM_LOCATION_END: usize = 0x9F; const FONT_DEFAULT_MEM_LOCATION_END: usize = 0x9F;
const ROM_START: usize = 0x200; const ROM_START: usize = 0x200;
pub fn cycle(&mut self) -> EmulatorResult<()> { pub fn cycle(&mut self) -> EmulatorResult<()> {
self.device_keyboard.update_keyboard()?; self.device_keyboard.update_keyboard()?;
@@ -60,13 +68,19 @@ impl Device {
} }
pub fn execute_instruction(&mut self, instruction: Instruction) -> EmulatorResult<()> { pub fn execute_instruction(&mut self, instruction: Instruction) -> EmulatorResult<()> {
// thread::sleep(Duration::from_millis(250)); // thread::sleep(Duration::from_millis(250));
log::trace!("Executing {:?}, {:?}",&instruction,&self.registers); log::trace!("Executing {:?}, {:?}", &instruction, &self.registers);
match instruction { match instruction {
Instruction::PassThrough => { Instruction::InvalidInstruction => {
log::info!("Executing passthrough"); log::info!("Executing passthrough");
} if self.halt_on_invalid {
return Err(EmulatorError::IOError("Caught Invalid Instruction".to_string()));
}
},
Instruction::ClearScreen => { Instruction::ClearScreen => {
let mut frame_buffer = self.frame_buffer.lock().expect("Failed to grab framebuffer for drawing"); let mut frame_buffer = self
.frame_buffer
.lock()
.expect("Failed to grab framebuffer for drawing");
for pixel in frame_buffer.iter_mut() { for pixel in frame_buffer.iter_mut() {
*pixel = false; *pixel = false;
} }
@@ -154,7 +168,8 @@ impl Device {
} }
Instruction::Add(x, y) => { Instruction::Add(x, y) => {
let left = self.registers.v[x]; let left = self.registers.v[x];
let (wrapped_addition_result, is_overflow) = left.overflowing_add(self.registers.v[y]); let (wrapped_addition_result, is_overflow) =
left.overflowing_add(self.registers.v[y]);
self.registers.v[x] = wrapped_addition_result; self.registers.v[x] = wrapped_addition_result;
self.set_flag_register(is_overflow); self.set_flag_register(is_overflow);
} }
@@ -167,7 +182,8 @@ impl Device {
} }
Instruction::RSub(x, y) => { Instruction::RSub(x, y) => {
let left = self.registers.v[y]; let left = self.registers.v[y];
let (wrapped_subtraction_result, is_overflow) = left.overflowing_sub(self.registers.v[x]); let (wrapped_subtraction_result, is_overflow) =
left.overflowing_sub(self.registers.v[x]);
self.registers.v[x] = wrapped_subtraction_result; self.registers.v[x] = wrapped_subtraction_result;
self.set_flag_register(!is_overflow); self.set_flag_register(!is_overflow);
} }
@@ -223,7 +239,8 @@ impl Device {
} }
Instruction::SetIndexToFontCharacter(x) => { Instruction::SetIndexToFontCharacter(x) => {
let requested_char = self.registers.v[x]; let requested_char = self.registers.v[x];
let font_address = Self::FONT_DEFAULT_MEM_LOCATION_START as u16 + Self::FONT_HEIGHT * requested_char as u16; let font_address = Self::FONT_DEFAULT_MEM_LOCATION_START as u16
+ Self::FONT_HEIGHT * requested_char as u16;
self.registers.i = font_address; self.registers.i = font_address;
} }
Instruction::DoBCDConversion(x) => { Instruction::DoBCDConversion(x) => {
@@ -267,7 +284,10 @@ impl Device {
/// Draw a sprite at location at (x,y) for n pixels long and 8 pixels wide. /// Draw a sprite at location at (x,y) for n pixels long and 8 pixels wide.
/// Returns whether any pixel was toggled /// Returns whether any pixel was toggled
fn draw_sprite_at_location(&mut self, x: usize, y: usize, n: u8) -> bool { fn draw_sprite_at_location(&mut self, x: usize, y: usize, n: u8) -> bool {
let mut frame_buffer = self.frame_buffer.lock().expect("Failed to grab framebuffer for drawing"); let mut frame_buffer = self
.frame_buffer
.lock()
.expect("Failed to grab framebuffer for drawing");
let mut is_pixel_toggled_off = false; let mut is_pixel_toggled_off = false;
for i in 0..n as usize { for i in 0..n as usize {
@@ -286,8 +306,11 @@ impl Device {
let bit_is_true = (slice_from_memory & (1 << bit_index)) == (1 << bit_index); let bit_is_true = (slice_from_memory & (1 << bit_index)) == (1 << bit_index);
// if the pixel is going to be toggled false, set this flag bit to true // if the pixel is going to be toggled false, set this flag bit to true
if frame_buffer[index + (7 - bit_index)] && (bit_is_true) { is_pixel_toggled_off = true; } if frame_buffer[index + (7 - bit_index)] && (bit_is_true) {
frame_buffer[index + (7 - bit_index)] = frame_buffer[index + (7 - bit_index)] ^ (bit_is_true); is_pixel_toggled_off = true;
}
frame_buffer[index + (7 - bit_index)] =
frame_buffer[index + (7 - bit_index)] ^ (bit_is_true);
} }
} }
is_pixel_toggled_off is_pixel_toggled_off
@@ -313,10 +336,11 @@ impl Device {
0xF0, 0x80, 0x80, 0x80, 0xF0, // C 0xF0, 0x80, 0x80, 0x80, 0xF0, // C
0xE0, 0x90, 0x90, 0x90, 0xE0, // D 0xE0, 0x90, 0x90, 0x90, 0xE0, // D
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
0xF0, 0x80, 0xF0, 0x80, 0x80 // F 0xF0, 0x80, 0xF0, 0x80, 0x80, // F
]; ];
log::info!("Loaded default font from memory"); log::info!("Loaded default font from memory");
self.memory[Self::FONT_DEFAULT_MEM_LOCATION_START..=Self::FONT_DEFAULT_MEM_LOCATION_END].copy_from_slice(&DEFAULT_FONT); self.memory[Self::FONT_DEFAULT_MEM_LOCATION_START..=Self::FONT_DEFAULT_MEM_LOCATION_END]
.copy_from_slice(&DEFAULT_FONT);
} }
/// load a rom from bytes /// load a rom from bytes
pub fn load_rom(&mut self, rom: &[u8]) { pub fn load_rom(&mut self, rom: &[u8]) {

View File

@@ -2,8 +2,8 @@ use byteorder::{BigEndian, ByteOrder};
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug)]
pub enum Instruction { pub enum Instruction {
/// Blanket instruction that does nothing /// Invalid instruction that may be skipped or raise error
PassThrough, InvalidInstruction,
/// 00E0 - Clear the screen /// 00E0 - Clear the screen
ClearScreen, ClearScreen,
/// 00EE - Return from procedure /// 00EE - Return from procedure
@@ -83,22 +83,14 @@ impl Instruction {
let instruction = BigEndian::read_u16(location); let instruction = BigEndian::read_u16(location);
let outer_instruction_nibble = (instruction & 0xF000) >> 12; let outer_instruction_nibble = (instruction & 0xF000) >> 12;
match outer_instruction_nibble { match outer_instruction_nibble {
0x0 if instruction == 0xe0 => { 0x0 if instruction == 0xe0 => Instruction::ClearScreen,
Instruction::ClearScreen 0x0 if instruction == 0xee => Instruction::ReturnFromProcedure,
}
0x0 if instruction == 0xee => {
Instruction::ReturnFromProcedure
}
0x0 => { 0x0 => {
log::warn!("Ignoring unsupported instruction {}",instruction); log::warn!("Ignoring unsupported instruction {}", instruction);
Instruction::PassThrough Instruction::InvalidInstruction
}
0x1 => {
Instruction::JumpTo(instruction & 0xfff)
}
0x2 => {
Instruction::JumpAndLink(instruction & 0xfff)
} }
0x1 => Instruction::JumpTo(instruction & 0xfff),
0x2 => Instruction::JumpAndLink(instruction & 0xfff),
0x3 => { 0x3 => {
let register = (instruction & 0xf00) >> 8; let register = (instruction & 0xf00) >> 8;
let val = instruction & 0xff; let val = instruction & 0xff;
@@ -115,24 +107,25 @@ impl Instruction {
Instruction::ConditionalEqRegisterSkipNext(register_x as usize, register_y as usize) Instruction::ConditionalEqRegisterSkipNext(register_x as usize, register_y as usize)
} }
0x6 => { 0x6 => Instruction::SetRegister(
Instruction::SetRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8) ((instruction & 0x0f00) >> 8) as usize,
} (instruction & 0xff) as u8,
0x7 => { ),
Instruction::AddValueToRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8) 0x7 => Instruction::AddValueToRegister(
} ((instruction & 0x0f00) >> 8) as usize,
0x8 => { (instruction & 0xff) as u8,
Self::decode_arithmetic_instruction(instruction) ),
} 0x8 => Self::decode_arithmetic_instruction(instruction),
0x9 => { 0x9 => {
let register_x = (instruction & 0xf00) >> 8; let register_x = (instruction & 0xf00) >> 8;
let register_y = (instruction & 0xf0) >> 4; let register_y = (instruction & 0xf0) >> 4;
Instruction::ConditionalInEqRegisterSkipNext(register_x as usize, register_y as usize) Instruction::ConditionalInEqRegisterSkipNext(
} register_x as usize,
0xA => { register_y as usize,
Instruction::SetIndex(instruction & 0xfff) )
} }
0xA => Instruction::SetIndex(instruction & 0xfff),
0xB => { 0xB => {
let register_x = (instruction & 0xf00) >> 8; let register_x = (instruction & 0xf00) >> 8;
let jump_address_base = instruction & 0xfff; let jump_address_base = instruction & 0xfff;
@@ -152,45 +145,45 @@ impl Instruction {
0xE if (instruction & 0xff) == 0x9e => { 0xE if (instruction & 0xff) == 0x9e => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::SkipIfKeyPressed(x as usize) Instruction::SkipIfKeyPressed(x as usize)
}, }
0xE if (instruction & 0xff) == 0xa1 => { 0xE if (instruction & 0xff) == 0xa1 => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::SkipIfKeyNotPressed(x as usize) Instruction::SkipIfKeyNotPressed(x as usize)
} }
0xF if (instruction & 0xff) == 0x07 =>{ 0xF if (instruction & 0xff) == 0x07 => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::FetchDelayTimer(x as usize) Instruction::FetchDelayTimer(x as usize)
} }
0xF if (instruction & 0xff) == 0x15 =>{ 0xF if (instruction & 0xff) == 0x15 => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::SetDelayTimer(x as usize) Instruction::SetDelayTimer(x as usize)
} }
0xF if (instruction & 0xff) == 0x18 =>{ 0xF if (instruction & 0xff) == 0x18 => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::SetSoundTimer(x as usize) Instruction::SetSoundTimer(x as usize)
} }
0xF if (instruction & 0xff) == 0x1E =>{ 0xF if (instruction & 0xff) == 0x1E => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::AddToIndex(x as usize) Instruction::AddToIndex(x as usize)
} }
0xF if (instruction & 0xff) == 0x0A =>{ 0xF if (instruction & 0xff) == 0x0A => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::GetKey(x as usize) Instruction::GetKey(x as usize)
} }
//TODO add tests from here //TODO add tests from here
0xF if (instruction & 0xff) == 0x29 =>{ 0xF if (instruction & 0xff) == 0x29 => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::SetIndexToFontCharacter(x as usize) Instruction::SetIndexToFontCharacter(x as usize)
} }
0xF if (instruction & 0xff) == 0x33 =>{ 0xF if (instruction & 0xff) == 0x33 => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::DoBCDConversion(x as usize) Instruction::DoBCDConversion(x as usize)
} }
0xF if (instruction & 0xff) == 0x55 =>{ 0xF if (instruction & 0xff) == 0x55 => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::StoreRegistersToMemory(x as usize) Instruction::StoreRegistersToMemory(x as usize)
} }
0xF if (instruction & 0xff) == 0x65 =>{ 0xF if (instruction & 0xff) == 0x65 => {
let x = (instruction & 0xf00) >> 8; let x = (instruction & 0xf00) >> 8;
Instruction::LoadRegistersFromMemory(x as usize) Instruction::LoadRegistersFromMemory(x as usize)
} }
@@ -206,36 +199,18 @@ impl Instruction {
let reg_y = ((instruction & 0xf0) >> 4) as usize; let reg_y = ((instruction & 0xf0) >> 4) as usize;
let operation = instruction & 0xf; let operation = instruction & 0xf;
match operation { match operation {
0 => { 0 => Instruction::Set(reg_x, reg_y),
Instruction::Set(reg_x, reg_y) 1 => Instruction::Or(reg_x, reg_y),
} 2 => Instruction::And(reg_x, reg_y),
1 => { 3 => Instruction::Xor(reg_x, reg_y),
Instruction::Or(reg_x, reg_y) 4 => Instruction::Add(reg_x, reg_y),
} 5 => Instruction::Sub(reg_x, reg_y),
2 => { 6 => Instruction::RShift(reg_x, reg_y),
Instruction::And(reg_x, reg_y) 7 => Instruction::RSub(reg_x, reg_y),
} 0xe => Instruction::LShift(reg_x, reg_y),
3 => {
Instruction::Xor(reg_x, reg_y)
}
4 => {
Instruction::Add(reg_x, reg_y)
}
5 => {
Instruction::Sub(reg_x, reg_y)
}
6 => {
Instruction::RShift(reg_x, reg_y)
}
7 => {
Instruction::RSub(reg_x, reg_y)
}
0xe => {
Instruction::LShift(reg_x, reg_y)
}
_ => { _ => {
log::error!("Encountered unexpected alu instruction {}",instruction); log::error!("Encountered unexpected alu instruction {}", instruction);
Instruction::PassThrough Instruction::InvalidInstruction
} }
} }
} }
@@ -265,11 +240,10 @@ mod tests {
for instruction_hex in [0xf0u16, 0x0, 0x1, 0x10] { for instruction_hex in [0xf0u16, 0x0, 0x1, 0x10] {
let instruction_bytes = instruction_hex.to_be_bytes(); let instruction_bytes = instruction_hex.to_be_bytes();
let instruction = Instruction::decode_instruction(&instruction_bytes); let instruction = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(instruction, PassThrough) assert_eq!(instruction, InvalidInstruction)
} }
} }
#[test] #[test]
fn test_jump_to_instruction_1() { fn test_jump_to_instruction_1() {
let instruction_bytes = 0x1123_u16.to_be_bytes(); let instruction_bytes = 0x1123_u16.to_be_bytes();
@@ -361,7 +335,6 @@ mod tests {
assert_eq!(ins, RandomAnd(0xa, 0xbd)); assert_eq!(ins, RandomAnd(0xa, 0xbd));
} }
#[test] #[test]
fn test_draw() { fn test_draw() {
let instruction_bytes = 0xdfab_u16.to_be_bytes(); let instruction_bytes = 0xdfab_u16.to_be_bytes();
@@ -432,71 +405,70 @@ mod tests {
assert_eq!(ins, LShift(0x1, 0x2)) assert_eq!(ins, LShift(0x1, 0x2))
} }
#[test] #[test]
fn test_skip_if_keypress(){ fn test_skip_if_keypress() {
let instruction_bytes = 0xef9e_u16.to_be_bytes(); let instruction_bytes = 0xef9e_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, SkipIfKeyPressed(0xf)) assert_eq!(ins, SkipIfKeyPressed(0xf))
} }
#[test] #[test]
fn test_skip_if_not_keypress(){ fn test_skip_if_not_keypress() {
let instruction_bytes = 0xeba1_u16.to_be_bytes(); let instruction_bytes = 0xeba1_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, SkipIfKeyNotPressed(0xb)) assert_eq!(ins, SkipIfKeyNotPressed(0xb))
} }
#[test] #[test]
fn test_fetch_delay_timer(){ fn test_fetch_delay_timer() {
let instruction_bytes = 0xfa07_u16.to_be_bytes(); let instruction_bytes = 0xfa07_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, FetchDelayTimer(0xa)) assert_eq!(ins, FetchDelayTimer(0xa))
} }
#[test] #[test]
fn test_set_delay_timer(){ fn test_set_delay_timer() {
let instruction_bytes = 0xfb15_u16.to_be_bytes(); let instruction_bytes = 0xfb15_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, SetDelayTimer(0xb)) assert_eq!(ins, SetDelayTimer(0xb))
} }
#[test] #[test]
fn test_set_sound_timer(){ fn test_set_sound_timer() {
let instruction_bytes = 0xfc18_u16.to_be_bytes(); let instruction_bytes = 0xfc18_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, SetSoundTimer(0xc)) assert_eq!(ins, SetSoundTimer(0xc))
} }
#[test] #[test]
fn test_add_to_index(){ fn test_add_to_index() {
let instruction_bytes = 0xfb1e_u16.to_be_bytes(); let instruction_bytes = 0xfb1e_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, AddToIndex(0xb)) assert_eq!(ins, AddToIndex(0xb))
} }
#[test] #[test]
fn test_get_key(){ fn test_get_key() {
let instruction_bytes = 0xf50a_u16.to_be_bytes(); let instruction_bytes = 0xf50a_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, GetKey(0x5)) assert_eq!(ins, GetKey(0x5))
} }
#[test] #[test]
fn test_set_index_to_font_char(){ fn test_set_index_to_font_char() {
let instruction_bytes = 0xfb29_u16.to_be_bytes(); let instruction_bytes = 0xfb29_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, SetIndexToFontCharacter(0xb)) assert_eq!(ins, SetIndexToFontCharacter(0xb))
} }
#[test] #[test]
fn test_do_bcd_conversion(){ fn test_do_bcd_conversion() {
let instruction_bytes = 0xfd33_u16.to_be_bytes(); let instruction_bytes = 0xfd33_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, DoBCDConversion(0xd)) assert_eq!(ins, DoBCDConversion(0xd))
} }
#[test] #[test]
fn test_store_regs_to_mem(){ fn test_store_regs_to_mem() {
let instruction_bytes = 0xfb55_u16.to_be_bytes(); let instruction_bytes = 0xfb55_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, StoreRegistersToMemory(0xb)) assert_eq!(ins, StoreRegistersToMemory(0xb))
} }
#[test] #[test]
fn test_load_regs_to_mem(){ fn test_load_regs_to_mem() {
let instruction_bytes = 0xf965_u16.to_be_bytes(); let instruction_bytes = 0xf965_u16.to_be_bytes();
let ins = Instruction::decode_instruction(&instruction_bytes); let ins = Instruction::decode_instruction(&instruction_bytes);
assert_eq!(ins, LoadRegistersFromMemory(0b1001)) assert_eq!(ins, LoadRegistersFromMemory(0b1001))
} }
} }

View File

@@ -33,7 +33,7 @@ mod rom;
fn main() -> EmulatorResult<()> { fn main() -> EmulatorResult<()> {
SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap(); SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap();
let Porcel8ProgramArgs { filename, new_chip8_behaviour, draw_scale } = Porcel8ProgramArgs::parse(); let Porcel8ProgramArgs { filename, new_chip8_behaviour, draw_scale, halt_on_invalid } = Porcel8ProgramArgs::parse();
log::info!("Started emulator"); log::info!("Started emulator");
@@ -46,7 +46,7 @@ fn main() -> EmulatorResult<()> {
timer.start(); timer.start();
let device = Device::new(timer, frame_buffer_for_device, device_keyboard, new_chip8_behaviour); let device = Device::new(timer, frame_buffer_for_device, device_keyboard, new_chip8_behaviour, halt_on_invalid);
let (device_termination_signal_sender, compute_handle) = start_compute_thread(filename, device)?; let (device_termination_signal_sender, compute_handle) = start_compute_thread(filename, device)?;
@@ -163,6 +163,3 @@ fn try_initiate_sdl(draw_scale: f32) -> EmulatorResult<(WindowCanvas, EventPump,
let event_pump = sdl_context.event_pump()?; let event_pump = sdl_context.event_pump()?;
Ok((canvas, event_pump, audio_queue)) Ok((canvas, event_pump, audio_queue))
} }