[feat] add arg to delete if invalid
This commit is contained in:
28
src/args.rs
28
src/args.rs
@@ -1,12 +1,24 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser,Debug,Clone)]
|
||||
#[command(version,about,author)]
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
#[command(version, about, author)]
|
||||
pub struct Porcel8ProgramArgs {
|
||||
#[arg(short,long,help = "Filename of ROM to load.")]
|
||||
pub filename:Option<String>,
|
||||
#[arg(short,long,help = "Draw scale of window",default_value_t=8f32)]
|
||||
#[arg(short, long, help = "Filename of ROM to load.")]
|
||||
pub filename: Option<String>,
|
||||
#[arg(short, long, help = "Draw scale of window", default_value_t = 8f32)]
|
||||
pub draw_scale: f32,
|
||||
#[arg(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,
|
||||
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,
|
||||
}
|
||||
|
@@ -1,10 +1,9 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
use rand::random;
|
||||
use crate::device::instruction::Instruction;
|
||||
use crate::{device::instruction::Instruction, util::EmulatorError};
|
||||
use crate::device::keyboard::Keyboard;
|
||||
use crate::device::timer::DeviceTimerManager;
|
||||
use crate::util::EmulatorResult;
|
||||
|
||||
use rand::random;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub struct Device {
|
||||
pub registers: RegisterFile,
|
||||
@@ -13,6 +12,7 @@ pub struct Device {
|
||||
pub stack: Vec<u16>,
|
||||
pub frame_buffer: Arc<Mutex<Box<[bool; 64 * 32]>>>,
|
||||
pub new_chip8_mode: bool,
|
||||
pub halt_on_invalid: bool,
|
||||
pub device_keyboard: Keyboard,
|
||||
}
|
||||
|
||||
@@ -21,14 +21,24 @@ impl Device {
|
||||
pub const FRAME_BUFFER_WIDTH: usize = 64;
|
||||
pub const FRAME_BUFFER_HEIGHT: usize = 32;
|
||||
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 {
|
||||
let memory = vec![0u8; Self::DEVICE_MEMORY_SIZE].into_boxed_slice().try_into().unwrap();
|
||||
pub fn new(
|
||||
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");
|
||||
Device {
|
||||
registers: RegisterFile::new(),
|
||||
memory,
|
||||
frame_buffer: fb,
|
||||
stack: Vec::with_capacity(16),
|
||||
halt_on_invalid,
|
||||
timer,
|
||||
new_chip8_mode,
|
||||
device_keyboard,
|
||||
@@ -41,9 +51,7 @@ impl Device {
|
||||
const FONT_DEFAULT_MEM_LOCATION_START: usize = 0x50;
|
||||
const FONT_DEFAULT_MEM_LOCATION_END: usize = 0x9F;
|
||||
const ROM_START: usize = 0x200;
|
||||
|
||||
|
||||
|
||||
|
||||
pub fn cycle(&mut self) -> EmulatorResult<()> {
|
||||
self.device_keyboard.update_keyboard()?;
|
||||
|
||||
@@ -60,13 +68,19 @@ impl Device {
|
||||
}
|
||||
pub fn execute_instruction(&mut self, instruction: Instruction) -> EmulatorResult<()> {
|
||||
// thread::sleep(Duration::from_millis(250));
|
||||
log::trace!("Executing {:?}, {:?}",&instruction,&self.registers);
|
||||
log::trace!("Executing {:?}, {:?}", &instruction, &self.registers);
|
||||
match instruction {
|
||||
Instruction::PassThrough => {
|
||||
Instruction::InvalidInstruction => {
|
||||
log::info!("Executing passthrough");
|
||||
}
|
||||
if self.halt_on_invalid {
|
||||
return Err(EmulatorError::IOError("Caught Invalid Instruction".to_string()));
|
||||
}
|
||||
},
|
||||
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() {
|
||||
*pixel = false;
|
||||
}
|
||||
@@ -154,7 +168,8 @@ impl Device {
|
||||
}
|
||||
Instruction::Add(x, y) => {
|
||||
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.set_flag_register(is_overflow);
|
||||
}
|
||||
@@ -167,7 +182,8 @@ impl Device {
|
||||
}
|
||||
Instruction::RSub(x, 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.set_flag_register(!is_overflow);
|
||||
}
|
||||
@@ -223,7 +239,8 @@ impl Device {
|
||||
}
|
||||
Instruction::SetIndexToFontCharacter(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;
|
||||
}
|
||||
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.
|
||||
/// Returns whether any pixel was toggled
|
||||
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;
|
||||
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);
|
||||
|
||||
// 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; }
|
||||
frame_buffer[index + (7 - bit_index)] = frame_buffer[index + (7 - bit_index)] ^ (bit_is_true);
|
||||
if 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
|
||||
@@ -313,10 +336,11 @@ impl Device {
|
||||
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
||||
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
||||
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");
|
||||
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
|
||||
pub fn load_rom(&mut self, rom: &[u8]) {
|
||||
|
@@ -2,8 +2,8 @@ use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub enum Instruction {
|
||||
/// Blanket instruction that does nothing
|
||||
PassThrough,
|
||||
/// Invalid instruction that may be skipped or raise error
|
||||
InvalidInstruction,
|
||||
/// 00E0 - Clear the screen
|
||||
ClearScreen,
|
||||
/// 00EE - Return from procedure
|
||||
@@ -26,14 +26,14 @@ pub enum Instruction {
|
||||
ConditionalInEqRegisterSkipNext(usize, usize),
|
||||
/// ANNN - Set index value
|
||||
SetIndex(u16),
|
||||
/// B(X+N)NN - Jump to address with offset. Either v0 or specified register
|
||||
/// B(X+N)NN - Jump to address with offset. Either v0 or specified register
|
||||
JumpWithOffset(usize, u16),
|
||||
/// CXNN - AND a random number with NN and place in register
|
||||
RandomAnd(usize, u8),
|
||||
/// DXYN - Draw pixels at xy pointed by register for n bytes long
|
||||
Draw(usize, usize, u8),
|
||||
|
||||
/// EX9E - Check if key is pressed
|
||||
/// EX9E - Check if key is pressed
|
||||
SkipIfKeyPressed(usize),
|
||||
/// EXA1 - Check if key is not pressed
|
||||
SkipIfKeyNotPressed(usize),
|
||||
@@ -83,22 +83,14 @@ impl Instruction {
|
||||
let instruction = BigEndian::read_u16(location);
|
||||
let outer_instruction_nibble = (instruction & 0xF000) >> 12;
|
||||
match outer_instruction_nibble {
|
||||
0x0 if instruction == 0xe0 => {
|
||||
Instruction::ClearScreen
|
||||
}
|
||||
0x0 if instruction == 0xee => {
|
||||
Instruction::ReturnFromProcedure
|
||||
}
|
||||
0x0 if instruction == 0xe0 => Instruction::ClearScreen,
|
||||
0x0 if instruction == 0xee => Instruction::ReturnFromProcedure,
|
||||
0x0 => {
|
||||
log::warn!("Ignoring unsupported instruction {}",instruction);
|
||||
Instruction::PassThrough
|
||||
}
|
||||
0x1 => {
|
||||
Instruction::JumpTo(instruction & 0xfff)
|
||||
}
|
||||
0x2 => {
|
||||
Instruction::JumpAndLink(instruction & 0xfff)
|
||||
log::warn!("Ignoring unsupported instruction {}", instruction);
|
||||
Instruction::InvalidInstruction
|
||||
}
|
||||
0x1 => Instruction::JumpTo(instruction & 0xfff),
|
||||
0x2 => Instruction::JumpAndLink(instruction & 0xfff),
|
||||
0x3 => {
|
||||
let register = (instruction & 0xf00) >> 8;
|
||||
let val = instruction & 0xff;
|
||||
@@ -115,24 +107,25 @@ impl Instruction {
|
||||
|
||||
Instruction::ConditionalEqRegisterSkipNext(register_x as usize, register_y as usize)
|
||||
}
|
||||
0x6 => {
|
||||
Instruction::SetRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
|
||||
}
|
||||
0x7 => {
|
||||
Instruction::AddValueToRegister(((instruction & 0x0f00) >> 8) as usize, (instruction & 0xff) as u8)
|
||||
}
|
||||
0x8 => {
|
||||
Self::decode_arithmetic_instruction(instruction)
|
||||
}
|
||||
0x6 => Instruction::SetRegister(
|
||||
((instruction & 0x0f00) >> 8) as usize,
|
||||
(instruction & 0xff) as u8,
|
||||
),
|
||||
0x7 => Instruction::AddValueToRegister(
|
||||
((instruction & 0x0f00) >> 8) as usize,
|
||||
(instruction & 0xff) as u8,
|
||||
),
|
||||
0x8 => Self::decode_arithmetic_instruction(instruction),
|
||||
0x9 => {
|
||||
let register_x = (instruction & 0xf00) >> 8;
|
||||
let register_y = (instruction & 0xf0) >> 4;
|
||||
|
||||
Instruction::ConditionalInEqRegisterSkipNext(register_x as usize, register_y as usize)
|
||||
}
|
||||
0xA => {
|
||||
Instruction::SetIndex(instruction & 0xfff)
|
||||
Instruction::ConditionalInEqRegisterSkipNext(
|
||||
register_x as usize,
|
||||
register_y as usize,
|
||||
)
|
||||
}
|
||||
0xA => Instruction::SetIndex(instruction & 0xfff),
|
||||
0xB => {
|
||||
let register_x = (instruction & 0xf00) >> 8;
|
||||
let jump_address_base = instruction & 0xfff;
|
||||
@@ -152,45 +145,45 @@ impl Instruction {
|
||||
0xE if (instruction & 0xff) == 0x9e => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::SkipIfKeyPressed(x as usize)
|
||||
},
|
||||
0xE if (instruction & 0xff) == 0xa1 => {
|
||||
}
|
||||
0xE if (instruction & 0xff) == 0xa1 => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::SkipIfKeyNotPressed(x as usize)
|
||||
}
|
||||
0xF if (instruction & 0xff) == 0x07 =>{
|
||||
0xF if (instruction & 0xff) == 0x07 => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::FetchDelayTimer(x as usize)
|
||||
}
|
||||
0xF if (instruction & 0xff) == 0x15 =>{
|
||||
0xF if (instruction & 0xff) == 0x15 => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::SetDelayTimer(x as usize)
|
||||
}
|
||||
0xF if (instruction & 0xff) == 0x18 =>{
|
||||
0xF if (instruction & 0xff) == 0x18 => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::SetSoundTimer(x as usize)
|
||||
}
|
||||
0xF if (instruction & 0xff) == 0x1E =>{
|
||||
0xF if (instruction & 0xff) == 0x1E => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::AddToIndex(x as usize)
|
||||
}
|
||||
0xF if (instruction & 0xff) == 0x0A =>{
|
||||
0xF if (instruction & 0xff) == 0x0A => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::GetKey(x as usize)
|
||||
}
|
||||
//TODO add tests from here
|
||||
0xF if (instruction & 0xff) == 0x29 =>{
|
||||
0xF if (instruction & 0xff) == 0x29 => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::SetIndexToFontCharacter(x as usize)
|
||||
}
|
||||
0xF if (instruction & 0xff) == 0x33 =>{
|
||||
0xF if (instruction & 0xff) == 0x33 => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::DoBCDConversion(x as usize)
|
||||
}
|
||||
0xF if (instruction & 0xff) == 0x55 =>{
|
||||
0xF if (instruction & 0xff) == 0x55 => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::StoreRegistersToMemory(x as usize)
|
||||
}
|
||||
0xF if (instruction & 0xff) == 0x65 =>{
|
||||
0xF if (instruction & 0xff) == 0x65 => {
|
||||
let x = (instruction & 0xf00) >> 8;
|
||||
Instruction::LoadRegistersFromMemory(x as usize)
|
||||
}
|
||||
@@ -206,36 +199,18 @@ impl Instruction {
|
||||
let reg_y = ((instruction & 0xf0) >> 4) as usize;
|
||||
let operation = instruction & 0xf;
|
||||
match operation {
|
||||
0 => {
|
||||
Instruction::Set(reg_x, reg_y)
|
||||
}
|
||||
1 => {
|
||||
Instruction::Or(reg_x, reg_y)
|
||||
}
|
||||
2 => {
|
||||
Instruction::And(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)
|
||||
}
|
||||
0 => Instruction::Set(reg_x, reg_y),
|
||||
1 => Instruction::Or(reg_x, reg_y),
|
||||
2 => Instruction::And(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);
|
||||
Instruction::PassThrough
|
||||
log::error!("Encountered unexpected alu instruction {}", instruction);
|
||||
Instruction::InvalidInstruction
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,11 +240,10 @@ mod tests {
|
||||
for instruction_hex in [0xf0u16, 0x0, 0x1, 0x10] {
|
||||
let instruction_bytes = instruction_hex.to_be_bytes();
|
||||
let instruction = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(instruction, PassThrough)
|
||||
assert_eq!(instruction, InvalidInstruction)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_jump_to_instruction_1() {
|
||||
let instruction_bytes = 0x1123_u16.to_be_bytes();
|
||||
@@ -361,7 +335,6 @@ mod tests {
|
||||
assert_eq!(ins, RandomAnd(0xa, 0xbd));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_draw() {
|
||||
let instruction_bytes = 0xdfab_u16.to_be_bytes();
|
||||
@@ -432,71 +405,70 @@ mod tests {
|
||||
assert_eq!(ins, LShift(0x1, 0x2))
|
||||
}
|
||||
#[test]
|
||||
fn test_skip_if_keypress(){
|
||||
fn test_skip_if_keypress() {
|
||||
let instruction_bytes = 0xef9e_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, SkipIfKeyPressed(0xf))
|
||||
}
|
||||
#[test]
|
||||
fn test_skip_if_not_keypress(){
|
||||
fn test_skip_if_not_keypress() {
|
||||
let instruction_bytes = 0xeba1_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, SkipIfKeyNotPressed(0xb))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_delay_timer(){
|
||||
fn test_fetch_delay_timer() {
|
||||
let instruction_bytes = 0xfa07_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, FetchDelayTimer(0xa))
|
||||
}
|
||||
#[test]
|
||||
fn test_set_delay_timer(){
|
||||
fn test_set_delay_timer() {
|
||||
let instruction_bytes = 0xfb15_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, SetDelayTimer(0xb))
|
||||
}
|
||||
#[test]
|
||||
fn test_set_sound_timer(){
|
||||
fn test_set_sound_timer() {
|
||||
let instruction_bytes = 0xfc18_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, SetSoundTimer(0xc))
|
||||
}
|
||||
#[test]
|
||||
fn test_add_to_index(){
|
||||
fn test_add_to_index() {
|
||||
let instruction_bytes = 0xfb1e_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, AddToIndex(0xb))
|
||||
}
|
||||
#[test]
|
||||
fn test_get_key(){
|
||||
fn test_get_key() {
|
||||
let instruction_bytes = 0xf50a_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, GetKey(0x5))
|
||||
}
|
||||
#[test]
|
||||
fn test_set_index_to_font_char(){
|
||||
fn test_set_index_to_font_char() {
|
||||
let instruction_bytes = 0xfb29_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, SetIndexToFontCharacter(0xb))
|
||||
}
|
||||
#[test]
|
||||
fn test_do_bcd_conversion(){
|
||||
fn test_do_bcd_conversion() {
|
||||
let instruction_bytes = 0xfd33_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, DoBCDConversion(0xd))
|
||||
}
|
||||
#[test]
|
||||
fn test_store_regs_to_mem(){
|
||||
fn test_store_regs_to_mem() {
|
||||
let instruction_bytes = 0xfb55_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, StoreRegistersToMemory(0xb))
|
||||
}
|
||||
#[test]
|
||||
fn test_load_regs_to_mem(){
|
||||
fn test_load_regs_to_mem() {
|
||||
let instruction_bytes = 0xf965_u16.to_be_bytes();
|
||||
let ins = Instruction::decode_instruction(&instruction_bytes);
|
||||
assert_eq!(ins, LoadRegistersFromMemory(0b1001))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ mod rom;
|
||||
|
||||
fn main() -> EmulatorResult<()> {
|
||||
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");
|
||||
|
||||
@@ -46,7 +46,7 @@ fn main() -> EmulatorResult<()> {
|
||||
|
||||
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)?;
|
||||
|
||||
@@ -163,6 +163,3 @@ fn try_initiate_sdl(draw_scale: f32) -> EmulatorResult<(WindowCanvas, EventPump,
|
||||
let event_pump = sdl_context.event_pump()?;
|
||||
Ok((canvas, event_pump, audio_queue))
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user