diff --git a/emulator/src/emulator/system/emulator.rs b/emulator/src/emulator/system/emulator.rs index 24daa34..04c1118 100644 --- a/emulator/src/emulator/system/emulator.rs +++ b/emulator/src/emulator/system/emulator.rs @@ -30,7 +30,11 @@ pub fn run_emulator( let mut history = Vec::<(u32, Instruction)>::new(); let size = 256; - let memory_view = processor.memory.read_range(addr, size); + let memory_view = processor + .memory + .read_range(addr, size) + .expect("Failed to read initial memory state!"); + let initial_state = state(&mut processor, running, 0, memory_view, &mut history); let _ = state_tx.send(initial_state); @@ -114,14 +118,25 @@ pub fn run_emulator( addr = new; } Command::Write(offset, data) => { - processor.memory.write_range(offset, data); + processor + .memory + .write_range(offset, data) + .unwrap_or_else(|_| { + eprintln!("Failed to write memory range!"); + processor.begin_interrupt(Interrupt::HardFault); + }); } Command::Interrupt(_interrupt) => { todo!("implement interrupts") } } - let memory_view = processor.memory.read_range(addr, size); + let memory_view = + processor.memory.read_range(addr, size).unwrap_or_else(|_| { + eprintln!("Failed to read memory range!"); + processor.begin_interrupt(Interrupt::HardFault); + Vec::new() + }); let state = state( &mut processor, running, @@ -130,8 +145,6 @@ pub fn run_emulator( &mut history, ); - println!("state"); - let _ = state_tx.send(state); } @@ -166,7 +179,15 @@ pub fn run_emulator( } if update { - let memory_view = processor.memory.read_range(addr, size); + let memory_view = + processor + .memory + .read_range(addr, size) + .unwrap_or_else(|why| { + eprintln!("Failed to read memory range! Reason: {why}"); + processor.begin_interrupt(Interrupt::HardFault); + Vec::new() + }); let state = state( &mut processor, running, @@ -185,7 +206,7 @@ pub fn run_emulator( } fn state( - cpu_lock: &mut Processor, + processor: &mut Processor, running: Running, instruction_count: usize, memory_view: Vec, @@ -196,12 +217,18 @@ fn state( State { // TODO: Replace with actual register access from your CPU. - reg_file: cpu_lock.registers, + reg_file: processor.registers, running, instructions: instruction_count, - stack_view: cpu_lock.get_stack(32), + stack_view: processor.get_stack(32).unwrap_or_else(|_| { + processor.begin_interrupt(Interrupt::HardFault); + Vec::new() + }), memory_view, - display_view: cpu_lock.display(), + display_view: processor.display().unwrap_or_else(|_| { + processor.begin_interrupt(Interrupt::HardFault); + Vec::new() + }), error: None, persistent: PersistentState { history: hsclone }, } diff --git a/emulator/src/emulator/system/memory.rs b/emulator/src/emulator/system/memory.rs index 32f2b48..ccc9719 100644 --- a/emulator/src/emulator/system/memory.rs +++ b/emulator/src/emulator/system/memory.rs @@ -1,13 +1,43 @@ use std::collections::HashMap; +use crate::emulator::system::model::ProcessorError; + pub trait MemoryUnit: Send + Sync { fn reset(&mut self); - fn read_byte(&mut self, addr: u32) -> u8; - fn write_byte(&mut self, addr: u32, value: u8); - fn read_word(&mut self, addr: u32) -> u32; - fn write_word(&mut self, addr: u32, value: u32); - fn read_range(&mut self, addr: u32, size: u32) -> Vec; - fn write_range(&mut self, addr: u32, value: Vec); + fn read_byte(&mut self, addr: u32) -> Result; + fn write_byte(&mut self, addr: u32, value: u8) -> Result<(), ProcessorError>; + fn read_word(&mut self, addr: u32) -> Result; + fn write_word(&mut self, addr: u32, value: u32) -> Result<(), ProcessorError>; + + fn read_range(&mut self, addr: u32, size: u32) -> Result, ProcessorError> { + let mut data = Vec::with_capacity(size as usize); + for i in 0..size { + data.push(self.read_byte(addr + i)?); + } + Ok(data) + } + + fn write_range(&mut self, addr: u32, value: Vec) -> Result<(), ProcessorError> { + for (i, byte) in value.into_iter().enumerate() { + self.write_byte(addr + i as u32, byte)?; + } + Ok(()) + } + + fn read_block(&mut self, addr: u32) -> Result<[u8; 256], ProcessorError> { + let mut data = [0; 256]; + for i in 0..256 { + data[i] = self.read_byte(addr + i as u32)?; + } + Ok(data) + } + + fn write_block(&mut self, addr: u32, data: [u8; 256]) -> Result<(), ProcessorError> { + for i in 0..256 { + self.write_byte(addr + i as u32, data[i])?; + } + Ok(()) + } } pub struct MainStore { @@ -64,59 +94,77 @@ impl MemoryUnit for MainStore { self.data.clear(); } - fn read_byte(&mut self, addr: u32) -> u8 { + fn read_byte(&mut self, addr: u32) -> Result { let (block_addr, offset) = Self::segment_addr(addr); let block = self.block(block_addr); - block.data[offset as usize] + Ok(block.data[offset as usize]) } - fn read_word(&mut self, addr: u32) -> u32 { + fn read_word(&mut self, addr: u32) -> Result { + if addr % 4 != 0 { + return Err(ProcessorError::BadMemoryAccess(addr)); + } + let (block_addr, offset) = Self::segment_addr(addr); - - println!("reading word from {block_addr:x?} + {offset}"); - let block = self.mut_block(block_addr); let mut bytes = [0; 4]; bytes[0] = block.data[offset as usize]; bytes[1] = block.data[(offset + 1) as usize]; bytes[2] = block.data[(offset + 2) as usize]; bytes[3] = block.data[(offset + 3) as usize]; - u32::from_be_bytes(bytes) + Ok(u32::from_be_bytes(bytes)) } - fn read_range(&mut self, addr: u32, size: u32) -> Vec { + fn read_range(&mut self, addr: u32, size: u32) -> Result, ProcessorError> { let mut data = Vec::with_capacity(size as usize); for i in 0..size { - data.push(self.read_byte(addr + i)); + data.push(self.read_byte(addr + i)?); } - // println!("reading {data:?} from {addr:x?}"); - - data + Ok(data) } - fn write_byte(&mut self, addr: u32, value: u8) { + fn write_byte(&mut self, addr: u32, value: u8) -> Result<(), ProcessorError> { let (block_addr, offset) = Self::segment_addr(addr); let block = self.mut_block(block_addr); block.data[offset as usize] = value; + Ok(()) } - fn write_word(&mut self, addr: u32, value: u32) { + fn write_word(&mut self, addr: u32, value: u32) -> Result<(), ProcessorError> { + if addr % 4 != 0 { + return Err(ProcessorError::BadMemoryAccess(addr)); + } + let (block_addr, offset) = Self::segment_addr(addr); let block = self.mut_block(block_addr); block.data[offset as usize] = (value >> 24) as u8; block.data[(offset + 1) as usize] = (value >> 16) as u8; block.data[(offset + 2) as usize] = (value >> 8) as u8; block.data[(offset + 3) as usize] = value as u8; + Ok(()) } - fn write_range(&mut self, addr: u32, value: Vec) { - // println!("writing {value:?} to {addr:x?}"); - + fn write_range(&mut self, addr: u32, value: Vec) -> Result<(), ProcessorError> { for (i, byte) in value.into_iter().enumerate() { let (block_addr, offset) = Self::segment_addr(addr + i as u32); let block = self.mut_block(block_addr); block.data[offset as usize] = byte; } + + Ok(()) + } + + fn read_block(&mut self, addr: u32) -> Result<[u8; 256], ProcessorError> { + let (block_addr, _) = Self::segment_addr(addr); + let block = self.block(block_addr); + Ok(block.data) + } + + fn write_block(&mut self, addr: u32, data: [u8; 256]) -> Result<(), ProcessorError> { + let (block_addr, _) = Self::segment_addr(addr); + let block = self.mut_block(block_addr); + block.data = data; + Ok(()) } } diff --git a/emulator/src/emulator/system/model.rs b/emulator/src/emulator/system/model.rs index 76c16f1..5b39a8e 100644 --- a/emulator/src/emulator/system/model.rs +++ b/emulator/src/emulator/system/model.rs @@ -27,6 +27,31 @@ pub enum Command { Write(Address, Vec), } +#[derive(Debug)] +pub enum ProcessorError { + InvalidInstruction(u32), + InvalidRegister(u8), + BadMemoryAccess(u32), +} + +impl std::error::Error for ProcessorError {} + +impl std::fmt::Display for ProcessorError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidInstruction(instruction) => { + write!(f, "Invalid instruction: {instruction}") + } + Self::InvalidRegister(register) => { + write!(f, "Invalid register: {register}") + } + Self::BadMemoryAccess(address) => { + write!(f, "Bad memory access: {address}") + } + } + } +} + #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub struct RegFile { // General Purpose Registers diff --git a/emulator/src/emulator/system/processor/mod.rs b/emulator/src/emulator/system/processor/mod.rs index c5f7fde..aa4f425 100644 --- a/emulator/src/emulator/system/processor/mod.rs +++ b/emulator/src/emulator/system/processor/mod.rs @@ -5,12 +5,10 @@ use std::{ use crate::emulator::system::{ memory::MemoryUnit, - model::{IODevice, RegFile}, + model::{IODevice, ProcessorError, RegFile}, }; -use common::instructions::{ - Instruction, Interrupt, Register, errors::InstructionDecodeError, -}; +use common::instructions::{Instruction, Interrupt, Register}; pub struct Processor { pub memory: Box, @@ -25,7 +23,6 @@ fn log(message: &str) { println!("\x1b[32mINFO:\x1b[0m {message}"); } -#[allow(clippy::needless_pass_by_ref_mut)] impl Processor { #[must_use] pub fn new(memory: Box, io_devices: Vec>) -> Self { @@ -48,7 +45,7 @@ impl Processor { self.memory.reset(); } - pub fn cycle(&mut self) -> Result<(u32, Instruction), InstructionDecodeError> { + pub fn cycle(&mut self) -> Result<(u32, Instruction), ProcessorError> { self.halted = false; // Get value from PCX. @@ -58,17 +55,18 @@ impl Processor { // Set MAR to the previous value of PCX. *self.reg(Register::Mar) = addr; - let val = self.memory.read_word(addr); + let val = self.memory.read_word(addr)?; // Set CIR to the value of RAM[MAR]. *self.reg(Register::Mar) = val; // Decode and execute the instruction. - let instruction = Instruction::decode(val)?; + let instruction = Instruction::decode(val) + .map_err(|_| ProcessorError::InvalidInstruction(val))?; log(&instruction.to_string()); - instruction.execute(self); + instruction.execute(self)?; Ok((addr, instruction)) } @@ -89,7 +87,7 @@ impl Processor { } } - pub fn display(&mut self) -> Vec { + pub fn display(&mut self) -> Result, ProcessorError> { self.memory.read_range(0x20000, 2000) } @@ -99,21 +97,7 @@ impl Processor { self.set_flag(Flag::LessThan, a < b); } - // stack operations - - pub fn push(&mut self, value: u32) { - let stack_ptr = self.get(Register::Spr); - *self.reg(Register::Spr) += 4; - self.memory.write_word(stack_ptr, value); - } - - pub fn pop(&mut self) -> u32 { - *self.reg(Register::Spr) -= 4; - self.memory.read_word(self.get(Register::Spr)) - } - // functions to set new state - fn set_flag(&mut self, flag: Flag, value: bool) { if value { *self.reg(Register::Sts) |= flag as u32; @@ -135,16 +119,18 @@ impl Processor { *self.reg(Register::Pcx) = self.get(reg) + u32::from(offset); } - fn begin_interrupt(&mut self, _int: Interrupt) { + pub fn begin_interrupt(&mut self, _int: Interrupt) { // first we get the address of the interrupt descriptor table. todo!(); } + // TODO: remove this once implemented + #[allow(clippy::needless_pass_by_ref_mut)] fn end_interrupt(&mut self) { todo!(); } - pub fn get_stack(&mut self, n: u32) -> Vec { + pub fn get_stack(&mut self, n: u32) -> Result, ProcessorError> { let addr = self.get(Register::Spr); let size = n * 4; // returns the stack @@ -170,12 +156,12 @@ enum Flag { } trait Executable { - fn execute(self, cpu: &mut Processor); + fn execute(self, cpu: &mut Processor) -> Result<(), ProcessorError>; } impl Executable for Instruction { #[allow(clippy::too_many_lines)] - fn execute(self, cpu: &mut Processor) { + fn execute(self, cpu: &mut Processor) -> Result<(), ProcessorError> { match self { // No operation - a blank line. // Copies from SrcReg to a.drReg. @@ -193,7 +179,8 @@ impl Executable for Instruction { // effective address must be byte-aligned. Self::LoadByte(a) => { *cpu.reg(a.r2) = u32::from( - cpu.memory.read_byte(cpu.get(a.r1) + u32::from(a.immediate)), + cpu.memory + .read_byte(cpu.get(a.r1) + u32::from(a.immediate))?, ); } @@ -201,7 +188,8 @@ impl Executable for Instruction { // a.drReg. The effective address must be byte-aligned. Self::LoadByteSigned(a) => { *cpu.reg(a.r2) = sign_extend(u32::from( - cpu.memory.read_byte(cpu.get(a.r1) + u32::from(a.immediate)), + cpu.memory + .read_byte(cpu.get(a.r1) + u32::from(a.immediate))?, )); } @@ -210,23 +198,28 @@ impl Executable for Instruction { Self::LoadHalfword(a) => { // we read an entire word, then right shift so we only get the first half // of the word - *cpu.reg(a.r2) = - cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16; + *cpu.reg(a.r2) = cpu + .memory + .read_word(cpu.get(a.r1) + u32::from(a.immediate))? + >> 16; } // Loads a sign-extended half-word from memory address (base + offset) into // a.drReg. The effective address must be 2-byte-aligned. Self::LoadHalfwordSigned(a) => { *cpu.reg(a.r2) = sign_extend( - cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16, + cpu.memory + .read_word(cpu.get(a.r1) + u32::from(a.immediate))? + >> 16, ); } // Loads a word from memory address (base + offset) into a.drReg. The // effective address must be 4-byte-aligned. Self::LoadWord(a) => { - *cpu.reg(a.r2) = - cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)); + *cpu.reg(a.r2) = cpu + .memory + .read_word(cpu.get(a.r1) + u32::from(a.immediate))?; } // Stores a byte from SrcReg in memory address (base + offset) The effective @@ -235,7 +228,7 @@ impl Executable for Instruction { cpu.memory.write_byte( cpu.get(a.r2) + u32::from(a.immediate), cpu.get(a.r1) as u8, - ); + )?; } // Stores a half-word from SrcReg in memory address (base + offset) The @@ -244,16 +237,16 @@ impl Executable for Instruction { // split the value into bytes and then write two bytes let bytes = (cpu.get(a.r1) as u16).to_le_bytes(); cpu.memory - .write_byte(cpu.get(a.r2) + u32::from(a.immediate), bytes[0]); + .write_byte(cpu.get(a.r2) + u32::from(a.immediate), bytes[0])?; cpu.memory - .write_byte(cpu.get(a.r2) + u32::from(a.immediate) + 1, bytes[1]); + .write_byte(cpu.get(a.r2) + u32::from(a.immediate) + 1, bytes[1])?; } // Stores a word from SrcReg in memory address (base + offset) The effective // address must be 4-byte-aligned. Self::StoreWord(a) => { cpu.memory - .write_word(cpu.get(a.r2) + u32::from(a.immediate), cpu.get(a.r1)); + .write_word(cpu.get(a.r2) + u32::from(a.immediate), cpu.get(a.r1))?; } // Loads a 16-bit literal value into reg, setting the bottom 16 bits of the @@ -411,6 +404,7 @@ impl Executable for Instruction { todo!() } } + Ok(()) } } diff --git a/emulator/src/emulator/system/processor/tests.rs b/emulator/src/emulator/system/processor/tests.rs index 5636a61..8276c2a 100644 --- a/emulator/src/emulator/system/processor/tests.rs +++ b/emulator/src/emulator/system/processor/tests.rs @@ -13,7 +13,9 @@ fn test_nop_instruction() { let mut cpu = create_test_processor(); let initial_state = cpu.registers; - Instruction::Nop.execute(&mut cpu); + Instruction::Nop.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!( cpu.registers.get(Register::Rg0), @@ -37,7 +39,9 @@ fn test_mov_instruction() { None, )); - mov_instr.execute(&mut cpu); + mov_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg2), 0x1234_5678); } @@ -53,7 +57,9 @@ fn test_mov_signed_instruction() { None, )); - mov_signed_instr.execute(&mut cpu); + mov_signed_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg2), 0xFFFF_FFFF); } @@ -61,7 +67,9 @@ fn test_mov_signed_instruction() { fn test_load_byte_instruction() { let mut cpu = create_test_processor(); let addr = 0x100; - cpu.memory.write_byte(addr, 0xAB); + cpu.memory + .write_byte(addr, 0xAB) + .expect("Failed to write byte to memory"); *cpu.reg(Register::Rg1) = addr - 4; let load_byte_instr = Instruction::LoadByte(ITypeArgs::new( @@ -70,7 +78,9 @@ fn test_load_byte_instruction() { Some(Register::Rg2), )); - load_byte_instr.execute(&mut cpu); + load_byte_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg2), 0x0000_00AB); } @@ -78,7 +88,9 @@ fn test_load_byte_instruction() { fn test_load_byte_signed_instruction() { let mut cpu = create_test_processor(); let addr = 0x100; - cpu.memory.write_byte(addr, 0xFF); + cpu.memory + .write_byte(addr, 0xFF) + .expect("Failed to write byte to memory"); *cpu.reg(Register::Rg1) = addr; let load_byte_signed_instr = Instruction::LoadByteSigned(ITypeArgs::new( @@ -87,7 +99,9 @@ fn test_load_byte_signed_instruction() { Some(Register::Rg2), )); - load_byte_signed_instr.execute(&mut cpu); + load_byte_signed_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg2), 0xFFFF_FFFF); } @@ -95,7 +109,9 @@ fn test_load_byte_signed_instruction() { fn test_load_halfword_instruction() { let mut cpu = create_test_processor(); let addr = 0x100; - cpu.memory.write_word(addr, 0x1234_5678); + cpu.memory + .write_word(addr, 0x1234_5678) + .expect("Failed to write word to memory"); *cpu.reg(Register::Rg1) = addr; let load_halfword_instr = Instruction::LoadHalfword(ITypeArgs::new( @@ -104,7 +120,9 @@ fn test_load_halfword_instruction() { Some(Register::Rg2), )); - load_halfword_instr.execute(&mut cpu); + load_halfword_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg2), 0x0000_1234); } @@ -112,7 +130,9 @@ fn test_load_halfword_instruction() { fn test_load_word_instruction() { let mut cpu = create_test_processor(); let addr = 0x100; - cpu.memory.write_word(addr, 0x1234_5678); + cpu.memory + .write_word(addr, 0x1234_5678) + .expect("Failed to write word to memory"); *cpu.reg(Register::Rg1) = addr; let load_word_instr = Instruction::LoadWord(ITypeArgs::new( @@ -121,7 +141,9 @@ fn test_load_word_instruction() { Some(Register::Rg2), )); - load_word_instr.execute(&mut cpu); + load_word_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg2), 0x1234_5678); } @@ -138,8 +160,10 @@ fn test_store_byte_instruction() { Some(Register::Rg1), )); - store_byte_instr.execute(&mut cpu); - assert_eq!(cpu.memory.read_byte(addr), 0xAB); + store_byte_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); + assert_eq!(cpu.memory.read_byte(addr).expect("Emulator was slain by losing the game while attempting to execute instruction"), 0xAB); } #[test] @@ -155,8 +179,10 @@ fn test_store_word_instruction() { Some(Register::Rg1), )); - store_word_instr.execute(&mut cpu); - assert_eq!(cpu.memory.read_word(addr), 0x1234_5678); + store_word_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); + assert_eq!(cpu.memory.read_word(addr).expect("Emulator was slain by losing the game while attempting to execute instruction"), 0x1234_5678); } #[test] @@ -172,7 +198,9 @@ fn test_add_instruction() { None, )); - add_instr.execute(&mut cpu); + add_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg3), 40); } @@ -189,7 +217,9 @@ fn test_sub_instruction() { None, )); - sub_instr.execute(&mut cpu); + sub_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg3), 30); } @@ -206,7 +236,9 @@ fn test_and_instruction() { None, )); - and_instr.execute(&mut cpu); + and_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg3), 0b1000); } @@ -223,7 +255,9 @@ fn test_or_instruction() { None, )); - or_instr.execute(&mut cpu); + or_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg3), 0b1110); } @@ -240,7 +274,9 @@ fn test_xor_instruction() { None, )); - xor_instr.execute(&mut cpu); + xor_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg3), 0b0110); } @@ -256,7 +292,9 @@ fn test_not_instruction() { None, )); - not_instr.execute(&mut cpu); + not_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg2), 0xF0F0_F0F0); } @@ -273,7 +311,9 @@ fn test_compare_equal() { None, )); - cmp_instr.execute(&mut cpu); + cmp_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert!(cpu.get_flag(Flag::Equal)); assert!(!cpu.get_flag(Flag::GreaterThan)); @@ -293,7 +333,9 @@ fn test_compare_greater_than() { None, )); - cmp_instr.execute(&mut cpu); + cmp_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert!(!cpu.get_flag(Flag::Equal)); assert!(cpu.get_flag(Flag::GreaterThan)); @@ -313,7 +355,9 @@ fn test_compare_less_than() { None, )); - cmp_instr.execute(&mut cpu); + cmp_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert!(!cpu.get_flag(Flag::Equal)); assert!(!cpu.get_flag(Flag::GreaterThan)); @@ -328,7 +372,9 @@ fn test_increment_instruction() { let inc_instr = Instruction::Increment(RTypeArgs::new(Some(Register::Rg1), None, None, None)); - inc_instr.execute(&mut cpu); + inc_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg1), 43); } @@ -340,7 +386,9 @@ fn test_decrement_instruction() { let dec_instr = Instruction::Decrement(RTypeArgs::new(Some(Register::Rg1), None, None, None)); - dec_instr.execute(&mut cpu); + dec_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg1), 41); } @@ -356,7 +404,9 @@ fn test_shift_left_with_shamt() { Some(2), )); - shl_instr.execute(&mut cpu); + shl_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg1), 0b10_1000); } @@ -372,7 +422,9 @@ fn test_shift_right_with_shamt() { Some(2), )); - shr_instr.execute(&mut cpu); + shr_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg1), 0b1010); } @@ -389,7 +441,9 @@ fn test_shift_left_with_register() { None, )); - shl_instr.execute(&mut cpu); + shl_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg1), 0b101_0000); } @@ -403,7 +457,9 @@ fn test_load_lower_immediate() { None, )); - lli_instr.execute(&mut cpu); + lli_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg1), 0x0000_1234); } @@ -418,7 +474,9 @@ fn test_load_upper_immediate() { None, )); - lui_instr.execute(&mut cpu); + lui_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg1), 0x1234_5678); } @@ -430,7 +488,9 @@ fn test_jump_unconditional() { let jump_instr = Instruction::Jump(ITypeArgs::new(0x100, Some(Register::Rg1), None)); - jump_instr.execute(&mut cpu); + jump_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Pcx), 0x1100); assert_ne!(cpu.get(Register::Pcx), initial_pc); } @@ -444,7 +504,9 @@ fn test_jump_equal_when_flag_set() { let jump_eq_instr = Instruction::JumpEq(ITypeArgs::new(0x100, Some(Register::Rg1), None)); - jump_eq_instr.execute(&mut cpu); + jump_eq_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Pcx), 0x1100); } @@ -458,7 +520,9 @@ fn test_jump_equal_when_flag_not_set() { let jump_eq_instr = Instruction::JumpEq(ITypeArgs::new(0x100, Some(Register::Rg1), None)); - jump_eq_instr.execute(&mut cpu); + jump_eq_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Pcx), initial_pc); } @@ -467,7 +531,9 @@ fn test_halt_instruction() { let mut cpu = create_test_processor(); assert!(!cpu.halted); - Instruction::Halt.execute(&mut cpu); + Instruction::Halt.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert!(cpu.halted); } @@ -484,7 +550,9 @@ fn test_nand_instruction() { None, )); - nand_instr.execute(&mut cpu); + nand_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg3), !0b1000); } @@ -501,7 +569,9 @@ fn test_nor_instruction() { None, )); - nor_instr.execute(&mut cpu); + nor_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg3), !0b1110); } @@ -518,6 +588,8 @@ fn test_xnor_instruction() { None, )); - xnor_instr.execute(&mut cpu); + xnor_instr.execute(&mut cpu).expect( + "Emulator was slain by losing the game while attempting to execute instruction", + ); assert_eq!(cpu.get(Register::Rg3), !0b0110); }