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> { pub fn parse_reg(name: &str) -> anyhow::Result<Register> {
// TODO deduplicate code // TODO deduplicate code
if let Some(rn) = name.strip_prefix("arg") { 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()))?; Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
} }
let val: u8 = rn.parse()?; let val: u8 = rn.parse()?;
Ok(Register::Arg(val)) Ok(Register::Arg(val))
} else if let Some(rn) = name.strip_prefix("res") { } 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()))?; Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
} }
let val: u8 = rn.parse()?; let val: u8 = rn.parse()?;
Ok(Register::Res(val)) Ok(Register::Res(val))
} else if let Some(rn) = name.strip_prefix("r") { } 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()))?; Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
} }
let val: u8 = rn.parse()?; let val: u8 = rn.parse()?;

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

@ -4,9 +4,10 @@ use std::sync::atomic::{AtomicU32, Ordering};
use crate::asm::data::{Rd, RdData}; use crate::asm::data::{Rd, RdData};
use crate::asm::data::literal::{Label, Value}; use crate::asm::data::literal::{Label, Value};
use crate::asm::error::{AsmError, CrsnError}; use crate::asm::error::{AsmError, CrsnError};
use crate::asm::instr::{Cond, Instr, Op, Routine}; use crate::asm::instr::{Cond, InstrWithBranches, Op, Routine};
use crate::builtin::defs::BuiltinOp; use crate::asm::instr::op::OpKind;
use crate::builtin::defs::Barrier; use crate::builtin::defs::Barrier;
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 {
@ -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> { fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
let mut ops = vec![self.op]; let mut ops = vec![self.op];
@ -37,8 +38,21 @@ impl Flatten for Instr {
} else { } else {
Label::unique(label_num) 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 { if cnt != branch_count - 1 {
ops.push(BuiltinOp::Jump(end_lbl.clone()).into()); ops.push(BuiltinOp::Jump(end_lbl.clone()).into());
@ -64,14 +78,13 @@ impl Flatten for Vec<Box<dyn Flatten>> {
impl Flatten for Routine { impl Flatten for Routine {
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> { 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 { BuiltinOp::Barrier {
kind: Barrier::Open(skip_label.clone()), kind: Barrier::Open(skip_label.clone()),
msg: Some(format!("proc {} start", self.name).into()) msg: Some(format!("proc {} start", self.name).into()),
}.into(), }.into(),
BuiltinOp::Routine(self.name.clone()).into(), BuiltinOp::Routine(self.name.clone()).into(),
]; ];
@ -80,7 +93,7 @@ impl Flatten for Routine {
ops.push( ops.push(
BuiltinOp::Barrier { BuiltinOp::Barrier {
kind: Barrier::Close(skip_label.clone()), kind: Barrier::Close(skip_label.clone()),
msg: Some(format!("proc {} end", self.name).into()) msg: Some(format!("proc {} end", self.name).into()),
}.into() }.into()
); );
@ -92,7 +105,7 @@ impl Flatten for Routine {
pub fn labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, CrsnError> { pub fn labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, CrsnError> {
let mut label_positions = HashMap::<Label, usize>::new(); let mut label_positions = HashMap::<Label, usize>::new();
for (n, op) in ops.iter().enumerate() { 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()); 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 cleaned = vec![];
let mut skipped = 0; let mut skipped = 0;
for (n, op) in ops.into_iter().enumerate() { for (n, op) in ops.into_iter().enumerate() {
match op { match op.kind {
Op::BuiltIn(BuiltinOp::Label(_)) => { OpKind::BuiltIn(BuiltinOp::Label(_)) => {
skipped += 1; skipped += 1;
} }
Op::BuiltIn(BuiltinOp::Jump(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::Skip(Rd::new(RdData::Immediate(skip as Value)))));
} else {
return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
}
}
Op::BuiltIn(BuiltinOp::JumpIf(cond, target)) => {
if let Some(dest) = label_positions.get(&target) { if let Some(dest) = label_positions.get(&target) {
let skip = *dest as isize - n as isize + skipped; 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 { } else {
return Err(CrsnError::Asm(AsmError::LabelNotDefined(target))); return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
} }
} }
other => { _ => {
cleaned.push(other); cleaned.push(op);
} }
} }
} }

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

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

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

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

@ -1,16 +1,26 @@
use crate::asm::error::CrsnError; use crate::asm::error::CrsnError;
use crate::asm::instr::cond::parse_cond;
use crate::asm::instr::Op; use crate::asm::instr::Op;
use crate::asm::parse::arg_parser::TokenParser; use crate::asm::parse::arg_parser::TokenParser;
use crate::builtin::parse::BuiltinOps; use crate::builtin::parse::BuiltinOps;
use crate::module::ParseRes; 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 // Include built-in instructions
let builtins = [BuiltinOps::new()]; 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) { for p in builtins.iter().chain(arg_tokens.pcx.parsers) {
arg_tokens = match p.parse_op(keyword, arg_tokens) { 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::ParsedNone) => return Ok(None),
Ok(ParseRes::Unknown(to_reuse)) => { Ok(ParseRes::Unknown(to_reuse)) => {
if to_reuse.parsing_started() { if to_reuse.parsing_started() {

@ -1,13 +1,13 @@
use sexp::Sexp; 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::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::parse::arg_parser::TokenParser;
use crate::asm::patches::SexpIsA;
use crate::asm::parse::parse_data::parse_reg_alias; use crate::asm::parse::parse_data::parse_reg_alias;
use crate::asm::data::Register; use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::asm::data::literal::RoutineName; use crate::asm::patches::SexpIsA;
use crate::builtin::parse::parse_routine_name; 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> { 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::{Rd, RdObj, Wr};
use crate::asm::data::literal::{DebugMsg, Label, RoutineName}; 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)] #[derive(Debug)]
pub enum Barrier { pub enum Barrier {
@ -9,7 +10,7 @@ pub enum Barrier {
/// Closing counterpart to the Open barrier /// Closing counterpart to the Open barrier
Close(Label), Close(Label),
/// Stand-alone barrier /// Stand-alone barrier
Standalone Standalone,
} }
#[derive(Debug)] #[derive(Debug)]
@ -26,10 +27,6 @@ pub enum BuiltinOp {
Label(Label), Label(Label),
/// Jump to a label /// Jump to a label
Jump(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). /// Mark a far jump target (can be jumped to from another routine).
/// This label is preserved in optimized code. /// This label is preserved in optimized code.
FarLabel(Label), FarLabel(Label),
@ -45,12 +42,10 @@ pub enum BuiltinOp {
Routine(RoutineName), Routine(RoutineName),
/// Skip backward or forward. The skip count can be defined by an argument. /// Skip backward or forward. The skip count can be defined by an argument.
Skip(Rd), Skip(Rd),
/// Skip if a flag is set
SkipIf(Cond, Rd),
/// Deny jumps, skips and run across this address, producing a run-time fault. /// Deny jumps, skips and run across this address, producing a run-time fault.
Barrier { Barrier {
kind: Barrier, kind: Barrier,
msg: Option<DebugMsg> msg: Option<DebugMsg>,
}, },
/// Generate a run-time fault with a debugger message /// Generate a run-time fault with a debugger message
Fault(Option<DebugMsg>), Fault(Option<DebugMsg>),
@ -67,6 +62,15 @@ pub enum BuiltinOp {
impl From<BuiltinOp> for Op { impl From<BuiltinOp> for Op {
fn from(bo: BuiltinOp) -> Self { 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::{Rd, RdData};
use crate::asm::data::literal::Addr; use crate::asm::data::literal::Addr;
use crate::asm::instr::Cond; use crate::asm::instr::Cond;
use crate::builtin::defs::{BuiltinOp, Barrier}; use crate::builtin::defs::{Barrier, BuiltinOp};
use crate::module::{EvalRes, OpTrait}; use crate::module::{EvalRes, OpTrait};
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::frame::StackFrame; use crate::runtime::frame::StackFrame;
@ -59,41 +59,8 @@ impl OpTrait for BuiltinOp {
} }
} }
} }
BuiltinOp::Jump(name) => { BuiltinOp::Jump(_name) => {
unimplemented!() panic!("jump not translated to skip by assembler!");
// 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::Call(name, args) => { BuiltinOp::Call(name, args) => {
match program.find_routine(&name) { match program.find_routine(&name) {
@ -134,15 +101,6 @@ impl OpTrait for BuiltinOp {
let pc = state.get_pc(); let pc = state.get_pc();
program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?; 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 } => { BuiltinOp::Move { dst, src } => {
state.clear_status(); state.clear_status();
let val = state.read(*src)?; let val = state.read(*src)?;

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

@ -7,7 +7,8 @@ pub use eval_res::EvalRes;
use crate::asm::data::literal::Value; use crate::asm::data::literal::Value;
use crate::asm::data::Mask; use crate::asm::data::Mask;
use crate::asm::error::CrsnError; 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::asm::parse::arg_parser::TokenParser;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::run_thread::state::RunState; use crate::runtime::run_thread::state::RunState;
@ -25,10 +26,10 @@ pub enum ParseRes<'a, T> {
Unknown(TokenParser<'a>), Unknown(TokenParser<'a>),
} }
impl<'a> ParseRes<'a, Op> { impl<'a> ParseRes<'a, OpKind> {
/// Helper to construct an extension op /// Helper to construct an extension op
pub fn ext(op: impl OpTrait) -> Self { 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. /// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
/// ///
/// pcx is available on the arg_tokens parser /// 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) /// Parse a generic S-expression (non-op)
/// ///

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

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

@ -1,5 +1,5 @@
use crsn::asm::error::CrsnError; 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::asm::parse::arg_parser::TokenParser;
use crsn::module::{CrsnExtension, ParseRes}; use crsn::module::{CrsnExtension, ParseRes};
@ -21,7 +21,7 @@ impl CrsnExtension for ArithOps {
"arith" "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) parse::parse(keyword, args)
} }
} }

@ -1,12 +1,12 @@
use crsn::asm::data::{Rd, Wr}; use crsn::asm::data::{Rd, Wr};
use crsn::asm::error::CrsnError; 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::asm::parse::arg_parser::TokenParser;
use crsn::module::ParseRes; use crsn::module::ParseRes;
use crate::defs::ArithOp; 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 { Ok(ParseRes::ext(match keyword {
"cmp" => { "cmp" => {
ArithOp::Compare { ArithOp::Compare {

@ -2,7 +2,7 @@
extern crate log; extern crate log;
use crsn::asm::error::CrsnError; 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::asm::parse::arg_parser::TokenParser;
use crsn::module::{CrsnExtension, ParseRes}; use crsn::module::{CrsnExtension, ParseRes};
@ -24,7 +24,7 @@ impl CrsnExtension for ScreenOps {
"screen" "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) parse::parse(keyword, args)
} }
} }

@ -1,12 +1,12 @@
use crsn::asm::data::Rd; use crsn::asm::data::Rd;
use crsn::asm::error::CrsnError; 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::asm::parse::arg_parser::TokenParser;
use crsn::module::ParseRes; use crsn::module::ParseRes;
use crate::defs::ScreenOp; 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 { Ok(ParseRes::ext(match keyword {
"sc-init" => { "sc-init" => {
ScreenOp::ScreenInit { ScreenOp::ScreenInit {

@ -1,6 +1,6 @@
use crsn::asm::data::literal::Value; use crsn::asm::data::literal::Value;
use crsn::asm::error::CrsnError; 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::asm::parse::arg_parser::TokenParser;
use crsn::module::{CrsnExtension, ParseRes}; use crsn::module::{CrsnExtension, ParseRes};
use crsn::runtime::fault::Fault; use crsn::runtime::fault::Fault;
@ -24,7 +24,7 @@ impl CrsnExtension for StackOps {
"stacks" "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) parse::parse(keyword, args)
} }

@ -1,11 +1,11 @@
use crsn::asm::error::CrsnError; 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::asm::parse::arg_parser::TokenParser;
use crsn::module::ParseRes; use crsn::module::ParseRes;
use crate::defs::StackOp; 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 { Ok(ParseRes::ext(match keyword {
"stack" => { "stack" => {
StackOp::NewStack { StackOp::NewStack {

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

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

Loading…
Cancel
Save