|
|
|
@ -6,6 +6,7 @@ use crate::asm::data::{ |
|
|
|
|
Rd, |
|
|
|
|
Wr, |
|
|
|
|
}; |
|
|
|
|
use crate::asm::data::literal::Addr; |
|
|
|
|
use crate::asm::error::Error; |
|
|
|
|
use crate::asm::instr::Cond; |
|
|
|
|
use crate::asm::parse::arg_parser::ArgParser; |
|
|
|
@ -15,22 +16,15 @@ use crate::runtime::program::Program; |
|
|
|
|
|
|
|
|
|
/// A higher level simple opration
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
pub enum OpWrapper { |
|
|
|
|
pub enum Op { |
|
|
|
|
/// 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), |
|
|
|
|
/// 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).
|
|
|
|
|
/// This label is preserved in optimized code.
|
|
|
|
|
FarLabel(Label), |
|
|
|
@ -58,23 +52,16 @@ pub enum Op { |
|
|
|
|
StoreStatus { dst: Wr }, |
|
|
|
|
/// Load runtime status from a register
|
|
|
|
|
LoadStatus { src: Rd }, |
|
|
|
|
|
|
|
|
|
/// Instruction added by an extension
|
|
|
|
|
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 { |
|
|
|
|
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 { |
|
|
|
|
Parsed(Box<dyn OpTrait + Send>), |
|
|
|
|
Parsed(Box<dyn OpTrait>), |
|
|
|
|
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.
|
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|