parent
							
								
									1d444fd516
								
							
						
					
					
						commit
						3e0aaa71e9
					
				@ -0,0 +1,50 @@ | 
				
			|||||||
 | 
					use crate::asm::data::literal::{Label, RoutineName, DebugMsg}; | 
				
			||||||
 | 
					use crate::asm::instr::{Cond, Op}; | 
				
			||||||
 | 
					use crate::asm::data::{Rd, Wr}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)] | 
				
			||||||
 | 
					pub enum BuiltinOp { | 
				
			||||||
 | 
					    /// Do nothing
 | 
				
			||||||
 | 
					    Nop, | 
				
			||||||
 | 
					    /// Mark a jump target.
 | 
				
			||||||
 | 
					    Label(Label), | 
				
			||||||
 | 
					    /// Jump to a label
 | 
				
			||||||
 | 
					    Jump(Label), | 
				
			||||||
 | 
					    /// Jump to a label if a flag is set
 | 
				
			||||||
 | 
					    JumpIf(Cond, Label), | 
				
			||||||
 | 
					    /// Far jump to a label if a flag is set
 | 
				
			||||||
 | 
					    FarJumpIf(Cond, Label), | 
				
			||||||
 | 
					    /// Mark a far jump target (can be jumped to from another routine).
 | 
				
			||||||
 | 
					    /// This label is preserved in optimized code.
 | 
				
			||||||
 | 
					    FarLabel(Label), | 
				
			||||||
 | 
					    /// Jump to a label that can be in another function
 | 
				
			||||||
 | 
					    FarJump(Label), | 
				
			||||||
 | 
					    /// Call a routine with arguments.
 | 
				
			||||||
 | 
					    /// The arguments are passed as argX. Return values are stored in resX registers.
 | 
				
			||||||
 | 
					    Call(RoutineName, Vec<Rd>), | 
				
			||||||
 | 
					    /// Exit the current routine with return values
 | 
				
			||||||
 | 
					    Ret(Vec<Rd>), | 
				
			||||||
 | 
					    /// Mark a routine entry point (call target).
 | 
				
			||||||
 | 
					    /// Kept in the low level instruction file for position-independent code
 | 
				
			||||||
 | 
					    Routine(RoutineName), | 
				
			||||||
 | 
					    /// Skip backward or forward
 | 
				
			||||||
 | 
					    Skip(Rd), | 
				
			||||||
 | 
					    /// Skip if a flag is set
 | 
				
			||||||
 | 
					    SkipIf(Cond, Rd), | 
				
			||||||
 | 
					    /// Deny jumps, skips and run across this address, producing a run-time fault with a message.
 | 
				
			||||||
 | 
					    Barrier(Option<DebugMsg>), | 
				
			||||||
 | 
					    /// Generate a run-time fault with a debugger message
 | 
				
			||||||
 | 
					    Fault(Option<DebugMsg>), | 
				
			||||||
 | 
					    /// Copy value
 | 
				
			||||||
 | 
					    Move { dst: Wr, src: Rd }, | 
				
			||||||
 | 
					    /// Store runtime status to a register
 | 
				
			||||||
 | 
					    StoreStatus { dst: Wr }, | 
				
			||||||
 | 
					    /// Load runtime status from a register
 | 
				
			||||||
 | 
					    LoadStatus { src: Rd }, | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<BuiltinOp> for Op { | 
				
			||||||
 | 
					    fn from(bo: BuiltinOp) -> Self { | 
				
			||||||
 | 
					        Op::BuiltIn(bo) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,141 @@ | 
				
			|||||||
 | 
					use std::ops::Rem; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use num_traits::PrimInt; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::asm::instr::op::{OpTrait, EvalRes}; | 
				
			||||||
 | 
					use crate::runtime::fault::Fault; | 
				
			||||||
 | 
					use crate::runtime::frame::{CallStack, StackFrame}; | 
				
			||||||
 | 
					use crate::runtime::program::Program; | 
				
			||||||
 | 
					use crate::builtin::defs::BuiltinOp; | 
				
			||||||
 | 
					use crate::asm::data::literal::Addr; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl OpTrait for BuiltinOp { | 
				
			||||||
 | 
					    fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> { | 
				
			||||||
 | 
					        let mut res = EvalRes::default(); | 
				
			||||||
 | 
					        match self { | 
				
			||||||
 | 
					            BuiltinOp::Nop => {} | 
				
			||||||
 | 
					            BuiltinOp::Label(_) | BuiltinOp::FarLabel(_) | BuiltinOp::Routine(_) => { | 
				
			||||||
 | 
					                /* this is nop, but without any cost - just markers */ | 
				
			||||||
 | 
					                res.cycles = 0; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::Barrier(msg) => { | 
				
			||||||
 | 
					                return Err(Fault::Barrier { | 
				
			||||||
 | 
					                    msg: msg.clone().unwrap_or_else(|| "BARRIER".into()) | 
				
			||||||
 | 
					                }); | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::Fault(msg) => { | 
				
			||||||
 | 
					                return Err(Fault::FaultInstr { | 
				
			||||||
 | 
					                    msg: msg.clone().unwrap_or_else(|| "FAULT".into()) | 
				
			||||||
 | 
					                }); | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::FarJump(name) => { | 
				
			||||||
 | 
					                match program.find_far_label(name) { | 
				
			||||||
 | 
					                    Ok(pos) => { | 
				
			||||||
 | 
					                        frame.pc = pos; | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                    Err(e) => { | 
				
			||||||
 | 
					                        return Err(e); | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::Jump(name) => { | 
				
			||||||
 | 
					                match program.find_local_label(frame.pc, name) { | 
				
			||||||
 | 
					                    Ok(pos) => { | 
				
			||||||
 | 
					                        frame.pc = pos; | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                    Err(e) => { | 
				
			||||||
 | 
					                        return Err(e); | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::JumpIf(cond, name) => { | 
				
			||||||
 | 
					                if frame.status.test(*cond) { | 
				
			||||||
 | 
					                    match program.find_local_label(frame.pc, name) { | 
				
			||||||
 | 
					                        Ok(pos) => { | 
				
			||||||
 | 
					                            frame.pc = pos; | 
				
			||||||
 | 
					                        } | 
				
			||||||
 | 
					                        Err(e) => { | 
				
			||||||
 | 
					                            return Err(e); | 
				
			||||||
 | 
					                        } | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::FarJumpIf(cond, name) => { | 
				
			||||||
 | 
					                if frame.status.test(*cond) { | 
				
			||||||
 | 
					                    match program.find_far_label(name) { | 
				
			||||||
 | 
					                        Ok(pos) => { | 
				
			||||||
 | 
					                            frame.pc = pos; | 
				
			||||||
 | 
					                        } | 
				
			||||||
 | 
					                        Err(e) => { | 
				
			||||||
 | 
					                            return Err(e); | 
				
			||||||
 | 
					                        } | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::Call(name, args) => { | 
				
			||||||
 | 
					                match program.find_routine(&name) { | 
				
			||||||
 | 
					                    Ok(pos) => { | 
				
			||||||
 | 
					                        let mut values = Vec::with_capacity(args.len()); | 
				
			||||||
 | 
					                        for arg in args { | 
				
			||||||
 | 
					                            values.push(frame.read(*arg)?); | 
				
			||||||
 | 
					                        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        let mut frame2 = StackFrame::new(pos, &values); | 
				
			||||||
 | 
					                        std::mem::swap(frame, &mut frame2); | 
				
			||||||
 | 
					                        call_stack.push(frame2); | 
				
			||||||
 | 
					                        res.advance = 0; | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                    Err(e) => { | 
				
			||||||
 | 
					                        return Err(e); | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::Ret(retvals) => { | 
				
			||||||
 | 
					                match call_stack.pop() { | 
				
			||||||
 | 
					                    Some(previous) => { | 
				
			||||||
 | 
					                        let mut values = Vec::with_capacity(retvals.len()); | 
				
			||||||
 | 
					                        for arg in retvals { | 
				
			||||||
 | 
					                            values.push(frame.read(*arg)?); | 
				
			||||||
 | 
					                        } | 
				
			||||||
 | 
					                        *frame = previous; | 
				
			||||||
 | 
					                        frame.set_retvals(&values); | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                    None => { | 
				
			||||||
 | 
					                        return Err(Fault::CallStackUnderflow); | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::Skip(val) => { | 
				
			||||||
 | 
					                let steps = frame.read(*val)?; | 
				
			||||||
 | 
					                res.advance = i64::from_ne_bytes(steps.to_ne_bytes()); | 
				
			||||||
 | 
					                program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + res.advance) as u64))?; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::SkipIf(cond, val) => { | 
				
			||||||
 | 
					                if frame.status.test(*cond) { | 
				
			||||||
 | 
					                    debug!("Skipping"); | 
				
			||||||
 | 
					                    let steps = frame.read(*val)?; | 
				
			||||||
 | 
					                    res.advance = i64::from_ne_bytes(steps.to_ne_bytes()); | 
				
			||||||
 | 
					                    program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + res.advance) as u64))?; | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::Move { dst, src } => { | 
				
			||||||
 | 
					                frame.status.clear(); | 
				
			||||||
 | 
					                let val = frame.read(*src)?; | 
				
			||||||
 | 
					                frame.status.update(val); | 
				
			||||||
 | 
					                frame.write(*dst, val)?; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::StoreStatus { dst } => { | 
				
			||||||
 | 
					                let packed = frame.status.store(); | 
				
			||||||
 | 
					                frame.write(*dst, packed)?; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					            BuiltinOp::LoadStatus { src } => { | 
				
			||||||
 | 
					                let x = frame.read(*src)?; | 
				
			||||||
 | 
					                frame.status.load(x); | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(res) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,3 @@ | 
				
			|||||||
 | 
					pub mod defs; | 
				
			||||||
 | 
					pub mod exec; | 
				
			||||||
 | 
					pub mod parse; | 
				
			||||||
@ -0,0 +1,132 @@ | 
				
			|||||||
 | 
					use crate::asm::data::{Rd, Wr}; | 
				
			||||||
 | 
					use crate::asm::error::{Error}; | 
				
			||||||
 | 
					use crate::asm::instr::op::{AsmModule, ParseOpResult}; | 
				
			||||||
 | 
					use crate::asm::parse::arg_parser::ArgParser; | 
				
			||||||
 | 
					use crate::asm::data::literal::{Label, RoutineName}; | 
				
			||||||
 | 
					use crate::asm::parse::sexp_expect::expect_string_atom; | 
				
			||||||
 | 
					use crate::asm::parse::parse_data::{parse_label, parse_rd}; | 
				
			||||||
 | 
					use crate::asm::instr::cond::parse_cond; | 
				
			||||||
 | 
					use crate::asm::instr::Op; | 
				
			||||||
 | 
					use crate::builtin::defs::BuiltinOp; | 
				
			||||||
 | 
					use sexp::{Sexp, Atom}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)] | 
				
			||||||
 | 
					pub struct BuiltinOpParser { | 
				
			||||||
 | 
					    _internal: () | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl BuiltinOpParser { | 
				
			||||||
 | 
					    pub fn new() -> Box<dyn AsmModule> { | 
				
			||||||
 | 
					        Box::new(Self { | 
				
			||||||
 | 
					            _internal: () | 
				
			||||||
 | 
					        }) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl AsmModule for BuiltinOpParser { | 
				
			||||||
 | 
					    fn name(&self) -> &'static str { | 
				
			||||||
 | 
					        "builtin" | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> { | 
				
			||||||
 | 
					        Ok(ParseOpResult::Parsed(Op::BuiltIn(match keyword { | 
				
			||||||
 | 
					            "j" => { | 
				
			||||||
 | 
					                let dest = parse_label(args.next())?; | 
				
			||||||
 | 
					                BuiltinOp::Jump(dest) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "fj" => { | 
				
			||||||
 | 
					                let dest = parse_label(args.next())?; | 
				
			||||||
 | 
					                BuiltinOp::FarJump(dest) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "call" => { | 
				
			||||||
 | 
					                let dest = RoutineName(args.next_string()?); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let mut call_args = vec![]; | 
				
			||||||
 | 
					                for t in args { | 
				
			||||||
 | 
					                    call_args.push(parse_rd(Some(t))?); | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					                BuiltinOp::Call(dest, call_args) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "ret" => { | 
				
			||||||
 | 
					                let mut ret_vals = vec![]; | 
				
			||||||
 | 
					                for t in args { | 
				
			||||||
 | 
					                    ret_vals.push(parse_rd(Some(t))?); | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					                BuiltinOp::Ret(ret_vals) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "routine" => { | 
				
			||||||
 | 
					                let dest = RoutineName(args.next_string()?); | 
				
			||||||
 | 
					                BuiltinOp::Routine(dest) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "s" => { | 
				
			||||||
 | 
					                BuiltinOp::Skip(args.next_rd()?) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "sif" => { | 
				
			||||||
 | 
					                let cond = parse_cond(&args.next_string()?)?; | 
				
			||||||
 | 
					                let offs = args.next_rd()?; | 
				
			||||||
 | 
					                BuiltinOp::SkipIf(cond, offs) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "jif" => { | 
				
			||||||
 | 
					                let cond = parse_cond(&args.next_string()?)?; | 
				
			||||||
 | 
					                let dest = parse_label(args.next())?; | 
				
			||||||
 | 
					                BuiltinOp::JumpIf(cond, dest) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "fjif" => { | 
				
			||||||
 | 
					                let cond = parse_cond(&args.next_string()?)?; | 
				
			||||||
 | 
					                let dest = parse_label(args.next())?; | 
				
			||||||
 | 
					                BuiltinOp::FarJumpIf(cond, dest) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "barrier" => { | 
				
			||||||
 | 
					                BuiltinOp::Barrier(match args.next() { | 
				
			||||||
 | 
					                    None => None, | 
				
			||||||
 | 
					                    Some(s) => Some(expect_string_atom(Some(s))?.into()), | 
				
			||||||
 | 
					                }) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "fault" => { | 
				
			||||||
 | 
					                BuiltinOp::Fault(match args.next() { | 
				
			||||||
 | 
					                    None => None, | 
				
			||||||
 | 
					                    Some(s) => Some(expect_string_atom(Some(s))?.into()), | 
				
			||||||
 | 
					                }) | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "ld" => { | 
				
			||||||
 | 
					                BuiltinOp::Move { | 
				
			||||||
 | 
					                    dst: args.next_wr()?, | 
				
			||||||
 | 
					                    src: args.next_rd()?, | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "far" => { | 
				
			||||||
 | 
					                if let Some(Sexp::Atom(Atom::S(ref label))) = args.peek() { | 
				
			||||||
 | 
					                    if let Some(label) = label.strip_prefix(':') { | 
				
			||||||
 | 
					                        let label = Label::Named(label.to_string()); | 
				
			||||||
 | 
					                        BuiltinOp::FarLabel(label) | 
				
			||||||
 | 
					                    } else { | 
				
			||||||
 | 
					                        return Ok(ParseOpResult::Unknown(args)); | 
				
			||||||
 | 
					                    } | 
				
			||||||
 | 
					                } else { | 
				
			||||||
 | 
					                    return Ok(ParseOpResult::Unknown(args)); | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            other => { | 
				
			||||||
 | 
					                if let Some(label) = other.strip_prefix(':') { | 
				
			||||||
 | 
					                    let label = Label::Named(label.to_string()); | 
				
			||||||
 | 
					                    BuiltinOp::Label(label) | 
				
			||||||
 | 
					                } else { | 
				
			||||||
 | 
					                    return Ok(ParseOpResult::Unknown(args)); | 
				
			||||||
 | 
					                } | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					        }))) | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue