From 3e0aaa71e9a6f66bbe2f44a4e1b17acf4c91dd31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 26 Sep 2020 22:00:20 +0200 Subject: [PATCH] Convert builtin ops into a pseudo-extension --- crsn/src/asm/data/literal.rs | 2 +- crsn/src/asm/instr/flatten.rs | 57 +++++++- crsn/src/asm/instr/op.rs | 155 ++-------------------- crsn/src/asm/mod.rs | 7 + crsn/src/asm/parse/arg_parser.rs | 5 + crsn/src/asm/parse/parse_instr.rs | 12 +- crsn/src/asm/parse/parse_op.rs | 114 +++------------- crsn/src/builtin/defs.rs | 50 +++++++ crsn/src/builtin/exec.rs | 141 ++++++++++++++++++++ crsn/src/builtin/mod.rs | 3 + crsn/src/builtin/parse.rs | 132 ++++++++++++++++++ crsn/src/lib.rs | 1 + crsn/src/runtime/{exec/mod.rs => exec.rs} | 15 +-- crsn/src/runtime/frame.rs | 8 +- crsn/src/runtime/program.rs | 19 +-- crsn/src/runtime/run_thread.rs | 2 +- crsn_arith/src/parse.rs | 11 +- launcher/src/main.rs | 6 - 18 files changed, 442 insertions(+), 298 deletions(-) create mode 100644 crsn/src/builtin/defs.rs create mode 100644 crsn/src/builtin/exec.rs create mode 100644 crsn/src/builtin/mod.rs create mode 100644 crsn/src/builtin/parse.rs rename crsn/src/runtime/{exec/mod.rs => exec.rs} (66%) diff --git a/crsn/src/asm/data/literal.rs b/crsn/src/asm/data/literal.rs index 6d345a1..89d445a 100644 --- a/crsn/src/asm/data/literal.rs +++ b/crsn/src/asm/data/literal.rs @@ -38,7 +38,7 @@ impl Display for Addr { if self.0 > 0x7fff_ffff_ffff_ffff { write!(f, "{}", i64::from_ne_bytes(self.0.to_ne_bytes())) } else { - write!(f, "{:#010x}", self.0) + write!(f, "{}", self.0) } } } diff --git a/crsn/src/asm/instr/flatten.rs b/crsn/src/asm/instr/flatten.rs index 511af83..0ffe420 100644 --- a/crsn/src/asm/instr/flatten.rs +++ b/crsn/src/asm/instr/flatten.rs @@ -5,6 +5,7 @@ use crate::asm::data::{Rd, SrcDisp}; use crate::asm::data::literal::{Label, Value}; use crate::asm::error::{AsmError, Error}; use crate::asm::instr::{Cond, Instr, Op, Routine}; +use crate::builtin::defs::BuiltinOp; /// A trait for something that can turn into multiple instructions pub trait Flatten { @@ -29,18 +30,18 @@ impl Flatten for Instr { } else { Label::unique(label_num) }; - ops.push(Op::JumpIf(!cond, next_lbl.clone())); + ops.push(BuiltinOp::JumpIf(!cond, next_lbl.clone()).into()); for branch_instr in branch { ops.extend(branch_instr.flatten(label_num)?); } if cnt != branch_count - 1 { - ops.push(Op::Jump(end_lbl.clone())); - ops.push(Op::Label(next_lbl)); + ops.push(BuiltinOp::Jump(end_lbl.clone()).into()); + ops.push(BuiltinOp::Label(next_lbl).into()); } } - ops.push(Op::Label(end_lbl)); + ops.push(BuiltinOp::Label(end_lbl).into()); } Ok(ops) @@ -50,14 +51,56 @@ impl Flatten for Instr { impl Flatten for Routine { fn flatten(self, label_num: &AtomicU32) -> Result, Error> { let mut ops = vec![ - Op::Routine(self.name.clone()).into(), + BuiltinOp::Routine(self.name.clone()).into(), ]; for instr in self.body { ops.extend(instr.flatten(label_num)?); } - ops.push(Op::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())).into()); - Ok(ops) + ops.push(BuiltinOp::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())).into()); + + numbered_labels_to_skips(ops) + } +} + +/// Convert jumps to relative skips +fn numbered_labels_to_skips(ops: Vec) -> Result, Error> { + let mut label_positions = HashMap::::new(); + for (n, op) in ops.iter().enumerate() { + if let Op::BuiltIn(BuiltinOp::Label(name @ Label::Numbered(_))) = op { + label_positions.insert(name.clone(), n - label_positions.len()); + } + } + + let mut cleaned = vec![]; + let mut skipped = 0; + for (n, op) in ops.into_iter().enumerate() { + match op { + Op::BuiltIn(BuiltinOp::Label(Label::Numbered(_))) => { + skipped += 1; + } + Op::BuiltIn(BuiltinOp::Jump(target @ Label::Numbered(_))) => { + if let Some(dest) = label_positions.get(&target) { + let skip = *dest as isize - n as isize + skipped; + cleaned.push(Op::BuiltIn(BuiltinOp::Skip(Rd::new(SrcDisp::Immediate(skip as Value))))); + } else { + return Err(Error::Asm(AsmError::LabelNotDefined(target))); + } + } + Op::BuiltIn(BuiltinOp::JumpIf(cond, target @ Label::Numbered(_))) => { + if let Some(dest) = label_positions.get(&target) { + let skip = *dest as isize - n as isize + skipped; + cleaned.push(Op::BuiltIn(BuiltinOp::SkipIf(cond, Rd::new(SrcDisp::Immediate(skip as Value))))); + } else { + return Err(Error::Asm(AsmError::LabelNotDefined(target))); + } + } + other => { + cleaned.push(other); + } + } } + + Ok(cleaned) } diff --git a/crsn/src/asm/instr/op.rs b/crsn/src/asm/instr/op.rs index ae9213e..b3bf321 100644 --- a/crsn/src/asm/instr/op.rs +++ b/crsn/src/asm/instr/op.rs @@ -10,6 +10,7 @@ use crate::asm::data::literal::Addr; use crate::asm::error::Error; use crate::asm::instr::Cond; use crate::asm::parse::arg_parser::ArgParser; +use crate::builtin::defs::BuiltinOp; use crate::runtime::fault::Fault; use crate::runtime::frame::{CallStack, StackFrame}; use crate::runtime::program::Program; @@ -17,43 +18,9 @@ use crate::runtime::program::Program; /// A higher level simple opration #[derive(Debug)] 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), - /// 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), - /// Exit the current routine with return values - Ret(Vec), - /// 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), - /// Generate a run-time fault with a debugger message - Fault(Option), - /// 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 }, + BuiltIn(BuiltinOp), /// Instruction added by an extension - Extension(Box), + Ext(Box), } pub trait OpTrait: Debug + Send + Sync + 'static { @@ -61,7 +28,7 @@ pub trait OpTrait: Debug + Send + Sync + 'static { } pub enum ParseOpResult { - Parsed(Box), + Parsed(Op), Unknown(ArgParser), } @@ -98,119 +65,13 @@ impl Default for EvalRes { impl OpTrait for Op { fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result { - 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::BuiltIn(op) => { + op.execute(&program, call_stack, frame) } - 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)?; + Op::Ext(op) => { + op.execute(&program, call_stack, frame) } } - - Ok(res) } } diff --git a/crsn/src/asm/mod.rs b/crsn/src/asm/mod.rs index 2b69dea..0cb8966 100644 --- a/crsn/src/asm/mod.rs +++ b/crsn/src/asm/mod.rs @@ -13,5 +13,12 @@ pub mod patches; /// Parse a program from string and assemble a low level instruction sequence from it. pub fn assemble(source: &str, parsers: &[Box]) -> Result, error::Error> { let ops = parse::parse(source, parsers)?; + + trace!("--- Compiled program ---"); + for (n, op) in ops.iter().enumerate() { + trace!("{:04} : {:?}", n, op); + } + trace!("------------------------"); + Ok(Program::new(ops)) } diff --git a/crsn/src/asm/parse/arg_parser.rs b/crsn/src/asm/parse/arg_parser.rs index caf8680..1755a81 100644 --- a/crsn/src/asm/parse/arg_parser.rs +++ b/crsn/src/asm/parse/arg_parser.rs @@ -49,6 +49,11 @@ impl ArgParser { self.args.pop() } + /// Look at the next entry + pub fn peek(&mut self) -> Option<&Sexp> { + self.args.last() + } + /// Get the next string entry pub fn next_string(&mut self) -> anyhow::Result { Ok(expect_string_atom(self.next())?) diff --git a/crsn/src/asm/parse/parse_instr.rs b/crsn/src/asm/parse/parse_instr.rs index 8dd4b3e..d2f2ae2 100644 --- a/crsn/src/asm/parse/parse_instr.rs +++ b/crsn/src/asm/parse/parse_instr.rs @@ -16,15 +16,7 @@ pub fn parse_instructions(instrs: Vec, parsers: &[Box]) -> let tokens = expect_list(Some(expr), false)?; let mut toki = tokens.into_iter(); - - let mut name = expect_string_atom(toki.next())?; - - let far = if name == "far" { - name = expect_string_atom(toki.next())?; - true - } else { - false - }; + let name = expect_string_atom(toki.next())?; let arg_tokens = ArgParser::new(toki.clone().take_while(|e| e.is_atom()).collect()); let branch_tokens = toki @@ -44,7 +36,7 @@ pub fn parse_instructions(instrs: Vec, parsers: &[Box]) -> }; parsed.push(Instr { - op: parse_op(name.as_str(), far, arg_tokens, parsers)?, + op: parse_op(name.as_str(), arg_tokens, parsers)?, branches, }); } diff --git a/crsn/src/asm/parse/parse_op.rs b/crsn/src/asm/parse/parse_op.rs index 249da6b..0788315 100644 --- a/crsn/src/asm/parse/parse_op.rs +++ b/crsn/src/asm/parse/parse_op.rs @@ -6,104 +6,26 @@ use crate::asm::instr::op::{AsmModule, ParseOpResult}; use crate::asm::parse::arg_parser::ArgParser; use crate::asm::parse::parse_data::{parse_label, parse_rd}; use crate::asm::parse::sexp_expect::expect_string_atom; - -pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[Box]) -> Result { - Ok(match keyword { - "j" => { - let dest = parse_label(arg_tokens.next())?; - if far { - Op::FarJump(dest) - } else { - Op::Jump(dest) - } - } - - "call" => { - let dest = RoutineName(arg_tokens.next_string()?); - - let mut args = vec![]; - for t in arg_tokens { - args.push(parse_rd(Some(t))?); - } - Op::Call(dest, args) - } - - "ret" => { - let mut args = vec![]; - for t in arg_tokens { - args.push(parse_rd(Some(t))?); +use crate::builtin::parse::BuiltinOpParser; + +pub fn parse_op(keyword: &str, mut arg_tokens: ArgParser, parsers: &[Box]) -> Result { + // Include built-in instructions + let builtins = [BuiltinOpParser::new()]; + + for p in builtins.iter().chain(parsers) { + arg_tokens = match p.parse_op(keyword, arg_tokens) { + Ok(ParseOpResult::Parsed(op)) => return Ok(op), + Ok(ParseOpResult::Unknown(to_reuse)) => { + if to_reuse.parsing_started() { + panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword); + } + to_reuse } - Op::Ret(args) - } - - "routine" => { - let dest = RoutineName(arg_tokens.next_string()?); - Op::Routine(dest) - } - - "s" => { - Op::Skip(arg_tokens.next_rd()?) - } - - "sif" => { - let cond = parse_cond(&arg_tokens.next_string()?)?; - let offs = arg_tokens.next_rd()?; - Op::SkipIf(cond, offs) - } - - "jif" => { - let cond = parse_cond(&arg_tokens.next_string()?)?; - let dest = parse_label(arg_tokens.next())?; - Op::JumpIf(cond, dest) - } - - "barrier" => { - Op::Barrier(match arg_tokens.next() { - None => None, - Some(s) => Some(expect_string_atom(Some(s))?.into()), - }) - } - - "fault" => { - Op::Fault(match arg_tokens.next() { - None => None, - Some(s) => Some(expect_string_atom(Some(s))?.into()), - }) - } - - "ld" => { - Op::Move { - dst: arg_tokens.next_wr()?, - src: arg_tokens.next_rd()?, + Err(err) => { + return Err(err); } } + } - other => { - if let Some(label) = other.strip_prefix(':') { - let label = Label::Named(label.to_string()); - if far { - Op::FarLabel(label) - } else { - Op::Label(label) - } - } else { - for p in parsers { - arg_tokens = match p.parse_op(keyword, arg_tokens) { - Ok(ParseOpResult::Parsed(op)) => return Ok(Op::Extension(op)), - Ok(ParseOpResult::Unknown(to_reuse)) => { - if to_reuse.parsing_started() { - panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword); - } - to_reuse - } - Err(err) => { - return Err(err); - } - } - } - - return Err(Error::Parse(format!("Unknown instruction: {}", other).into())); - } - } - }) + return Err(Error::Parse(format!("Unknown instruction: {}", keyword).into())); } diff --git a/crsn/src/builtin/defs.rs b/crsn/src/builtin/defs.rs new file mode 100644 index 0000000..d2be813 --- /dev/null +++ b/crsn/src/builtin/defs.rs @@ -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), + /// Exit the current routine with return values + Ret(Vec), + /// 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), + /// Generate a run-time fault with a debugger message + Fault(Option), + /// 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 for Op { + fn from(bo: BuiltinOp) -> Self { + Op::BuiltIn(bo) + } +} diff --git a/crsn/src/builtin/exec.rs b/crsn/src/builtin/exec.rs new file mode 100644 index 0000000..495fc22 --- /dev/null +++ b/crsn/src/builtin/exec.rs @@ -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 { + 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) + } + // +} + diff --git a/crsn/src/builtin/mod.rs b/crsn/src/builtin/mod.rs new file mode 100644 index 0000000..e318438 --- /dev/null +++ b/crsn/src/builtin/mod.rs @@ -0,0 +1,3 @@ +pub mod defs; +pub mod exec; +pub mod parse; diff --git a/crsn/src/builtin/parse.rs b/crsn/src/builtin/parse.rs new file mode 100644 index 0000000..83360e1 --- /dev/null +++ b/crsn/src/builtin/parse.rs @@ -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 { + Box::new(Self { + _internal: () + }) + } +} + +impl AsmModule for BuiltinOpParser { + fn name(&self) -> &'static str { + "builtin" + } + + fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result { + 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)); + } + } + }))) + } +} diff --git a/crsn/src/lib.rs b/crsn/src/lib.rs index 7b3bc71..6b8b0e2 100644 --- a/crsn/src/lib.rs +++ b/crsn/src/lib.rs @@ -4,5 +4,6 @@ extern crate log; pub use sexp; pub mod asm; +pub mod builtin; pub mod runtime; diff --git a/crsn/src/runtime/exec/mod.rs b/crsn/src/runtime/exec.rs similarity index 66% rename from crsn/src/runtime/exec/mod.rs rename to crsn/src/runtime/exec.rs index 94914fc..bea9d3d 100644 --- a/crsn/src/runtime/exec/mod.rs +++ b/crsn/src/runtime/exec.rs @@ -8,24 +8,17 @@ use crate::runtime::run_thread::RunThread; impl RunThread { // TODO unit tests pub fn eval_op(&mut self) -> Result { - let mut cycles = 1; - let mut advance = 1; - let frame = &mut self.frame; let op = self.program.read(frame.pc); - debug!("------------------------"); - debug!("{} | {:?}", frame.pc, op); + trace!("### {:04} : {:?}", frame.pc.0, op); /* Operations can be given different execution times when run in slow mode. */ /* Presently, all that do anything use 1 cycle. */ - op.execute(&self.program, &mut self.call_stack, frame)?; - - Ok(EvalRes { - cycles, - advance, - }) + let rv = op.execute(&self.program, &mut self.call_stack, frame); + trace!("-> {:?}", rv); + rv } } diff --git a/crsn/src/runtime/frame.rs b/crsn/src/runtime/frame.rs index 67680c3..9e9c7cf 100644 --- a/crsn/src/runtime/frame.rs +++ b/crsn/src/runtime/frame.rs @@ -52,7 +52,7 @@ impl StackFrame { if rn >= REG_COUNT as u8 { Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490 } else { - debug!("Rd {:?} = {}", rd, self.res[rn as usize]); + trace!("Rd {:?} = {}", rd, self.res[rn as usize]); Ok(self.res[rn as usize]) } } @@ -60,7 +60,7 @@ impl StackFrame { if rn >= REG_COUNT as u8 { Err(Fault::RegisterNotExist { reg: Register::Arg(rn) }) } else { - debug!("Rd {:?} = {}", rd, self.arg[rn as usize]); + trace!("Rd {:?} = {}", rd, self.arg[rn as usize]); Ok(self.arg[rn as usize]) } } @@ -68,7 +68,7 @@ impl StackFrame { if rn >= REG_COUNT as u8 { Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) } else { - debug!("Rd {:?} = {}", rd, self.gen[rn as usize]); + trace!("Rd {:?} = {}", rd, self.gen[rn as usize]); Ok(self.gen[rn as usize]) } } @@ -79,7 +79,7 @@ impl StackFrame { } pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> { - debug!("WR {:?} := {}", wr, val); + trace!("WR {:?} := {}", wr, val); match wr.d() { DstDisp::ImmediatePtr(_) => { diff --git a/crsn/src/runtime/program.rs b/crsn/src/runtime/program.rs index 6b756d1..09e7bb5 100644 --- a/crsn/src/runtime/program.rs +++ b/crsn/src/runtime/program.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use crate::asm::data::literal::{Addr, Label, RoutineName}; use crate::asm::instr::Op; use crate::runtime::fault::Fault; +use crate::builtin::defs::BuiltinOp; #[derive(Debug)] pub struct Program { @@ -29,13 +30,13 @@ impl Program { fn scan(&mut self) { for (pos, op) in self.ops.iter().enumerate() { match op { - Op::FarLabel(name) => { + Op::BuiltIn(BuiltinOp::FarLabel(name)) => { self.far_labels.insert(name.clone(), pos.into()); } - Op::Routine(name) => { + Op::BuiltIn(BuiltinOp::Routine(name)) => { self.routines.insert(name.clone(), pos.into()); } - Op::Barrier(_) => { + Op::BuiltIn(BuiltinOp::Barrier(_)) => { self.barriers.push(pos.into()); } _ => {} @@ -46,7 +47,7 @@ impl Program { /// Read a program instruction at address pub fn read(&self, addr: Addr) -> &Op { if addr.0 >= self.ops.len() as u64 { - &Op::Nop + &Op::BuiltIn(BuiltinOp::Nop) } else { &self.ops[addr.0 as usize] } @@ -60,7 +61,7 @@ impl Program { for b in &self.barriers { if *b >= from && *b <= to { - if let Op::Barrier(msg) = self.read(*b) { + if let Op::BuiltIn(BuiltinOp::Barrier(msg)) = self.read(*b) { return Err(Fault::JumpThroughBarrier { msg: msg.clone().unwrap_or("No msg".into()) }); @@ -91,10 +92,10 @@ impl Program { for at in (0..=pc.0).rev() { match &self.ops[at as usize] { - Op::Label(lbl) if lbl == name => { + Op::BuiltIn(BuiltinOp::Label(lbl)) if lbl == name => { return Ok(at.into()); } - Op::Barrier(_) => { + Op::BuiltIn(BuiltinOp::Barrier(_)) => { break; } _ => {} @@ -103,10 +104,10 @@ impl Program { for at in pc.0..(self.ops.len() as u64) { match &self.ops[at as usize] { - Op::Label(lbl) if lbl == name => { + Op::BuiltIn(BuiltinOp::Label(lbl)) if lbl == name => { return Ok(at.into()); } - Op::Barrier(_) => { + Op::BuiltIn(BuiltinOp::Barrier(_)) => { break; } _ => {} diff --git a/crsn/src/runtime/run_thread.rs b/crsn/src/runtime/run_thread.rs index 8945375..8d50d49 100644 --- a/crsn/src/runtime/run_thread.rs +++ b/crsn/src/runtime/run_thread.rs @@ -54,7 +54,7 @@ impl RunThread { cycles, advance }) => { std::thread::sleep(CYCLE_TIME * (cycles as u32)); - debug!("Step {}; Status = {}", advance, self.frame.status); + trace!("Step {}; Status = {}", advance, self.frame.status); self.frame.pc.advance(advance); } Err(e) => { diff --git a/crsn_arith/src/parse.rs b/crsn_arith/src/parse.rs index 70d80bd..b42404d 100644 --- a/crsn_arith/src/parse.rs +++ b/crsn_arith/src/parse.rs @@ -1,11 +1,10 @@ use crsn::asm::data::{Rd, Wr}; -use crsn::asm::error::{Error}; +use crsn::asm::error::Error; use crsn::asm::instr::op::{AsmModule, ParseOpResult}; - - +use crsn::asm::instr::Op; +use crsn::asm::parse::arg_parser::ArgParser; use crate::defs::ArithOp; -use crsn::asm::parse::arg_parser::ArgParser; #[derive(Debug, Clone)] pub struct ArithOpParser { @@ -26,7 +25,7 @@ impl AsmModule for ArithOpParser { } fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result { - Ok(ParseOpResult::Parsed(Box::new(match keyword { + Ok(ParseOpResult::Parsed(Op::Ext(Box::new(match keyword { "cmp" => { ArithOp::Compare { a: args.next_rd()?, @@ -451,6 +450,6 @@ impl AsmModule for ArithOpParser { _other => { return Ok(ParseOpResult::Unknown(args)); } - }))) + })))) } } diff --git a/launcher/src/main.rs b/launcher/src/main.rs index 9178ff6..518e0c2 100644 --- a/launcher/src/main.rs +++ b/launcher/src/main.rs @@ -71,12 +71,6 @@ fn main() { let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap(); - debug!("---"); - for op in &parsed.ops { - debug!("{:?}", op); - } - debug!("---"); - let thread = RunThread::new(ThreadToken(0), parsed, Addr(0), &[]); thread.start().join().unwrap();