|  |  | @ -6,6 +6,7 @@ use crate::asm::data::{ | 
			
		
	
		
		
			
				
					
					|  |  |  |     Rd, |  |  |  |     Rd, | 
			
		
	
		
		
			
				
					
					|  |  |  |     Wr, |  |  |  |     Wr, | 
			
		
	
		
		
			
				
					
					|  |  |  | }; |  |  |  | }; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | use crate::asm::data::literal::Addr; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::asm::error::Error; |  |  |  | use crate::asm::error::Error; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::asm::instr::Cond; |  |  |  | use crate::asm::instr::Cond; | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::asm::parse::arg_parser::ArgParser; |  |  |  | use crate::asm::parse::arg_parser::ArgParser; | 
			
		
	
	
		
		
			
				
					|  |  | @ -15,22 +16,15 @@ use crate::runtime::program::Program; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /// A higher level simple opration
 |  |  |  | /// A higher level simple opration
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[derive(Debug)] |  |  |  | #[derive(Debug)] | 
			
		
	
		
		
			
				
					
					|  |  |  | pub enum OpWrapper { |  |  |  | pub enum Op { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     /// Do nothing
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     Nop, | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Mark a jump target.
 |  |  |  |     /// Mark a jump target.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     Label(Label), |  |  |  |     Label(Label), | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Jump to a label
 |  |  |  |     /// Jump to a label
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     Jump(Label), |  |  |  |     Jump(Label), | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Jump to a label if a flag is set
 |  |  |  |     /// Jump to a label if a flag is set
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     JumpIf(Cond, Label), |  |  |  |     JumpIf(Cond, Label), | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Low level op
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     Op(Op), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | /// A low level instruction
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | #[derive(Debug)] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | pub enum Op { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Do nothing
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     Nop, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Mark a far jump target (can be jumped to from another routine).
 |  |  |  |     /// Mark a far jump target (can be jumped to from another routine).
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// This label is preserved in optimized code.
 |  |  |  |     /// This label is preserved in optimized code.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     FarLabel(Label), |  |  |  |     FarLabel(Label), | 
			
		
	
	
		
		
			
				
					|  |  | @ -58,23 +52,16 @@ pub enum Op { | 
			
		
	
		
		
			
				
					
					|  |  |  |     StoreStatus { dst: Wr }, |  |  |  |     StoreStatus { dst: Wr }, | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Load runtime status from a register
 |  |  |  |     /// Load runtime status from a register
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     LoadStatus { src: Rd }, |  |  |  |     LoadStatus { src: Rd }, | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |     /// Instruction added by an extension
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     Extension(Box<dyn OpTrait>), |  |  |  |     Extension(Box<dyn OpTrait>), | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /// Make "into" work
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | impl From<Op> for OpWrapper { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     fn from(op: Op) -> Self { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         OpWrapper::Op(op) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | pub trait OpTrait: Debug + Send + Sync + 'static { |  |  |  | pub trait OpTrait: Debug + Send + Sync + 'static { | 
			
		
	
		
		
			
				
					
					|  |  |  |     fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<(), Fault>; |  |  |  |     fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault>; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | pub enum ParseOpResult { |  |  |  | pub enum ParseOpResult { | 
			
		
	
		
		
			
				
					
					|  |  |  |     Parsed(Box<dyn OpTrait + Send>), |  |  |  |     Parsed(Box<dyn OpTrait>), | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     Unknown(ArgParser), |  |  |  |     Unknown(ArgParser), | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -89,3 +76,141 @@ pub trait AsmModule: Debug + Send + 'static { | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
 |  |  |  |     /// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result<ParseOpResult, Error>; |  |  |  |     fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result<ParseOpResult, Error>; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | pub type CyclesSpent = usize; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #[derive(Debug)] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | pub struct EvalRes { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     pub cycles: CyclesSpent, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     pub advance: i64, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | impl Default for EvalRes { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     fn default() -> Self { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         Self { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             cycles: 1, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             advance: 1, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | impl OpTrait for Op { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let mut res = EvalRes::default(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         match self { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::Nop => {} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::Label(_) | Op::FarLabel(_) | Op::Routine(_) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 /* this is nop, but without any cost - just markers */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 res.cycles = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::Barrier(msg) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 return Err(Fault::Barrier { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     msg: msg.clone().unwrap_or_else(|| "BARRIER".into()) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::Fault(msg) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 return Err(Fault::FaultInstr { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     msg: msg.clone().unwrap_or_else(|| "FAULT".into()) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::FarJump(name) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 match program.find_far_label(name) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     Ok(pos) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         frame.pc = pos; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     Err(e) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         return Err(e); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::Jump(name) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 match program.find_local_label(frame.pc, name) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     Ok(pos) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         frame.pc = pos; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     Err(e) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         return Err(e); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::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); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::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); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::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); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::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))?; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::SkipIf(cond, val) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if frame.status.test(*cond) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     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))?; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::Move { dst, src } => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 frame.status.clear(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 let val = frame.read(*src)?; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 frame.status.update(val); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 frame.write(*dst, val)?; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::StoreStatus { dst } => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 let packed = frame.status.store(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 frame.write(*dst, packed)?; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::LoadStatus { src } => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 let x = frame.read(*src)?; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 frame.status.load(x); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Op::Extension(xop) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 xop.execute(&program, call_stack, frame)?; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         Ok(res) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |