Convert builtin ops into a pseudo-extension

floats
Ondřej Hruška 4 years ago
parent 1d444fd516
commit 3e0aaa71e9
Signed by untrusted user: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      crsn/src/asm/data/literal.rs
  2. 57
      crsn/src/asm/instr/flatten.rs
  3. 155
      crsn/src/asm/instr/op.rs
  4. 7
      crsn/src/asm/mod.rs
  5. 5
      crsn/src/asm/parse/arg_parser.rs
  6. 12
      crsn/src/asm/parse/parse_instr.rs
  7. 92
      crsn/src/asm/parse/parse_op.rs
  8. 50
      crsn/src/builtin/defs.rs
  9. 141
      crsn/src/builtin/exec.rs
  10. 3
      crsn/src/builtin/mod.rs
  11. 132
      crsn/src/builtin/parse.rs
  12. 1
      crsn/src/lib.rs
  13. 15
      crsn/src/runtime/exec.rs
  14. 8
      crsn/src/runtime/frame.rs
  15. 19
      crsn/src/runtime/program.rs
  16. 2
      crsn/src/runtime/run_thread.rs
  17. 11
      crsn_arith/src/parse.rs
  18. 6
      launcher/src/main.rs

@ -38,7 +38,7 @@ impl Display for Addr {
if self.0 > 0x7fff_ffff_ffff_ffff { if self.0 > 0x7fff_ffff_ffff_ffff {
write!(f, "{}", i64::from_ne_bytes(self.0.to_ne_bytes())) write!(f, "{}", i64::from_ne_bytes(self.0.to_ne_bytes()))
} else { } else {
write!(f, "{:#010x}", self.0) write!(f, "{}", self.0)
} }
} }
} }

@ -5,6 +5,7 @@ use crate::asm::data::{Rd, SrcDisp};
use crate::asm::data::literal::{Label, Value}; use crate::asm::data::literal::{Label, Value};
use crate::asm::error::{AsmError, Error}; use crate::asm::error::{AsmError, Error};
use crate::asm::instr::{Cond, Instr, Op, Routine}; use crate::asm::instr::{Cond, Instr, Op, Routine};
use crate::builtin::defs::BuiltinOp;
/// A trait for something that can turn into multiple instructions /// A trait for something that can turn into multiple instructions
pub trait Flatten { pub trait Flatten {
@ -29,18 +30,18 @@ impl Flatten for Instr {
} else { } else {
Label::unique(label_num) 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 { for branch_instr in branch {
ops.extend(branch_instr.flatten(label_num)?); ops.extend(branch_instr.flatten(label_num)?);
} }
if cnt != branch_count - 1 { if cnt != branch_count - 1 {
ops.push(Op::Jump(end_lbl.clone())); ops.push(BuiltinOp::Jump(end_lbl.clone()).into());
ops.push(Op::Label(next_lbl)); ops.push(BuiltinOp::Label(next_lbl).into());
} }
} }
ops.push(Op::Label(end_lbl)); ops.push(BuiltinOp::Label(end_lbl).into());
} }
Ok(ops) Ok(ops)
@ -50,14 +51,56 @@ impl Flatten for Instr {
impl Flatten for Routine { impl Flatten for Routine {
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> { fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
let mut ops = vec![ let mut ops = vec![
Op::Routine(self.name.clone()).into(), BuiltinOp::Routine(self.name.clone()).into(),
]; ];
for instr in self.body { for instr in self.body {
ops.extend(instr.flatten(label_num)?); ops.extend(instr.flatten(label_num)?);
} }
ops.push(Op::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())).into()); ops.push(BuiltinOp::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())).into());
Ok(ops)
numbered_labels_to_skips(ops)
}
}
/// Convert jumps to relative skips
fn numbered_labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
let mut label_positions = HashMap::<Label, usize>::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)
} }

@ -10,6 +10,7 @@ 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;
use crate::builtin::defs::BuiltinOp;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::frame::{CallStack, StackFrame}; use crate::runtime::frame::{CallStack, StackFrame};
use crate::runtime::program::Program; use crate::runtime::program::Program;
@ -17,43 +18,9 @@ use crate::runtime::program::Program;
/// A higher level simple opration /// A higher level simple opration
#[derive(Debug)] #[derive(Debug)]
pub enum Op { pub enum Op {
/// Do nothing BuiltIn(BuiltinOp),
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<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 },
/// Instruction added by an extension /// Instruction added by an extension
Extension(Box<dyn OpTrait>), Ext(Box<dyn OpTrait>),
} }
pub trait OpTrait: Debug + Send + Sync + 'static { pub trait OpTrait: Debug + Send + Sync + 'static {
@ -61,7 +28,7 @@ pub trait OpTrait: Debug + Send + Sync + 'static {
} }
pub enum ParseOpResult { pub enum ParseOpResult {
Parsed(Box<dyn OpTrait>), Parsed(Op),
Unknown(ArgParser), Unknown(ArgParser),
} }
@ -98,119 +65,13 @@ impl Default for EvalRes {
impl OpTrait for Op { impl OpTrait for Op {
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> { fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> {
let mut res = EvalRes::default();
match self { match self {
Op::Nop => {} Op::BuiltIn(op) => {
Op::Label(_) | Op::FarLabel(_) | Op::Routine(_) => { op.execute(&program, call_stack, frame)
/* this is nop, but without any cost - just markers */
res.cycles = 0;
} }
Op::Barrier(msg) => { Op::Ext(op) => {
return Err(Fault::Barrier { op.execute(&program, call_stack, frame)
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)
} }
} }

@ -13,5 +13,12 @@ pub mod patches;
/// Parse a program from string and assemble a low level instruction sequence from it. /// Parse a program from string and assemble a low level instruction sequence from it.
pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Arc<Program>, error::Error> { pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Arc<Program>, error::Error> {
let ops = parse::parse(source, parsers)?; 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)) Ok(Program::new(ops))
} }

@ -49,6 +49,11 @@ impl ArgParser {
self.args.pop() self.args.pop()
} }
/// Look at the next entry
pub fn peek(&mut self) -> Option<&Sexp> {
self.args.last()
}
/// Get the next string entry /// Get the next string entry
pub fn next_string(&mut self) -> anyhow::Result<String> { pub fn next_string(&mut self) -> anyhow::Result<String> {
Ok(expect_string_atom(self.next())?) Ok(expect_string_atom(self.next())?)

@ -16,15 +16,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn AsmModule>]) ->
let tokens = expect_list(Some(expr), false)?; let tokens = expect_list(Some(expr), false)?;
let mut toki = tokens.into_iter(); let mut toki = tokens.into_iter();
let name = expect_string_atom(toki.next())?;
let mut name = expect_string_atom(toki.next())?;
let far = if name == "far" {
name = expect_string_atom(toki.next())?;
true
} else {
false
};
let arg_tokens = ArgParser::new(toki.clone().take_while(|e| e.is_atom()).collect()); let arg_tokens = ArgParser::new(toki.clone().take_while(|e| e.is_atom()).collect());
let branch_tokens = toki let branch_tokens = toki
@ -44,7 +36,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn AsmModule>]) ->
}; };
parsed.push(Instr { parsed.push(Instr {
op: parse_op(name.as_str(), far, arg_tokens, parsers)?, op: parse_op(name.as_str(), arg_tokens, parsers)?,
branches, branches,
}); });
} }

@ -6,90 +6,15 @@ use crate::asm::instr::op::{AsmModule, ParseOpResult};
use crate::asm::parse::arg_parser::ArgParser; use crate::asm::parse::arg_parser::ArgParser;
use crate::asm::parse::parse_data::{parse_label, parse_rd}; use crate::asm::parse::parse_data::{parse_label, parse_rd};
use crate::asm::parse::sexp_expect::expect_string_atom; use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::builtin::parse::BuiltinOpParser;
pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[Box<dyn AsmModule>]) -> Result<Op, Error> { pub fn parse_op(keyword: &str, mut arg_tokens: ArgParser, parsers: &[Box<dyn AsmModule>]) -> Result<Op, Error> {
Ok(match keyword { // Include built-in instructions
"j" => { let builtins = [BuiltinOpParser::new()];
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))?);
}
Op::Ret(args)
}
"routine" => {
let dest = RoutineName(arg_tokens.next_string()?);
Op::Routine(dest)
}
"s" => { for p in builtins.iter().chain(parsers) {
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()?,
}
}
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) { arg_tokens = match p.parse_op(keyword, arg_tokens) {
Ok(ParseOpResult::Parsed(op)) => return Ok(Op::Extension(op)), Ok(ParseOpResult::Parsed(op)) => return Ok(op),
Ok(ParseOpResult::Unknown(to_reuse)) => { Ok(ParseOpResult::Unknown(to_reuse)) => {
if to_reuse.parsing_started() { if to_reuse.parsing_started() {
panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword); panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword);
@ -102,8 +27,5 @@ pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[
} }
} }
return Err(Error::Parse(format!("Unknown instruction: {}", other).into())); return Err(Error::Parse(format!("Unknown instruction: {}", keyword).into()));
}
}
})
} }

