diff --git a/assembler/src/assembler/codegen.rs b/assembler/src/assembler/codegen.rs index 5c101a4..3e34281 100644 --- a/assembler/src/assembler/codegen.rs +++ b/assembler/src/assembler/codegen.rs @@ -11,10 +11,7 @@ pub fn codegen(nodes: Vec) -> Result, AssembleError> { let mut instructions = vec![]; for node in nodes { - instructions.push( - build_instruction(&node) - .unwrap_or_else(|_| panic!("Failed to build instruction: {node:?}")), - ); + instructions.push(build_instruction(&node)?); } println!("------------------------"); diff --git a/common/src/instructions.rs b/common/src/instructions.rs index 381e739..032e4ae 100644 --- a/common/src/instructions.rs +++ b/common/src/instructions.rs @@ -10,7 +10,9 @@ pub enum Interrupt { pub type Address = u32; impl Interrupt { - const fn as_u8(self) -> u8 { + // someone tell clippy to stfu. + #[allow(clippy::must_use_candidate)] + pub const fn as_u8(self) -> u8 { match self { Self::Breakpoint => 0, Self::HardFault => 1, diff --git a/common/src/instructions/encode.rs b/common/src/instructions/encode.rs index f6d65d7..7b11a55 100644 --- a/common/src/instructions/encode.rs +++ b/common/src/instructions/encode.rs @@ -54,12 +54,14 @@ impl Encode for Instruction { ], no_args: [Nop, IntReturn, Halt], special: [ - Self::Interrupt(_) => todo!(), Self::Data(data) => data, + Self::Interrupt(interrupt) => { + let opcode = u32::from(self.opcode()); + (opcode << 26) | u32::from(interrupt.as_u8()) + }, Self::Segment(segment) => { let opcode = u32::from(self.opcode()); - let segment = segment as u8; - (opcode << 26) | u32::from(segment) + (opcode << 26) | u32::from(segment as u8) } ] ) diff --git a/emulator/src/emulator/system/emulator.rs b/emulator/src/emulator/system/emulator.rs index fec2a9a..376659f 100644 --- a/emulator/src/emulator/system/emulator.rs +++ b/emulator/src/emulator/system/emulator.rs @@ -212,8 +212,14 @@ pub fn run_emulator( Ok(instruction) => instruction, Err(why) => { let pcx = processor.get(Register::Pcx); - eprintln!("Could not decode instruction at {pcx:x}. Reason: {why}"); - continue; + report_err( + state_tx, + &format!( + "Could not decode instruction at {pcx:x}. Reason: {why}" + ), + &mut processor, + ); + (pcx, Instruction::Nop) } }; @@ -228,6 +234,8 @@ pub fn run_emulator( } fn report_err(state_tx: &Sender, why: &str, processor: &mut Processor) { - processor.begin_interrupt(Interrupt::HardFault); + processor + .begin_interrupt(Interrupt::HardFault) + .expect("What kind of goofy ahh shenanigans did you do with your fault handler? At this point, the emulator can just crash. this is on you."); let _ = state_tx.send(StateUpdate::Error(why.to_string())); } diff --git a/emulator/src/emulator/system/processor/mod.rs b/emulator/src/emulator/system/processor/mod.rs index 3e9a37a..e3997dc 100644 --- a/emulator/src/emulator/system/processor/mod.rs +++ b/emulator/src/emulator/system/processor/mod.rs @@ -116,15 +116,42 @@ impl Processor { *self.reg(Register::Pcx) = self.get(reg) + u32::from(offset); } - pub fn begin_interrupt(&mut self, _int: Interrupt) { - // first we get the address of the interrupt descriptor table. - todo!(); + pub fn begin_interrupt( + &mut self, + interrupt: Interrupt, + ) -> Result<(), ProcessorError> { + let idt = self.get(Register::Idr); + + let addr = self + .memory + .read_word(idt + u32::from(interrupt.as_u8()) * 4)?; + println!("INFO: Interrupt {interrupt:?} addr: {addr}"); + + self.push(self.get(Register::Pcx))?; + *self.reg(Register::Pcx) = addr; + Ok(()) + } + + fn push(&mut self, val: u32) -> Result<(), ProcessorError> { + *self.reg(Register::Spr) -= 4; + let reg = *self.reg(Register::Spr); + self.memory.write_word(reg, val) + } + + fn pop(&mut self) -> Result { + let reg = *self.reg(Register::Spr); + let val = self.memory.read_word(reg)?; + *self.reg(Register::Spr) += 4; + Ok(val) } // TODO: remove this once implemented #[allow(clippy::needless_pass_by_ref_mut)] - fn end_interrupt(&mut self) { - todo!(); + fn end_interrupt(&mut self) -> Result<(), ProcessorError> { + let ret = self.pop()?; + *self.reg(Register::Ret) = ret; + *self.reg(Register::Pcx) = ret; + Ok(()) } pub fn get_stack(&mut self, n: u32) -> Result, ProcessorError> { @@ -382,12 +409,12 @@ impl Executable for Instruction { // - The return address is saved to the RET register. // - The stack base ptr is set to the kernel stack. Self::Interrupt(interrupt_code) => { - cpu.begin_interrupt(interrupt_code); + cpu.begin_interrupt(interrupt_code)?; } // Returns from an interrupt, Self::IntReturn => { - cpu.end_interrupt(); + cpu.end_interrupt()?; } // Halts the processor.