From 986f3be6a2105ef453c3cbb03ed0f150d5dba807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 4 Oct 2020 23:30:11 +0200 Subject: [PATCH] cleanup. remove conditional jumps, replaced by condition embedded in the enum --- _stash/README.txt | 1 + {crsn/src/runtime => _stash}/mlock.rs | 0 {crsn/src/runtime => _stash}/span.rs | 0 {crsn/src/runtime => _stash}/sparse.rs | 0 crsn/src/asm/data/reg.rs | 6 +-- crsn/src/asm/error.rs | 2 +- crsn/src/asm/instr/flatten.rs | 58 +++++++++++++++----------- crsn/src/asm/instr/mod.rs | 2 +- crsn/src/asm/instr/op.rs | 24 +++++++++-- crsn/src/asm/mod.rs | 6 --- crsn/src/asm/parse/parse_data.rs | 14 +++---- crsn/src/asm/parse/parse_instr.rs | 9 ++-- crsn/src/asm/parse/parse_op.rs | 14 ++++++- crsn/src/asm/parse/parse_routine.rs | 12 +++--- crsn/src/builtin/defs.rs | 24 ++++++----- crsn/src/builtin/exec.rs | 48 ++------------------- crsn/src/builtin/parse.rs | 37 ++++------------ crsn/src/module/mod.rs | 9 ++-- crsn/src/runtime/mod.rs | 2 +- crsn/src/runtime/program.rs | 27 ++++++------ crsn_arith/src/lib.rs | 4 +- crsn_arith/src/parse.rs | 4 +- crsn_screen/src/lib.rs | 4 +- crsn_screen/src/parse.rs | 4 +- crsn_stacks/src/lib.rs | 4 +- crsn_stacks/src/parse.rs | 4 +- launcher/src/main.rs | 27 +++++++++++- launcher/src/serde_duration_millis.rs | 3 +- 28 files changed, 170 insertions(+), 179 deletions(-) create mode 100644 _stash/README.txt rename {crsn/src/runtime => _stash}/mlock.rs (100%) rename {crsn/src/runtime => _stash}/span.rs (100%) rename {crsn/src/runtime => _stash}/sparse.rs (100%) diff --git a/_stash/README.txt b/_stash/README.txt new file mode 100644 index 0000000..288326b --- /dev/null +++ b/_stash/README.txt @@ -0,0 +1 @@ +Files in this folder were developed for crsn but are not currently used by core or any extension. diff --git a/crsn/src/runtime/mlock.rs b/_stash/mlock.rs similarity index 100% rename from crsn/src/runtime/mlock.rs rename to _stash/mlock.rs diff --git a/crsn/src/runtime/span.rs b/_stash/span.rs similarity index 100% rename from crsn/src/runtime/span.rs rename to _stash/span.rs diff --git a/crsn/src/runtime/sparse.rs b/_stash/sparse.rs similarity index 100% rename from crsn/src/runtime/sparse.rs rename to _stash/sparse.rs diff --git a/crsn/src/asm/data/reg.rs b/crsn/src/asm/data/reg.rs index 159c38e..de82774 100644 --- a/crsn/src/asm/data/reg.rs +++ b/crsn/src/asm/data/reg.rs @@ -26,19 +26,19 @@ impl Display for Register { pub fn parse_reg(name: &str) -> anyhow::Result { // 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()?; diff --git a/crsn/src/asm/error.rs b/crsn/src/asm/error.rs index 53077b8..d121c92 100644 --- a/crsn/src/asm/error.rs +++ b/crsn/src/asm/error.rs @@ -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)] diff --git a/crsn/src/asm/instr/flatten.rs b/crsn/src/asm/instr/flatten.rs index dd4c2ac..5f4cb86 100644 --- a/crsn/src/asm/instr/flatten.rs +++ b/crsn/src/asm/instr/flatten.rs @@ -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, label_num: &AtomicU32) -> Result, 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> { impl Flatten for Routine { fn flatten(self: Box, label_num: &AtomicU32) -> Result, CrsnError> { - let skip_label = Label::Numbered(label_num.fetch_add(1, Ordering::Relaxed)); + let skip_label = Label::unique(label_num); - let mut ops : Vec = vec![ + let mut ops: Vec = 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) -> Result, CrsnError> { let mut label_positions = HashMap::::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) -> Result, 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); } } } diff --git a/crsn/src/asm/instr/mod.rs b/crsn/src/asm/instr/mod.rs index 94f25a5..0ac1913 100644 --- a/crsn/src/asm/instr/mod.rs +++ b/crsn/src/asm/instr/mod.rs @@ -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)>>, } diff --git a/crsn/src/asm/instr/op.rs b/crsn/src/asm/instr/op.rs index a065720..f6e7f6d 100644 --- a/crsn/src/asm/instr/op.rs +++ b/crsn/src/asm/instr/op.rs @@ -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), } +#[derive(Debug)] +pub struct Op { + pub cond: Option, + pub kind: OpKind, +} + impl OpTrait for Op { fn execute(&self, ti: &ThreadInfo, state: &mut RunState) -> Result { - 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) } } diff --git a/crsn/src/asm/mod.rs b/crsn/src/asm/mod.rs index 01184e5..f4eb875 100644 --- a/crsn/src/asm/mod.rs +++ b/crsn/src/asm/mod.rs @@ -24,11 +24,5 @@ pub fn assemble(source: &str, parsers: Arc>>) -> 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)?) } diff --git a/crsn/src/asm/parse/parse_data.rs b/crsn/src/asm/parse/parse_data.rs index fb3e63d..e5ad224 100644 --- a/crsn/src/asm/parse/parse_data.rs +++ b/crsn/src/asm/parse/parse_data.rs @@ -16,7 +16,7 @@ fn is_valid_identifier(name: &str) -> bool { /// Parse register alias pub fn parse_reg_alias(name: Option) -> Result { - 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) -> Result { /// Parse constant name pub fn parse_constant_name(name: Option) -> Result { - 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) -> Result) -> Result { - 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) -> Result { /// Parse data disposition (address/value, without the read/write restriction) pub fn parse_data_disp(tok: Option, pcx: &ParserContext) -> Result { - 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) -> Result { 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) -> Result { pub fn parse_u64(literal: &str) -> anyhow::Result { - 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 { } pub fn parse_i64(literal: &str) -> anyhow::Result { - 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 { diff --git a/crsn/src/asm/parse/parse_instr.rs b/crsn/src/asm/parse/parse_instr.rs index a63b0e6..ae0e3aa 100644 --- a/crsn/src/asm/parse/parse_instr.rs +++ b/crsn/src/asm/parse/parse_instr.rs @@ -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, pcx: &ParserContext) -> Result, CrsnError> { let mut parsed = vec![]; @@ -66,7 +63,7 @@ pub fn parse_instructions(items: impl Iterator, 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, })); diff --git a/crsn/src/asm/parse/parse_op.rs b/crsn/src/asm/parse/parse_op.rs index 1375f66..c32afbc 100644 --- a/crsn/src/asm/parse/parse_op.rs +++ b/crsn/src/asm/parse/parse_op.rs @@ -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, CrsnError> { +pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>) -> Result, 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() { diff --git a/crsn/src/asm/parse/parse_routine.rs b/crsn/src/asm/parse/parse_routine.rs index 7ead555..3e79e30 100644 --- a/crsn/src/asm/parse/parse_routine.rs +++ b/crsn/src/asm/parse/parse_routine.rs @@ -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 + Clone, pcx: &ParserContext) -> Result, CrsnError> { diff --git a/crsn/src/builtin/defs.rs b/crsn/src/builtin/defs.rs index d32adf0..a20ae1d 100644 --- a/crsn/src/builtin/defs.rs +++ b/crsn/src/builtin/defs.rs @@ -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 + msg: Option, }, /// Generate a run-time fault with a debugger message Fault(Option), @@ -67,6 +62,15 @@ pub enum BuiltinOp { impl From for Op { fn from(bo: BuiltinOp) -> Self { - Op::BuiltIn(bo) + Op { + kind: bo.into(), + cond: None, + } + } +} + +impl From for OpKind { + fn from(bo: BuiltinOp) -> Self { + OpKind::BuiltIn(bo) } } diff --git a/crsn/src/builtin/exec.rs b/crsn/src/builtin/exec.rs index f68ee94..485805c 100644 --- a/crsn/src/builtin/exec.rs +++ b/crsn/src/builtin/exec.rs @@ -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)?; diff --git a/crsn/src/builtin/parse.rs b/crsn/src/builtin/parse.rs index 755b59c..baeab36 100644 --- a/crsn/src/builtin/parse.rs +++ b/crsn/src/builtin/parse.rs @@ -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, CrsnError> { + fn parse_op<'a>(&self, keyword: &str, mut args: TokenParser<'a>) -> Result, 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 { +pub(crate) fn parse_routine_name(name: String) -> Result { let (name, arity) = if let Some(n) = name.find('/') { ( (&name[0..n]).to_string(), - (&name[(n+1)..]).parse::()? + (&name[(n + 1)..]).parse::()? ) } else { (name, 0) diff --git a/crsn/src/module/mod.rs b/crsn/src/module/mod.rs index 05207ba..9e894e1 100644 --- a/crsn/src/module/mod.rs +++ b/crsn/src/module/mod.rs @@ -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, CrsnError>; + fn parse_op<'a>(&self, keyword: &str, arg_tokens: TokenParser<'a>) -> Result, CrsnError>; /// Parse a generic S-expression (non-op) /// diff --git a/crsn/src/runtime/mod.rs b/crsn/src/runtime/mod.rs index c89a37c..17c2715 100644 --- a/crsn/src/runtime/mod.rs +++ b/crsn/src/runtime/mod.rs @@ -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; diff --git a/crsn/src/runtime/program.rs b/crsn/src/runtime/program.rs index c550081..b45d89e 100644 --- a/crsn/src/runtime/program.rs +++ b/crsn/src/runtime/program.rs @@ -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, pub extensions: Arc>>, routines: HashMap, - local_labels: HashMap, far_labels: HashMap, /// 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()) }); diff --git a/crsn_arith/src/lib.rs b/crsn_arith/src/lib.rs index 51095a4..12a87e8 100644 --- a/crsn_arith/src/lib.rs +++ b/crsn_arith/src/lib.rs @@ -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, CrsnError> { + fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result, CrsnError> { parse::parse(keyword, args) } } diff --git a/crsn_arith/src/parse.rs b/crsn_arith/src/parse.rs index 5e1ce93..2b3b6fe 100644 --- a/crsn_arith/src/parse.rs +++ b/crsn_arith/src/parse.rs @@ -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, CrsnError> { +pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { Ok(ParseRes::ext(match keyword { "cmp" => { ArithOp::Compare { diff --git a/crsn_screen/src/lib.rs b/crsn_screen/src/lib.rs index cd87ba8..c694e55 100644 --- a/crsn_screen/src/lib.rs +++ b/crsn_screen/src/lib.rs @@ -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, CrsnError> { + fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result, CrsnError> { parse::parse(keyword, args) } } diff --git a/crsn_screen/src/parse.rs b/crsn_screen/src/parse.rs index e912f4a..9eb8700 100644 --- a/crsn_screen/src/parse.rs +++ b/crsn_screen/src/parse.rs @@ -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, CrsnError> { +pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { Ok(ParseRes::ext(match keyword { "sc-init" => { ScreenOp::ScreenInit { diff --git a/crsn_stacks/src/lib.rs b/crsn_stacks/src/lib.rs index f20a6f5..c61336e 100644 --- a/crsn_stacks/src/lib.rs +++ b/crsn_stacks/src/lib.rs @@ -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, CrsnError> { + fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result, CrsnError> { parse::parse(keyword, args) } diff --git a/crsn_stacks/src/parse.rs b/crsn_stacks/src/parse.rs index 2b39f54..55da319 100644 --- a/crsn_stacks/src/parse.rs +++ b/crsn_stacks/src/parse.rs @@ -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, CrsnError> { +pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { Ok(ParseRes::ext(match keyword { "stack" => { StackOp::NewStack { diff --git a/launcher/src/main.rs b/launcher/src/main.rs index b737f4e..a996299 100644 --- a/launcher/src/main.rs +++ b/launcher/src/main.rs @@ -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.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 = &[]; diff --git a/launcher/src/serde_duration_millis.rs b/launcher/src/serde_duration_millis.rs index d16a1b9..306ad82 100644 --- a/launcher/src/serde_duration_millis.rs +++ b/launcher/src/serde_duration_millis.rs @@ -1,6 +1,7 @@ -use serde::{self, Deserialize, Deserializer, Serializer}; use std::time::Duration; +use serde::{self, Deserialize, Deserializer, Serializer}; + pub fn serialize(value: &Duration, se: S) -> Result where S: Serializer,