@ -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));
}
}
})))
}
}

@ -4,5 +4,6 @@ extern crate log;
pub use sexp; pub use sexp;
pub mod asm; pub mod asm;
pub mod builtin;
pub mod runtime; pub mod runtime;

@ -8,24 +8,17 @@ use crate::runtime::run_thread::RunThread;
impl RunThread { impl RunThread {
// TODO unit tests // TODO unit tests
pub fn eval_op(&mut self) -> Result<EvalRes, Fault> { pub fn eval_op(&mut self) -> Result<EvalRes, Fault> {
let mut cycles = 1;
let mut advance = 1;
let frame = &mut self.frame; let frame = &mut self.frame;
let op = self.program.read(frame.pc); let op = self.program.read(frame.pc);
debug!("------------------------"); trace!("### {:04} : {:?}", frame.pc.0, op);
debug!("{} | {:?}", frame.pc, op);
/* Operations can be given different execution times when run in slow mode. */ /* Operations can be given different execution times when run in slow mode. */
/* Presently, all that do anything use 1 cycle. */ /* Presently, all that do anything use 1 cycle. */
op.execute(&self.program, &mut self.call_stack, frame)?; let rv = op.execute(&self.program, &mut self.call_stack, frame);
trace!("-> {:?}", rv);
Ok(EvalRes { rv
cycles,
advance,
})
} }
} }

