cleanup. remove conditional jumps, replaced by condition embedded in the enum

pull/21/head
Ondřej Hruška 4 years ago
parent 810ed2dddc
commit 986f3be6a2
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 1
      _stash/README.txt
  2. 0
      _stash/mlock.rs
  3. 0
      _stash/span.rs
  4. 0
      _stash/sparse.rs
  5. 6
      crsn/src/asm/data/reg.rs
  6. 2
      crsn/src/asm/error.rs
  7. 58
      crsn/src/asm/instr/flatten.rs
  8. 2
      crsn/src/asm/instr/mod.rs
  9. 24
      crsn/src/asm/instr/op.rs
  10. 6
      crsn/src/asm/mod.rs
  11. 14
      crsn/src/asm/parse/parse_data.rs
  12. 9
      crsn/src/asm/parse/parse_instr.rs
  13. 14
      crsn/src/asm/parse/parse_op.rs
  14. 12
      crsn/src/asm/parse/parse_routine.rs
  15. 24
      crsn/src/builtin/defs.rs
  16. 48
      crsn/src/builtin/exec.rs
  17. 37
      crsn/src/builtin/parse.rs
  18. 9
      crsn/src/module/mod.rs
  19. 2
      crsn/src/runtime/mod.rs
  20. 27
      crsn/src/runtime/program.rs
  21. 4
      crsn_arith/src/lib.rs
  22. 4
      crsn_arith/src/parse.rs
  23. 4
      crsn_screen/src/lib.rs
  24. 4
      crsn_screen/src/parse.rs
  25. 4
      crsn_stacks/src/lib.rs
  26. 4
      crsn_stacks/src/parse.rs
  27. 27
      launcher/src/main.rs
  28. 3
      launcher/src/serde_duration_millis.rs

@ -0,0 +1 @@
Files in this folder were developed for crsn but are not currently used by core or any extension.

@ -26,19 +26,19 @@ impl Display for Register {
pub fn parse_reg(name: &str) -> anyhow::Result<Register> {
// TODO deduplicate code
if let Some(rn) = name.strip_prefix("arg") {
if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
}
let val: u8 = rn.parse()?;
Ok(Register::Arg(val))
} else if let Some(rn) = name.strip_prefix("res") {
if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
}
let val: u8 = rn.parse()?;
Ok(Register::Res(val))
} else if let Some(rn) = name.strip_prefix("r") {
if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
}
let val: u8 = rn.parse()?;

@ -1,11 +1,11 @@
use std::borrow::Cow;
use std::num::ParseIntError;
use thiserror::Error;
use crate::asm::data::{Mask, Register};
use crate::asm::data::literal::Label;
use crate::asm::instr::Cond;
use std::num::ParseIntError;
/// csn_asm unified error type
#[derive(Error, Debug)]

@ -4,9 +4,10 @@ use std::sync::atomic::{AtomicU32, Ordering};
use crate::asm::data::{Rd, RdData};
use crate::asm::data::literal::{Label, Value};
use crate::asm::error::{AsmError, CrsnError};
use crate::asm::instr::{Cond, Instr, Op, Routine};
use crate::builtin::defs::BuiltinOp;
use crate::asm::instr::{Cond, InstrWithBranches, Op, Routine};
use crate::asm::instr::op::OpKind;
use crate::builtin::defs::Barrier;
use crate::builtin::defs::BuiltinOp;
/// A trait for something that can turn into multiple instructions
pub trait Flatten {
@ -19,7 +20,7 @@ impl Flatten for () {
}
}
impl Flatten for Instr {
impl Flatten for InstrWithBranches {
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
let mut ops = vec![self.op];
@ -37,8 +38,21 @@ impl Flatten for Instr {
} else {
Label::unique(label_num)
};
ops.push(BuiltinOp::JumpIf(!cond, next_lbl.clone()).into());
ops.extend(branch.flatten(label_num)?);
let mut flattened = branch.flatten(label_num)?;
if flattened.len() == 0 {
ops.push(Op { cond: Some(cond), kind: BuiltinOp::Jump(end_lbl.clone()).into() });
} else if flattened.len() == 1 && flattened[0].cond.is_none() && branch_count == 1 {
// optimization for single-branch conditionals with a single instruction
ops.push(Op { cond: Some(cond), kind: flattened.remove(0).kind });
} else {
ops.push(Op {
kind: OpKind::BuiltIn(BuiltinOp::Jump(next_lbl.clone())),
cond: Some(!cond),
});
ops.extend(flattened);
}
if cnt != branch_count - 1 {
ops.push(BuiltinOp::Jump(end_lbl.clone()).into());
@ -64,14 +78,13 @@ impl Flatten for Vec<Box<dyn Flatten>> {
impl Flatten for Routine {
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
let skip_label = Label::Numbered(label_num.fetch_add(1, Ordering::Relaxed));
let skip_label = Label::unique(label_num);
let mut ops : Vec<Op> = vec![
let mut ops: Vec<Op> = vec![
BuiltinOp::Barrier {
kind: Barrier::Open(skip_label.clone()),
msg: Some(format!("proc {} start", self.name).into())
msg: Some(format!("proc {} start", self.name).into()),
}.into(),
BuiltinOp::Routine(self.name.clone()).into(),
];
@ -80,7 +93,7 @@ impl Flatten for Routine {
ops.push(
BuiltinOp::Barrier {
kind: Barrier::Close(skip_label.clone()),
msg: Some(format!("proc {} end", self.name).into())
msg: Some(format!("proc {} end", self.name).into()),
}.into()
);
@ -92,7 +105,7 @@ impl Flatten for Routine {
pub fn labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, CrsnError> {
let mut label_positions = HashMap::<Label, usize>::new();
for (n, op) in ops.iter().enumerate() {
if let Op::BuiltIn(BuiltinOp::Label(name)) = op {
if let OpKind::BuiltIn(BuiltinOp::Label(name)) = &op.kind {
label_positions.insert(name.clone(), n - label_positions.len());
}
}
@ -100,28 +113,23 @@ pub fn labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, CrsnError> {
let mut cleaned = vec![];
let mut skipped = 0;
for (n, op) in ops.into_iter().enumerate() {
match op {
Op::BuiltIn(BuiltinOp::Label(_)) => {
match op.kind {
OpKind::BuiltIn(BuiltinOp::Label(_)) => {
skipped += 1;
}
Op::BuiltIn(BuiltinOp::Jump(target)) => {
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(RdData::Immediate(skip as Value)))));
} else {
return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
}
}
Op::BuiltIn(BuiltinOp::JumpIf(cond, target)) => {
OpKind::BuiltIn(BuiltinOp::Jump(target)) => {
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(RdData::Immediate(skip as Value)))));
cleaned.push(Op {
cond: op.cond,
kind: OpKind::BuiltIn(BuiltinOp::Skip(Rd::new(RdData::Immediate(skip as Value)))),
});
} else {
return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
}
}
other => {
cleaned.push(other);
_ => {
cleaned.push(op);
}
}
}

@ -9,7 +9,7 @@ pub mod cond;
mod flatten;
/// A higher-level instruction
pub struct Instr {
pub struct InstrWithBranches {
pub op: Op,
pub branches: Option<Vec<(Cond, Box<dyn Flatten>)>>,
}

@ -1,5 +1,6 @@
use std::fmt::Debug;
use crate::asm::instr::Cond;
use crate::builtin::defs::BuiltinOp;
use crate::module::{EvalRes, OpTrait};
use crate::runtime::fault::Fault;
@ -7,19 +8,34 @@ use crate::runtime::run_thread::{info::ThreadInfo, state::RunState};
/// A higher level simple opration
#[derive(Debug)]
pub enum Op {
pub enum OpKind {
BuiltIn(BuiltinOp),
/// Instruction added by an extension
Ext(Box<dyn OpTrait>),
}
#[derive(Debug)]
pub struct Op {
pub cond: Option<Cond>,
pub kind: OpKind,
}
impl OpTrait for Op {
fn execute(&self, ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
match self {
Op::BuiltIn(op) => {
if let Some(cond) = self.cond {
if !state.test_cond(cond) {
return Ok(EvalRes {
cycles: 0,
advance: 1,
});
}
}
match &self.kind {
OpKind::BuiltIn(op) => {
op.execute(ti, state)
}
Op::Ext(op) => {
OpKind::Ext(op) => {
op.execute(ti, state)
}
}

@ -24,11 +24,5 @@ pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Resu
let ops = parse::parse(source, &pcx)?;
trace!("--- Compiled program ---");
for (n, op) in ops.iter().enumerate() {
trace!("{:04} : {:?}", n, op);
}
trace!("------------------------");
Ok(Program::new(ops, parsers)?)
}

@ -16,7 +16,7 @@ fn is_valid_identifier(name: &str) -> bool {
/// Parse register alias
pub fn parse_reg_alias(name: Option<Sexp>) -> Result<RegisterAlias, CrsnError> {
trace!("parse reg alias: {:?}", name);
// trace!("parse reg alias: {:?}", name);
let name = expect_string_atom(name)?;
@ -29,7 +29,7 @@ pub fn parse_reg_alias(name: Option<Sexp>) -> Result<RegisterAlias, CrsnError> {
/// Parse constant name
pub fn parse_constant_name(name: Option<Sexp>) -> Result<ConstantName, CrsnError> {
trace!("parse const name: {:?}", name);
// trace!("parse const name: {:?}", name);
let name = expect_string_atom(name)?;
@ -42,7 +42,7 @@ pub fn parse_constant_name(name: Option<Sexp>) -> Result<ConstantName, CrsnError
/// Parse a label
pub fn parse_label(name: Option<Sexp>) -> Result<Label, CrsnError> {
trace!("parse label: {:?}", name);
// trace!("parse label: {:?}", name);
let name = expect_string_atom(name)?;
Ok(Label::Named(name.trim_start_matches(':').into()))
@ -50,7 +50,7 @@ pub fn parse_label(name: Option<Sexp>) -> Result<Label, CrsnError> {
/// Parse data disposition (address/value, without the read/write restriction)
pub fn parse_data_disp(tok: Option<Sexp>, pcx: &ParserContext) -> Result<DataDisp, CrsnError> {
trace!("parse data: {:?}", tok);
// trace!("parse data: {:?}", tok);
let tok = if let Some(tok) = tok {
tok
@ -103,7 +103,7 @@ pub fn parse_value(tok: Option<Sexp>) -> Result<Value, CrsnError> {
return Err(CrsnError::Parse("Expected value token".into()));
};
trace!("parse value: {:?}", tok);
// trace!("parse value: {:?}", tok);
match &tok {
Sexp::Atom(Atom::I(val)) => {
@ -120,7 +120,7 @@ pub fn parse_value(tok: Option<Sexp>) -> Result<Value, CrsnError> {
pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
trace!("parse u64 from {}", literal);
// trace!("parse u64 from {}", literal);
let mut without_underscores = Cow::Borrowed(literal);
if without_underscores.contains('_') {
without_underscores = without_underscores.replace('_', "").into();
@ -136,7 +136,7 @@ pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
}
pub fn parse_i64(literal: &str) -> anyhow::Result<i64> {
trace!("parse i64 from {}", literal);
// trace!("parse i64 from {}", literal);
if let Some(_value) = literal.strip_prefix("-") {
Ok(-1 * i64::try_from(parse_u64(literal)?)?)
} else {

@ -1,19 +1,16 @@
use sexp::Sexp;
use crate::asm::data::literal::RoutineName;
use crate::asm::data::Register;
use crate::asm::error::CrsnError;
use crate::asm::instr::{Flatten, Instr, Routine};
use crate::asm::instr::{Flatten, InstrWithBranches};
use crate::asm::parse::arg_parser::TokenParser;
use crate::asm::parse::parse_cond::parse_cond_branch;
use crate::asm::parse::parse_data::parse_reg_alias;
use crate::asm::parse::parse_routine::parse_routine;
use crate::asm::parse::ParserContext;
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
use crate::asm::patches::SexpIsA;
use crate::module::ParseRes;
use super::parse_op::parse_op;
use crate::asm::parse::parse_routine::parse_routine;
pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
let mut parsed = vec![];
@ -66,7 +63,7 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pcx: &ParserContext)
};
if let Some(op) = parse_op(name.as_str(), arg_tokens)? {
parsed.push(Box::new(Instr {
parsed.push(Box::new(InstrWithBranches {
op,
branches,
}));

@ -1,16 +1,26 @@
use crate::asm::error::CrsnError;
use crate::asm::instr::cond::parse_cond;
use crate::asm::instr::Op;
use crate::asm::parse::arg_parser::TokenParser;
use crate::builtin::parse::BuiltinOps;
use crate::module::ParseRes;
pub fn parse_op<'a>(keyword: &str, mut arg_tokens: TokenParser<'a>) -> Result<Option<Op>, CrsnError> {
pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>) -> Result<Option<Op>, CrsnError> {
// Include built-in instructions
let builtins = [BuiltinOps::new()];
let mut cond = None;
if let Some(pos) = keyword.find('.') {
cond = Some(parse_cond(&keyword[(pos + 1)..])?);
keyword = &keyword[..pos];
}
for p in builtins.iter().chain(arg_tokens.pcx.parsers) {
arg_tokens = match p.parse_op(keyword, arg_tokens) {
Ok(ParseRes::Parsed(op)) => return Ok(Some(op)),
Ok(ParseRes::Parsed(kind)) => return Ok(Some(Op {
cond,
kind,
})),
Ok(ParseRes::ParsedNone) => return Ok(None),
Ok(ParseRes::Unknown(to_reuse)) => {
if to_reuse.parsing_started() {

@ -1,13 +1,13 @@
use sexp::Sexp;
use crate::asm::parse::{ParserContext, parse_instructions};
use crate::asm::instr::{Flatten, Routine};
use crate::asm::data::Register;
use crate::asm::error::CrsnError;
use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::asm::instr::{Flatten, Routine};
use crate::asm::parse::{parse_instructions, ParserContext};
use crate::asm::parse::arg_parser::TokenParser;
use crate::asm::patches::SexpIsA;
use crate::asm::parse::parse_data::parse_reg_alias;
use crate::asm::data::Register;
use crate::asm::data::literal::RoutineName;
use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::asm::patches::SexpIsA;
use crate::builtin::parse::parse_routine_name;
pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {

@ -1,6 +1,7 @@
use crate::asm::data::{Rd, RdObj, Wr};
use crate::asm::data::literal::{DebugMsg, Label, RoutineName};
use crate::asm::instr::{Cond, Op};
use crate::asm::instr::Op;
use crate::asm::instr::op::OpKind;
#[derive(Debug)]
pub enum Barrier {
@ -9,7 +10,7 @@ pub enum Barrier {
/// Closing counterpart to the Open barrier
Close(Label),
/// Stand-alone barrier
Standalone
Standalone,
}
#[derive(Debug)]
@ -26,10 +27,6 @@ pub enum BuiltinOp {
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),
@ -45,12 +42,10 @@ pub enum BuiltinOp {
Routine(RoutineName),
/// Skip backward or forward. The skip count can be defined by an argument.
Skip(Rd),
/// Skip if a flag is set
SkipIf(Cond, Rd),
/// Deny jumps, skips and run across this address, producing a run-time fault.
Barrier {
kind: Barrier,
msg: Option<DebugMsg>
msg: Option<DebugMsg>,
},
/// Generate a run-time fault with a debugger message
Fault(Option<DebugMsg>),
@ -67,6 +62,15 @@ pub enum BuiltinOp {
impl From<BuiltinOp> for Op {
fn from(bo: BuiltinOp) -> Self {
Op::BuiltIn(bo)
Op {
kind: bo.into(),
cond: None,
}
}
}
impl From<BuiltinOp> for OpKind {
fn from(bo: BuiltinOp) -> Self {
OpKind::BuiltIn(bo)
}
}

@ -3,7 +3,7 @@ use std::time::Duration;
use crate::asm::data::{Rd, RdData};
use crate::asm::data::literal::Addr;
use crate::asm::instr::Cond;
use crate::builtin::defs::{BuiltinOp, Barrier};
use crate::builtin::defs::{Barrier, BuiltinOp};
use crate::module::{EvalRes, OpTrait};
use crate::runtime::fault::Fault;
use crate::runtime::frame::StackFrame;
@ -59,41 +59,8 @@ impl OpTrait for BuiltinOp {
}
}
}
BuiltinOp::Jump(name) => {
unimplemented!()
// match program.find_local_label(state.get_pc(), name) {
// Ok(pos) => {
// state.set_pc(pos);
// }
// Err(e) => {
// return Err(e);
// }
// }
}
BuiltinOp::JumpIf(cond, name) => {
unimplemented!()
// if state.test_cond(*cond) {
// match program.find_local_label(state.get_pc(), name) {
// Ok(pos) => {
// state.set_pc(pos);
// }
// Err(e) => {
// return Err(e);
// }
// }
// }
}
BuiltinOp::FarJumpIf(cond, name) => {
if state.test_cond(*cond) {
match program.find_far_label(name) {
Ok(pos) => {
state.set_pc(pos);
}
Err(e) => {
return Err(e);
}
}
}
BuiltinOp::Jump(_name) => {
panic!("jump not translated to skip by assembler!");
}
BuiltinOp::Call(name, args) => {
match program.find_routine(&name) {
@ -134,15 +101,6 @@ impl OpTrait for BuiltinOp {
let pc = state.get_pc();
program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?;
}
BuiltinOp::SkipIf(cond, val) => {
if state.test_cond(*cond) {
debug!("Skipping");
let steps = state.read(*val)?;
res.advance = i64::from_ne_bytes(steps.to_ne_bytes());
let pc = state.get_pc();
program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?;
}
}
BuiltinOp::Move { dst, src } => {
state.clear_status();
let val = state.read(*src)?;

@ -3,12 +3,11 @@ use sexp::{Atom, Sexp};
use crate::asm::data::literal::{Label, RoutineName};
use crate::asm::data::reg::parse_reg;
use crate::asm::error::CrsnError;
use crate::asm::instr::cond::parse_cond;
use crate::asm::instr::Op;
use crate::asm::instr::op::OpKind;
use crate::asm::parse::arg_parser::TokenParser;
use crate::asm::parse::parse_data::{parse_constant_name, parse_label, parse_rd, parse_reg_alias, parse_value};
use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::builtin::defs::{BuiltinOp, Barrier};
use crate::builtin::defs::{Barrier, BuiltinOp};
use crate::module::{CrsnExtension, ParseRes};
#[derive(Debug, Clone)]
@ -29,10 +28,10 @@ impl CrsnExtension for BuiltinOps {
"builtin"
}
fn parse_op<'a>(&self, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
fn parse_op<'a>(&self, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
let pcx = args.pcx;
Ok(ParseRes::Parsed(Op::BuiltIn(match keyword {
Ok(ParseRes::Parsed(OpKind::BuiltIn(match keyword {
"nop" => {
BuiltinOp::Nop
}
@ -142,37 +141,17 @@ impl CrsnExtension for BuiltinOps {
BuiltinOp::Routine(parse_routine_name(name)?)
}
"sk" => {
"skip" => {
BuiltinOp::Skip(args.next_rd()?)
}
// TODO add jne-style names for jif ne ...
"skif" => {
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 {
kind: Barrier::Standalone,
msg: match args.next() {
None => None,
Some(s) => Some(expect_string_atom(Some(s))?.into()),
}
},
}
}
@ -231,11 +210,11 @@ impl CrsnExtension for BuiltinOps {
}
}
pub(crate) fn parse_routine_name(name : String) -> Result<RoutineName, CrsnError> {
pub(crate) fn parse_routine_name(name: String) -> Result<RoutineName, CrsnError> {
let (name, arity) = if let Some(n) = name.find('/') {
(
(&name[0..n]).to_string(),
(&name[(n+1)..]).parse::<u8>()?
(&name[(n + 1)..]).parse::<u8>()?
)
} else {
(name, 0)

@ -7,7 +7,8 @@ pub use eval_res::EvalRes;
use crate::asm::data::literal::Value;
use crate::asm::data::Mask;
use crate::asm::error::CrsnError;
use crate::asm::instr::{Flatten, Op};
use crate::asm::instr::Flatten;
use crate::asm::instr::op::OpKind;
use crate::asm::parse::arg_parser::TokenParser;
use crate::runtime::fault::Fault;
use crate::runtime::run_thread::state::RunState;
@ -25,10 +26,10 @@ pub enum ParseRes<'a, T> {
Unknown(TokenParser<'a>),
}
impl<'a> ParseRes<'a, Op> {
impl<'a> ParseRes<'a, OpKind> {
/// Helper to construct an extension op
pub fn ext(op: impl OpTrait) -> Self {
Self::Parsed(Op::Ext(Box::new(op)))
Self::Parsed(OpKind::Ext(Box::new(op)))
}
}
@ -47,7 +48,7 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static {
/// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
///
/// pcx is available on the arg_tokens parser
fn parse_op<'a>(&self, keyword: &str, arg_tokens: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError>;
fn parse_op<'a>(&self, keyword: &str, arg_tokens: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError>;
/// Parse a generic S-expression (non-op)
///

@ -2,7 +2,7 @@ pub mod run_thread;
// pub mod mlock;
// pub mod sparse;
pub mod fault;
pub mod span;
// pub mod span;
pub mod exec;
pub mod frame;
pub mod program;

@ -3,7 +3,8 @@ use std::sync::Arc;
use crate::asm::data::literal::{Addr, Label, RoutineName};
use crate::asm::instr::Op;
use crate::builtin::defs::{BuiltinOp, Barrier};
use crate::asm::instr::op::OpKind;
use crate::builtin::defs::{Barrier, BuiltinOp};
use crate::module::CrsnExtension;
use crate::runtime::fault::Fault;
@ -12,7 +13,6 @@ pub struct Program {
pub ops: Vec<Op>,
pub extensions: Arc<Vec<Box<dyn CrsnExtension>>>,
routines: HashMap<RoutineName, Addr>,
local_labels: HashMap<Label, Addr>,
far_labels: HashMap<Label, Addr>,
/// Barriers from-to (inclusive).
/// Standalone barriers have both addresses the same.
@ -25,7 +25,6 @@ impl Program {
ops,
extensions,
routines: Default::default(),
local_labels: Default::default(),
far_labels: Default::default(),
barriers: Default::default(),
};
@ -35,23 +34,23 @@ impl Program {
/// Find all the named things
fn scan(&mut self) -> anyhow::Result<()> {
let mut barrier_starts : HashMap<&Label, Addr> = HashMap::new();
let mut barrier_starts: HashMap<&Label, Addr> = HashMap::new();
for (pos, op) in self.ops.iter().enumerate() {
match op {
Op::BuiltIn(BuiltinOp::FarLabel(name)) => {
match &op.kind {
OpKind::BuiltIn(BuiltinOp::FarLabel(name)) => {
self.far_labels.insert(name.clone(), pos.into());
}
Op::BuiltIn(BuiltinOp::Routine(name)) => {
OpKind::BuiltIn(BuiltinOp::Routine(name)) => {
self.routines.insert(name.clone(), pos.into());
}
Op::BuiltIn(
OpKind::BuiltIn(
BuiltinOp::Barrier {
kind: Barrier::Open(lbl), ..
}
) => {
barrier_starts.insert(lbl, pos.into());
}
Op::BuiltIn(
OpKind::BuiltIn(
BuiltinOp::Barrier {
kind: Barrier::Close(lbl),
msg,
@ -64,7 +63,7 @@ impl Program {
anyhow::bail!("Block barrier \"{:?}\" closed without being open!", msg);
}
}
Op::BuiltIn(
OpKind::BuiltIn(
BuiltinOp::Barrier {
kind: Barrier::Standalone,
..
@ -80,7 +79,7 @@ impl Program {
anyhow::bail!("Some block barriers open without being closed!");
}
debug!("Program scanned: {:?}", self);
trace!("Program scanned: {:?}", self);
Ok(())
}
@ -88,7 +87,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::BuiltIn(BuiltinOp::Halt)
&Op { kind: OpKind::BuiltIn(BuiltinOp::Halt), cond: None }
} else {
&self.ops[addr.0 as usize]
}
@ -104,7 +103,7 @@ impl Program {
if b0 != b1 {
// block barrier that only partially intersects the jump
if (*b0 >= from && *b0 <= to) != (*b1 >= from && *b1 <= to) {
if let Op::BuiltIn(BuiltinOp::Barrier { msg, .. }) = self.read(*b0) {
if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.read(*b0).kind {
return Err(Fault::JumpThroughBarrier {
msg: msg.clone().unwrap_or("BLOCK BARRIER".into())
});
@ -115,7 +114,7 @@ impl Program {
} else {
// point barrier
if *b0 >= from && *b0 <= to {
if let Op::BuiltIn(BuiltinOp::Barrier { msg, .. }) = self.read(*b0) {
if let OpKind::BuiltIn(BuiltinOp::Barrier { msg, .. }) = &self.read(*b0).kind {
return Err(Fault::JumpThroughBarrier {
msg: msg.clone().unwrap_or("POINT BARRIER".into())
});

@ -1,5 +1,5 @@
use crsn::asm::error::CrsnError;
use crsn::asm::instr::Op;
use crsn::asm::instr::op::OpKind;
use crsn::asm::parse::arg_parser::TokenParser;
use crsn::module::{CrsnExtension, ParseRes};
@ -21,7 +21,7 @@ impl CrsnExtension for ArithOps {
"arith"
}
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
parse::parse(keyword, args)
}
}

@ -1,12 +1,12 @@
use crsn::asm::data::{Rd, Wr};
use crsn::asm::error::CrsnError;
use crsn::asm::instr::Op;
use crsn::asm::instr::op::OpKind;
use crsn::asm::parse::arg_parser::TokenParser;
use crsn::module::ParseRes;
use crate::defs::ArithOp;
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
Ok(ParseRes::ext(match keyword {
"cmp" => {
ArithOp::Compare {

@ -2,7 +2,7 @@
extern crate log;
use crsn::asm::error::CrsnError;
use crsn::asm::instr::Op;
use crsn::asm::instr::op::OpKind;
use crsn::asm::parse::arg_parser::TokenParser;
use crsn::module::{CrsnExtension, ParseRes};
@ -24,7 +24,7 @@ impl CrsnExtension for ScreenOps {
"screen"
}
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
parse::parse(keyword, args)
}
}

@ -1,12 +1,12 @@
use crsn::asm::data::Rd;
use crsn::asm::error::CrsnError;
use crsn::asm::instr::Op;
use crsn::asm::instr::op::OpKind;
use crsn::asm::parse::arg_parser::TokenParser;
use crsn::module::ParseRes;
use crate::defs::ScreenOp;
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
Ok(ParseRes::ext(match keyword {
"sc-init" => {
ScreenOp::ScreenInit {

@ -1,6 +1,6 @@
use crsn::asm::data::literal::Value;
use crsn::asm::error::CrsnError;
use crsn::asm::instr::Op;
use crsn::asm::instr::op::OpKind;
use crsn::asm::parse::arg_parser::TokenParser;
use crsn::module::{CrsnExtension, ParseRes};
use crsn::runtime::fault::Fault;
@ -24,7 +24,7 @@ impl CrsnExtension for StackOps {
"stacks"
}
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
parse::parse(keyword, args)
}

@ -1,11 +1,11 @@
use crsn::asm::error::CrsnError;
use crsn::asm::instr::Op;
use crsn::asm::instr::op::OpKind;
use crsn::asm::parse::arg_parser::TokenParser;
use crsn::module::ParseRes;
use crate::defs::StackOp;
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
Ok(ParseRes::ext(match keyword {
"stack" => {
StackOp::NewStack {

@ -3,6 +3,7 @@ extern crate log;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use clappconfig::{AppConfig, clap};
use clappconfig::clap::ArgMatches;
@ -13,7 +14,6 @@ use crsn::runtime::run_thread::{RunThread, ThreadToken};
use crsn_arith::ArithOps;
use crsn_screen::ScreenOps;
use crsn_stacks::StackOps;
use std::time::Duration;
mod read_file;
mod serde_duration_millis;
@ -30,7 +30,9 @@ struct Config {
log: LogConfig,
#[serde(skip)]
program_file: String,
#[serde(with="serde_duration_millis")]
#[serde(skip)]
asm_only: bool,
#[serde(with = "serde_duration_millis")]
cycle_time: Duration,
}
@ -42,6 +44,7 @@ impl Default for Config {
modules: Default::default(),
},
program_file: "".to_string(),
asm_only: false,
cycle_time: Duration::default(),
}
}
@ -69,6 +72,12 @@ impl AppConfig for Config {
.required_unless("default-config")
.takes_value(true),
)
.arg(
clap::Arg::with_name("asm-only")
.short("P")
.long("asm")
.help("Only assemble, do not run."),
)
.arg(
clap::Arg::with_name("cycle")
.long("cycle")
@ -95,6 +104,7 @@ impl AppConfig for Config {
fn configure(mut self, clap: &ArgMatches) -> anyhow::Result<Self> {
self.program_file = clap.value_of("input").unwrap().to_string();
self.asm_only = clap.is_present("asm-only");
if let Some(c) = clap.value_of("cycle") {
self.cycle_time = Duration::from_millis(c.parse().unwrap());
}
@ -118,6 +128,19 @@ fn main() -> anyhow::Result<()> {
let parsed = crsn::asm::assemble(&source, parsers)?;
if config.asm_only {
for (n, op) in parsed.ops.iter().enumerate() {
println!("{:04} : {:?}", n, op);
}
return Ok(());
} else {
trace!("--- Compiled program ---");
for (n, op) in parsed.ops.iter().enumerate() {
trace!("{:04} : {:?}", n, op);
}
trace!("------------------------");
}
info!("Start runtime");
let args = &[];

@ -1,6 +1,7 @@
use serde::{self, Deserialize, Deserializer, Serializer};
use std::time::Duration;
use serde::{self, Deserialize, Deserializer, Serializer};
pub fn serialize<S>(value: &Duration, se: S) -> Result<S::Ok, S::Error>
where
S: Serializer,

Loading…
Cancel
Save