diff --git a/dcb-exe/src/inst/basic.rs b/dcb-exe/src/inst/basic.rs index 78ae37d..b1374d4 100644 --- a/dcb-exe/src/inst/basic.rs +++ b/dcb-exe/src/inst/basic.rs @@ -207,9 +207,8 @@ impl Executable for Inst { Inst::Mult (inst) => inst.exec(state), Inst::Shift(inst) => inst.exec(state), Inst::Store(inst) => inst.exec(state), - //Inst::Sys (inst) => inst.exec(state), - //Inst::Co (inst) => inst.exec(state), - _ => todo!(), + Inst::Sys (inst) => inst.exec(state), + Inst::Co (_) => todo!(), } } } diff --git a/dcb-exe/src/inst/basic/sys.rs b/dcb-exe/src/inst/basic/sys.rs index e0af2a9..8631710 100644 --- a/dcb-exe/src/inst/basic/sys.rs +++ b/dcb-exe/src/inst/basic/sys.rs @@ -4,6 +4,7 @@ use super::ModifiesReg; use crate::inst::{ basic::{Decode, TryEncode}, + exec::{ExecCtx, ExecError, Executable}, parse::LineArg, DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register, }; @@ -121,3 +122,9 @@ impl ModifiesReg for Inst { false } } + +impl Executable for Inst { + fn exec(&self, state: &mut Ctx) -> Result<(), ExecError> { + state.sys(*self) + } +} diff --git a/dcb-exe/src/inst/exec.rs b/dcb-exe/src/inst/exec.rs index 44d9bc0..03cc8b2 100644 --- a/dcb-exe/src/inst/exec.rs +++ b/dcb-exe/src/inst/exec.rs @@ -7,6 +7,7 @@ pub mod error; pub use error::ExecError; // Imports +use super::basic; use crate::{ inst::{basic::mult::MultReg, Register}, Pos, @@ -40,6 +41,9 @@ pub trait ExecCtx: /// Writes a byte fn write_byte(&mut self, pos: Pos, value: u8) -> Result<(), ExecError>; + + /// Executes a syscall + fn sys(&mut self, inst: basic::sys::Inst) -> Result<(), ExecError>; } /// An executable instruction diff --git a/dcb-exe/src/inst/exec/error.rs b/dcb-exe/src/inst/exec/error.rs index 37560bc..4024121 100644 --- a/dcb-exe/src/inst/exec/error.rs +++ b/dcb-exe/src/inst/exec/error.rs @@ -33,6 +33,9 @@ pub enum ExecError { JumpWhileJumping, /// Unknown syscall - #[error("Unknown syscall")] - UnknownSys, + #[error("Unknown syscall {comment:#x}")] + UnknownSys { + /// Syscall comment + comment: u32, + }, } diff --git a/dcb-tools/dcb-dbg/src/main.rs b/dcb-tools/dcb-dbg/src/main.rs index e9b87d9..d762395 100644 --- a/dcb-tools/dcb-dbg/src/main.rs +++ b/dcb-tools/dcb-dbg/src/main.rs @@ -17,8 +17,6 @@ use dcb_exe::{ Pos, }; use std::{ - cell::RefCell, - collections::HashMap, convert::TryInto, fs, ops::{Index, IndexMut}, @@ -50,43 +48,12 @@ fn main() -> Result<(), anyhow::Error> { lo_hi_reg: [0; 2], memory: memory.into(), jump_target: JumpTarget::None, + should_stop: false, }; - // Setup syscalls - let should_stop = RefCell::new(false); - let sys0 = |_: &mut ExecState| { - *should_stop.borrow_mut() = true; - Ok(()) - }; - let sys1 = |state: &mut ExecState| { - // Print whatever string is in `$v0` - let ptr = Pos(state[Register::V0]); - - for n in 0u32.. { - match state.read_byte(ptr + n)? { - 0 => break, - b => print!("{}", char::from(b)), - } - } - - Ok(()) - }; - let sys2 = |state: &mut ExecState| { - // Print all registers - for ® in &Register::ALL_REGISTERS { - println!("{}: {:#x}", reg, state[reg]); - } - - Ok(()) - }; - let mut syscalls: HashMap> = - vec![(0, box_fn_mut(sys0)), (1, box_fn_mut(sys1)), (2, box_fn_mut(sys2))] - .into_iter() - .collect(); - - while !*should_stop.borrow() { + while !exec_state.should_stop { exec_state - .exec(&mut syscalls) + .exec() .with_context(|| format!("Failed to execute at {}", exec_state.pc()))?; } @@ -94,13 +61,6 @@ fn main() -> Result<(), anyhow::Error> { Ok(()) } -fn box_fn_mut<'a>( - f: impl FnMut(&mut ExecState) -> Result<(), ExecError> + 'a, -) -> Box Result<(), ExecError> + 'a> { - box f -} - - /// Execution state pub struct ExecState { /// Program counter @@ -117,26 +77,22 @@ pub struct ExecState { /// Jump target jump_target: JumpTarget, + + /// If the processor should stop + should_stop: bool, } impl ExecState { /// Executes the next instruction - fn exec(&mut self, sys_calls: &mut HashMap>) -> Result<(), ExecError> { + fn exec(&mut self) -> Result<(), ExecError> { // Read the next instruction let inst = self.read_word(self.pc)?; // Parse the instruction let inst = basic::Inst::decode(inst).ok_or(ExecError::DecodeInst)?; - match inst { - // Special case syscalls here - // TODO: Better solution than this - basic::Inst::Sys(inst) => { - let f = sys_calls.get_mut(&inst.comment).ok_or(ExecError::UnknownSys)?; - f(self)?; - }, - _ => inst.exec(self)?, - } + // Then execute the instruction + inst.exec(self)?; // Then update our pc depending on whether we have a jump self.pc = match self.jump_target { @@ -275,6 +231,34 @@ impl ExecCtx for ExecState { Ok(()) } + + fn sys(&mut self, inst: basic::sys::Inst) -> Result<(), ExecError> { + match inst.comment { + 0x0 => { + self.should_stop = true; + }, + 0x1 => { + // Print whatever string is in `$v0` + let ptr = Pos(self[Register::V0]); + + for n in 0u32.. { + match self.read_byte(ptr + n)? { + 0 => break, + b => print!("{}", char::from(b)), + } + } + }, + 0x2 => { + // Print all registers + for ® in &Register::ALL_REGISTERS { + println!("{}: {:#x}", reg, self[reg]); + } + }, + comment => return Err(ExecError::UnknownSys { comment }), + } + + Ok(()) + } } impl Index for ExecState {