diff --git a/vcore/src/cpu.rs b/vcore/src/cpu.rs index bd9b44f..a0bd92d 100644 --- a/vcore/src/cpu.rs +++ b/vcore/src/cpu.rs @@ -11,7 +11,7 @@ pub struct CPU { pc: Word, // program counter, address of the low byte of the instruction dp: Word, // data pointer, address of the low byte of one cell above the data stack sp: Word, // stack pointer, address of the low byte of the return stack - iv: [Word; 256], // interrupt vectors + iv: [Word; 16], // interrupt vectors int_enabled: bool, // interrupt enable bit halted: bool, // Whether the CPU is halted sp_top: Word, // The last value given for the sp, or 0x400 @@ -31,6 +31,7 @@ enum ExecutionError { DataUnderflow, StackUnderflow, Overflow, + InvalidOpcode, } impl PeekPoke for CPU { @@ -55,7 +56,7 @@ impl CPU { pc: 1024.into(), dp: 256.into(), sp: 1024.into(), - iv: [1024.into(); 256], + iv: [1024.into(); 16], int_enabled: false, halted: true, sp_top: 0x400.into(), @@ -67,7 +68,7 @@ impl CPU { self.pc = 1024.into(); self.dp = 256.into(); self.sp = 1024.into(); - self.iv = [1024.into(); 256]; + self.iv = [1024.into(); 16]; self.int_enabled = false; self.halted = true; self.sp_top = 0x400.into(); @@ -194,7 +195,7 @@ impl CPU { } } Opcode::Setiv => { - self.iv[u8::from(x) as usize] = y; + self.iv[usize::from(x % 16)] = y; } _ => unreachable!(), } @@ -354,6 +355,7 @@ impl CPU { ExecutionError::DataUnderflow => 1, ExecutionError::StackUnderflow => 2, ExecutionError::Overflow => 3, + ExecutionError::InvalidOpcode => 4, }; self.int_enabled = false; self.push_call(self.pc); @@ -374,10 +376,7 @@ impl CPU { } } - Err(invalid_opcode) => { - self.halted = true; - println!("Error: {}", invalid_opcode) - } + Err(_) => self.pc = self.handle_error(ExecutionError::InvalidOpcode), } } @@ -398,7 +397,7 @@ impl CPU { pub fn get_stack(&self) -> Vec { let mut v = Vec::new(); - let mut curr = Word::from(self.dp_btm); + let mut curr = self.dp_btm; while curr < self.dp { v.push(self.memory.peek24(curr)); curr += 3 @@ -408,7 +407,7 @@ impl CPU { pub fn get_call(&self) -> Vec { let mut v = Vec::new(); - let mut curr = Word::from(self.sp_top); + let mut curr = self.sp_top; while curr > self.sp { curr -= 3; v.push(self.memory.peek24(curr)); diff --git a/vtest/src/integration_tests.rs b/vtest/src/integration_tests.rs index 048541b..3e116d7 100644 --- a/vtest/src/integration_tests.rs +++ b/vtest/src/integration_tests.rs @@ -421,3 +421,23 @@ fn test_overflow_promotion() { // Stack is now the previous bottom values, minus three cells: assert_eq!((22.into(), 16.into()), cpu.sdp()); } + +#[test] +fn test_invalid_opcode() { + let cpu = test_mem( + ".org 0x400 + push onop + setiv 4 ; set the overflow handler + push 1 + push 2 ; fine so far + .org 0x4ff ; bunch of nops and then... + .db 0xf6 ; this isn't an instruction! + store ; never happens + onop: hlt" + .lines(), + [(256, 1), (259, 2)].into(), // expect the two successful pushes to be still there + ); + + // Call stack contains the address of the offending instruction + assert_eq!(vec![Word::from(0x4ff)], cpu.get_call()); +}