@ -52,7 +52,7 @@ impl StackFrame {
if rn >= REG_COUNT as u8 { 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 Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
} else { } else {
debug!("Rd {:?} = {}", rd, self.res[rn as usize]); trace!("Rd {:?} = {}", rd, self.res[rn as usize]);
Ok(self.res[rn as usize]) Ok(self.res[rn as usize])
} }
} }
@ -60,7 +60,7 @@ impl StackFrame {
if rn >= REG_COUNT as u8 { if rn >= REG_COUNT as u8 {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) }) Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
} else { } else {
debug!("Rd {:?} = {}", rd, self.arg[rn as usize]); trace!("Rd {:?} = {}", rd, self.arg[rn as usize]);
Ok(self.arg[rn as usize]) Ok(self.arg[rn as usize])
} }
} }
@ -68,7 +68,7 @@ impl StackFrame {
if rn >= REG_COUNT as u8 { if rn >= REG_COUNT as u8 {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) }) Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
} else { } else {
debug!("Rd {:?} = {}", rd, self.gen[rn as usize]); trace!("Rd {:?} = {}", rd, self.gen[rn as usize]);
Ok(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> { pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> {
debug!("WR {:?} := {}", wr, val); trace!("WR {:?} := {}", wr, val);
match wr.d() { match wr.d() {
DstDisp::ImmediatePtr(_) => { DstDisp::ImmediatePtr(_) => {

@ -4,6 +4,7 @@ use std::sync::Arc;
use crate::asm::data::literal::{Addr, Label, RoutineName}; use crate::asm::data::literal::{Addr, Label, RoutineName};
use crate::asm::instr::Op; use crate::asm::instr::Op;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::builtin::defs::BuiltinOp;
#[derive(Debug)] #[derive(Debug)]
pub struct Program { pub struct Program {
@ -29,13 +30,13 @@ impl Program {
fn scan(&mut self) { fn scan(&mut self) {
for (pos, op) in self.ops.iter().enumerate() { for (pos, op) in self.ops.iter().enumerate() {
match op { match op {
Op::FarLabel(name) => { Op::BuiltIn(BuiltinOp::FarLabel(name)) => {
self.far_labels.insert(name.clone(), pos.into()); self.far_labels.insert(name.clone(), pos.into());
} }
Op::Routine(name) => { Op::BuiltIn(BuiltinOp::Routine(name)) => {
self.routines.insert(name.clone(), pos.into()); self.routines.insert(name.clone(), pos.into());
} }
Op::Barrier(_) => { Op::BuiltIn(BuiltinOp::Barrier(_)) => {
self.barriers.push(pos.into()); self.barriers.push(pos.into());
} }
_ => {} _ => {}
@ -46,7 +47,7 @@ impl Program {
/// Read a program instruction at address /// Read a program instruction at address
pub fn read(&self, addr: Addr) -> &Op { pub fn read(&self, addr: Addr) -> &Op {
if addr.0 >= self.ops.len() as u64 { if addr.0 >= self.ops.len() as u64 {
&Op::Nop &Op::BuiltIn(BuiltinOp::Nop)
} else { } else {
&self.ops[addr.0 as usize] &self.ops[addr.0 as usize]
} }
@ -60,7 +61,7 @@ impl Program {
for b in &self.barriers { for b in &self.barriers {
if *b >= from && *b <= to { 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 { return Err(Fault::JumpThroughBarrier {
msg: msg.clone().unwrap_or("No msg".into()) msg: msg.clone().unwrap_or("No msg".into())
}); });
@ -91,10 +92,10 @@ impl Program {
for at in (0..=pc.0).rev() { for at in (0..=pc.0).rev() {
match &self.ops[at as usize] { match &self.ops[at as usize] {
Op::Label(lbl) if lbl == name => { Op::BuiltIn(BuiltinOp::Label(lbl)) if lbl == name => {
return Ok(at.into()); return Ok(at.into());
} }
Op::Barrier(_) => { Op::BuiltIn(BuiltinOp::Barrier(_)) => {
break; break;
} }
_ => {} _ => {}
@ -103,10 +104,10 @@ impl Program {
for at in pc.0..(self.ops.len() as u64) { for at in pc.0..(self.ops.len() as u64) {
match &self.ops[at as usize] { match &self.ops[at as usize] {
Op::Label(lbl) if lbl == name => { Op::BuiltIn(BuiltinOp::Label(lbl)) if lbl == name => {
return Ok(at.into()); return Ok(at.into());
} }
Op::Barrier(_) => { Op::BuiltIn(BuiltinOp::Barrier(_)) => {
break; break;
} }
_ => {} _ => {}

@ -54,7 +54,7 @@ impl RunThread {
cycles, advance cycles, advance
}) => { }) => {
std::thread::sleep(CYCLE_TIME * (cycles as u32)); 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); self.frame.pc.advance(advance);
} }
Err(e) => { Err(e) => {

@ -1,11 +1,10 @@
use crsn::asm::data::{Rd, Wr}; 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::{AsmModule, ParseOpResult};
use crsn::asm::instr::Op;
use crsn::asm::parse::arg_parser::ArgParser;
use crate::defs::ArithOp; use crate::defs::ArithOp;
use crsn::asm::parse::arg_parser::ArgParser;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ArithOpParser { pub struct ArithOpParser {
@ -26,7 +25,7 @@ impl AsmModule for ArithOpParser {
} }
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> { fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> {
Ok(ParseOpResult::Parsed(Box::new(match keyword { Ok(ParseOpResult::Parsed(Op::Ext(Box::new(match keyword {
"cmp" => { "cmp" => {
ArithOp::Compare { ArithOp::Compare {
a: args.next_rd()?, a: args.next_rd()?,
@ -451,6 +450,6 @@ impl AsmModule for ArithOpParser {
_other => { _other => {
return Ok(ParseOpResult::Unknown(args)); return Ok(ParseOpResult::Unknown(args));
} }
}))) }))))
} }
} }

@ -71,12 +71,6 @@ fn main() {
let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap(); 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), &[]); let thread = RunThread::new(ThreadToken(0), parsed, Addr(0), &[]);
thread.start().join().unwrap(); thread.start().join().unwrap();

Loading…
Cancel
Save