From f015104b95ef2e692b4fd501f894f01be800c074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 26 Sep 2020 00:29:33 +0200 Subject: [PATCH] re-arrange modules, add "plug-in" system so instructions can be defined in multiple crates --- Cargo.lock | 73 ++- Cargo.toml | 6 +- asm/Cargo.toml | 11 - asm/src/parse/parse_cond.rs | 19 - asm/src/parse/parse_op.rs | 516 ------------------ asm/src/parse/parse_routines.rs | 22 - crsn/Cargo.toml | 11 +- {asm/src => crsn/src/asm}/data/literal.rs | 0 {asm/src => crsn/src/asm}/data/mask.rs | 2 +- {asm/src => crsn/src/asm}/data/mod.rs | 2 +- {asm/src => crsn/src/asm}/data/reg.rs | 2 +- {asm/src => crsn/src/asm}/error.rs | 6 +- {asm/src => crsn/src/asm}/instr/cond.rs | 3 +- {asm/src => crsn/src/asm}/instr/flatten.rs | 8 +- {asm/src => crsn/src/asm}/instr/mod.rs | 6 +- {asm/src => crsn/src/asm}/instr/op.rs | 53 +- asm/src/lib.rs => crsn/src/asm/mod.rs | 17 +- {asm/src => crsn/src/asm}/parse/mod.rs | 15 +- crsn/src/asm/parse/parse_cond.rs | 20 + {asm/src => crsn/src/asm}/parse/parse_data.rs | 8 +- .../src => crsn/src/asm}/parse/parse_instr.rs | 17 +- crsn/src/asm/parse/parse_op.rs | 109 ++++ crsn/src/asm/parse/parse_routines.rs | 23 + .../src => crsn/src/asm}/parse/sexp_expect.rs | 2 +- {asm/src => crsn/src/asm}/patches/mod.rs | 0 .../src => crsn/src/asm}/patches/sexp_is_a.rs | 0 .../src/asm}/patches/try_remove.rs | 0 crsn/src/lib.rs | 8 + crsn/src/runtime/exec/mod.rs | 131 +++++ {runtime/src => crsn/src/runtime}/fault.rs | 7 +- {runtime/src => crsn/src/runtime}/frame.rs | 9 +- .../src => crsn/src/runtime}/frame/status.rs | 4 +- {runtime/src => crsn/src/runtime}/mlock.rs | 6 +- runtime/src/lib.rs => crsn/src/runtime/mod.rs | 3 - {runtime/src => crsn/src/runtime}/program.rs | 7 +- .../src => crsn/src/runtime}/run_thread.rs | 11 +- {runtime/src => crsn/src/runtime}/span.rs | 2 +- {runtime/src => crsn/src/runtime}/sparse.rs | 0 {runtime => crsn_arith}/Cargo.toml | 7 +- crsn_arith/src/defs.rs | 28 + .../src/exec/mod.rs => crsn_arith/src/exec.rs | 166 +----- crsn_arith/src/lib.rs | 6 + crsn_arith/src/parse.rs | 452 +++++++++++++++ launcher/Cargo.toml | 16 + {crsn => launcher}/src/main.rs | 13 +- 45 files changed, 984 insertions(+), 843 deletions(-) delete mode 100644 asm/Cargo.toml delete mode 100644 asm/src/parse/parse_cond.rs delete mode 100644 asm/src/parse/parse_op.rs delete mode 100644 asm/src/parse/parse_routines.rs rename {asm/src => crsn/src/asm}/data/literal.rs (100%) rename {asm/src => crsn/src/asm}/data/mask.rs (97%) rename {asm/src => crsn/src/asm}/data/mod.rs (99%) rename {asm/src => crsn/src/asm}/data/reg.rs (97%) rename {asm/src => crsn/src/asm}/error.rs (93%) rename {asm/src => crsn/src/asm}/instr/cond.rs (99%) rename {asm/src => crsn/src/asm}/instr/flatten.rs (94%) rename {asm/src => crsn/src/asm}/instr/mod.rs (80%) rename {asm/src => crsn/src/asm}/instr/op.rs (64%) rename asm/src/lib.rs => crsn/src/asm/mod.rs (96%) rename {asm/src => crsn/src/asm}/parse/mod.rs (58%) create mode 100644 crsn/src/asm/parse/parse_cond.rs rename {asm/src => crsn/src/asm}/parse/parse_data.rs (92%) rename {asm/src => crsn/src/asm}/parse/parse_instr.rs (65%) create mode 100644 crsn/src/asm/parse/parse_op.rs create mode 100644 crsn/src/asm/parse/parse_routines.rs rename {asm/src => crsn/src/asm}/parse/sexp_expect.rs (98%) rename {asm/src => crsn/src/asm}/patches/mod.rs (100%) rename {asm/src => crsn/src/asm}/patches/sexp_is_a.rs (100%) rename {asm/src => crsn/src/asm}/patches/try_remove.rs (100%) create mode 100644 crsn/src/lib.rs create mode 100644 crsn/src/runtime/exec/mod.rs rename {runtime/src => crsn/src/runtime}/fault.rs (89%) rename {runtime/src => crsn/src/runtime}/frame.rs (95%) rename {runtime/src => crsn/src/runtime}/frame/status.rs (97%) rename {runtime/src => crsn/src/runtime}/mlock.rs (95%) rename runtime/src/lib.rs => crsn/src/runtime/mod.rs (87%) rename {runtime/src => crsn/src/runtime}/program.rs (95%) rename {runtime/src => crsn/src/runtime}/run_thread.rs (87%) rename {runtime/src => crsn/src/runtime}/span.rs (96%) rename {runtime/src => crsn/src/runtime}/sparse.rs (100%) rename {runtime => crsn_arith}/Cargo.toml (70%) create mode 100644 crsn_arith/src/defs.rs rename runtime/src/exec/mod.rs => crsn_arith/src/exec.rs (54%) create mode 100644 crsn_arith/src/lib.rs create mode 100644 crsn_arith/src/parse.rs create mode 100644 launcher/Cargo.toml rename {crsn => launcher}/src/main.rs (81%) diff --git a/Cargo.lock b/Cargo.lock index 89a1407..0040b5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,15 +6,6 @@ version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" -[[package]] -name = "asm" -version = "0.1.0" -dependencies = [ - "anyhow", - "sexp", - "thiserror", -] - [[package]] name = "atty" version = "0.2.14" @@ -65,13 +56,48 @@ name = "crsn" version = "0.1.0" dependencies = [ "anyhow", - "asm", + "dyn-clonable", "log", - "runtime", - "simple_logger", + "num-traits", + "sexp", "thiserror", ] +[[package]] +name = "crsn_arith" +version = "0.1.0" +dependencies = [ + "crsn", + "num-traits", +] + +[[package]] +name = "dyn-clonable" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +dependencies = [ + "dyn-clonable-impl", + "dyn-clone", +] + +[[package]] +name = "dyn-clonable-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dyn-clone" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c53dc3a653e0f64081026e4bf048d48fec9fce90c66e8326ca7292df0ff2d82" + [[package]] name = "hermit-abi" version = "0.1.16" @@ -81,6 +107,18 @@ dependencies = [ "libc", ] +[[package]] +name = "launcher" +version = "0.1.0" +dependencies = [ + "anyhow", + "crsn", + "crsn_arith", + "log", + "simple_logger", + "thiserror", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -139,17 +177,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "runtime" -version = "0.1.0" -dependencies = [ - "anyhow", - "asm", - "log", - "num-traits", - "thiserror", -] - [[package]] name = "sexp" version = "1.1.4" diff --git a/Cargo.toml b/Cargo.toml index 3a297ed..9299fd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] members = [ - "asm", - "runtime", - "crsn" + "launcher", + "crsn", + "crsn_arith", ] diff --git a/asm/Cargo.toml b/asm/Cargo.toml deleted file mode 100644 index 1d75c30..0000000 --- a/asm/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "asm" -version = "0.1.0" -authors = ["Ondřej Hruška "] -edition = "2018" -publish = false - -[dependencies] -sexp = "1.1.4" -thiserror = "1.0.20" -anyhow = "1.0.32" diff --git a/asm/src/parse/parse_cond.rs b/asm/src/parse/parse_cond.rs deleted file mode 100644 index b505308..0000000 --- a/asm/src/parse/parse_cond.rs +++ /dev/null @@ -1,19 +0,0 @@ -use sexp::Sexp; - -use crate::error::Error; -use crate::instr::{Cond, Instr, cond}; -use crate::parse::parse_instr::parse_instructions; -use crate::parse::sexp_expect::{expect_list, expect_string_atom}; -use crate::patches::TryRemove; - -pub fn parse_cond_branch(tok: Sexp) -> Result<(Cond, Vec), Error> { - let mut list = expect_list(Some(tok), false)?; - let kw = expect_string_atom(list.try_remove(0))?; - - if !kw.ends_with('?') { - return Err(Error::Parse(format!("Condition must end with '?': {}", kw).into())); - } - - Ok((cond::parse_cond(&kw)?, parse_instructions(list)?)) -} - diff --git a/asm/src/parse/parse_op.rs b/asm/src/parse/parse_op.rs deleted file mode 100644 index e7e7d7d..0000000 --- a/asm/src/parse/parse_op.rs +++ /dev/null @@ -1,516 +0,0 @@ -use sexp::Sexp; - -use crate::data::{Rd, Wr}; -use crate::data::literal::{Label, RoutineName}; -use crate::error::Error; -use crate::instr::{HLOp, Op}; -use crate::instr::cond::parse_cond; -use crate::parse::parse_data::{parse_label, parse_rd, parse_wr}; -use crate::parse::sexp_expect::expect_string_atom; - -pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: impl ExactSizeIterator + Clone) -> Result { - Ok(match keyword { - "j" => { - let dest = parse_label(arg_tokens.next())?; - if far { - HLOp::L(Op::FarJump(dest)) - } else { - HLOp::Jump(dest) - } - } - - "call" => { - let dest = RoutineName(expect_string_atom(arg_tokens.next())?); - - let mut args = vec![]; - for t in arg_tokens { - args.push(parse_rd(Some(t))?); - } - HLOp::L(Op::Call(dest, args)) - } - - "ret" => { - let mut args = vec![]; - for t in arg_tokens { - args.push(parse_rd(Some(t))?); - } - HLOp::L(Op::Ret(args)) - } - - "routine" => { - let dest = RoutineName(expect_string_atom(arg_tokens.next())?); - HLOp::L(Op::Routine(dest)) - } - - "s" => { - HLOp::L(Op::Skip(parse_rd(arg_tokens.next())?)) - } - - "sif" => { - let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?; - let offs = parse_rd(arg_tokens.next())?; - HLOp::L(Op::SkipIf(cond, offs)) - } - - "jif" => { - let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?; - let dest = parse_label(arg_tokens.next())?; - HLOp::JumpIf(cond, dest) - } - - "barrier" => { - HLOp::L(Op::Barrier(match arg_tokens.next() { - None => None, - Some(s) => Some(expect_string_atom(Some(s))?.into()), - })) - } - - "fault" => { - HLOp::L(Op::Fault(match arg_tokens.next() { - None => None, - Some(s) => Some(expect_string_atom(Some(s))?.into()), - })) - } - - "ld" => { - HLOp::L(Op::Move { - dst: parse_wr(arg_tokens.next())?, - src: parse_rd(arg_tokens.next())?, - }) - } - - "cmp" => { - HLOp::L(Op::Compare { - a: parse_rd(arg_tokens.next())?, - b: parse_rd(arg_tokens.next())?, - }) - } - - "tst" => { - let arg = parse_rd(arg_tokens.next())?; - HLOp::L(Op::Test { a: arg }) - } - - "inc" => { - let dst = parse_wr(arg_tokens.next())?; - HLOp::L(Op::Add { - dst, - a: dst.as_rd(), - b: Rd::immediate(1), - }) - } - - "dec" => { - let dst = parse_wr(arg_tokens.next())?; - HLOp::L(Op::Sub { - dst, - a: dst.as_rd(), - b: Rd::immediate(1), - }) - } - - "add" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Add { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - b: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Add { - dst, - a: dst.as_rd(), - b: parse_rd(arg_tokens.next())?, - } - } - _ => { - return Err(Error::Parse("Add requires 2 or 3 arguments".into())); - } - }) - } - - "sub" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Sub { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - b: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Sub { - dst, - a: dst.as_rd(), - b: parse_rd(arg_tokens.next())?, - } - } - _ => { - return Err(Error::Parse("Sub requires 2 or 3 arguments".into())); - } - }) - } - - "mul" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Mul { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - b: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Mul { - dst, - a: dst.as_rd(), - b: parse_rd(arg_tokens.next())?, - } - } - _ => { - return Err(Error::Parse("Mul requires 2 or 3 arguments".into())); - } - }) - } - - "divr" => { - HLOp::L(match arg_tokens.len() { - 3 => { - let dst = parse_wr(arg_tokens.next())?; - let rem = parse_wr(arg_tokens.next())?; - let div = parse_rd(arg_tokens.next())?; - Op::Div { - dst, - rem, - a: dst.as_rd(), - div, - } - } - 4 => { - Op::Div { - dst: parse_wr(arg_tokens.next())?, - rem: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - div: parse_rd(arg_tokens.next())?, - } - } - _ => { - return Err(Error::Parse("DivR requires 3 or 4 arguments".into())); - } - }) - } - - "div" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Div { - dst: parse_wr(arg_tokens.next())?, - rem: Wr::discard(), - a: parse_rd(arg_tokens.next())?, - div: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - let div = parse_rd(arg_tokens.next())?; - Op::Div { - dst, - rem: Wr::discard(), - a: dst.as_rd(), - div, - } - } - _ => { - return Err(Error::Parse("Div requires 2 or 3 arguments".into())); - } - }) - } - - "mod" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Mod { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - div: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - let div = parse_rd(arg_tokens.next())?; - Op::Mod { - dst, - a: dst.as_rd(), - div, - } - } - _ => { - return Err(Error::Parse("Mod requires 2 or 3 arguments".into())); - } - }) - } - - "and" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::And { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - b: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::And { - dst, - a: dst.as_rd(), - b: parse_rd(arg_tokens.next())?, - } - } - _ => { - return Err(Error::Parse("And requires 2 or 3 arguments".into())); - } - }) - } - - "or" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Or { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - b: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Or { - dst, - a: dst.as_rd(), - b: parse_rd(arg_tokens.next())?, - } - } - _ => { - return Err(Error::Parse("Or requires 2 or 3 arguments".into())); - } - }) - } - - "xor" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Xor { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - b: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Xor { - dst, - a: dst.as_rd(), - b: parse_rd(arg_tokens.next())?, - } - } - _ => { - return Err(Error::Parse("Xor requires 2 or 3 arguments".into())); - } - }) - } - - "cpl" => { - HLOp::L(match arg_tokens.len() { - 2 => { - Op::Cpl { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - } - } - 1 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Cpl { - dst, - a: dst.as_rd(), - } - } - _ => { - return Err(Error::Parse("Cpl requires 1 or 2 arguments".into())); - } - }) - } - - "rol" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Rol { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - n: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Rol { - dst, - a: dst.as_rd(), - n: parse_rd(arg_tokens.next())?, - } - } - 1 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Rol { - dst, - a: dst.as_rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(Error::Parse("Rol requires 1, 2 or 3 arguments".into())); - } - }) - } - - "ror" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Ror { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - n: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Ror { - dst, - a: dst.as_rd(), - n: parse_rd(arg_tokens.next())?, - } - } - 1 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Ror { - dst, - a: dst.as_rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(Error::Parse("Ror requires 1, 2 or 3 arguments".into())); - } - }) - } - - "lsl" | "asl" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Lsl { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - n: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Lsl { - dst, - a: dst.as_rd(), - n: parse_rd(arg_tokens.next())?, - } - } - 1 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Lsl { - dst, - a: dst.as_rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(Error::Parse("Lsl requires 1, 2 or 3 arguments".into())); - } - }) - } - - "lsr" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Lsr { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - n: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Lsr { - dst, - a: dst.as_rd(), - n: parse_rd(arg_tokens.next())?, - } - } - 1 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Lsr { - dst, - a: dst.as_rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(Error::Parse("Lsr requires 1, 2 or 3 arguments".into())); - } - }) - } - - "asr" => { - HLOp::L(match arg_tokens.len() { - 3 => { - Op::Asr { - dst: parse_wr(arg_tokens.next())?, - a: parse_rd(arg_tokens.next())?, - n: parse_rd(arg_tokens.next())?, - } - } - 2 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Asr { - dst, - a: dst.as_rd(), - n: parse_rd(arg_tokens.next())?, - } - } - 1 => { - let dst = parse_wr(arg_tokens.next())?; - Op::Asr { - dst, - a: dst.as_rd(), - n: Rd::immediate(1), - } - } - _ => { - return Err(Error::Parse("Asr requires 1, 2 or 3 arguments".into())); - } - }) - } - - other => { - if let Some(label) = other.strip_prefix(':') { - let label = Label::Named(label.to_string()); - if far { - HLOp::L(Op::FarLabel(label)) - } else { - HLOp::Label(label) - } - } else { - return Err(Error::Parse(format!("Unknown instruction: {}", other).into())); - } - } - }) -} diff --git a/asm/src/parse/parse_routines.rs b/asm/src/parse/parse_routines.rs deleted file mode 100644 index 0c79a21..0000000 --- a/asm/src/parse/parse_routines.rs +++ /dev/null @@ -1,22 +0,0 @@ -use sexp::Sexp; - -use crate::data::literal::RoutineName; -use crate::error::Error; -use crate::instr::Routine; -use crate::parse::parse_instr::parse_instructions; -use crate::parse::sexp_expect::{expect_list, expect_string_atom}; -use crate::patches::TryRemove; - -pub fn parse_routines(routines: Vec) -> Result, Error> { - let mut parsed = vec![]; - for rt in routines { - let mut def = expect_list(Some(rt), false)?; - let name = expect_string_atom(def.try_remove(0))?; - let body = parse_instructions(def)?; - parsed.push(Routine { - name: RoutineName(name), - body, - }) - } - Ok(parsed) -} diff --git a/crsn/Cargo.toml b/crsn/Cargo.toml index 7173874..c060343 100644 --- a/crsn/Cargo.toml +++ b/crsn/Cargo.toml @@ -3,13 +3,12 @@ name = "crsn" version = "0.1.0" authors = ["Ondřej Hruška "] edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +publish = false [dependencies] -asm = { path = "../asm" } -runtime = { path = "../runtime" } -simple_logger = "1.9.0" -log = "0.4.11" +sexp = "1.1.4" thiserror = "1.0.20" anyhow = "1.0.32" +dyn-clonable = "0.9.0" +log = "0.4.11" +num-traits = "0.2.12" diff --git a/asm/src/data/literal.rs b/crsn/src/asm/data/literal.rs similarity index 100% rename from asm/src/data/literal.rs rename to crsn/src/asm/data/literal.rs diff --git a/asm/src/data/mask.rs b/crsn/src/asm/data/mask.rs similarity index 97% rename from asm/src/data/mask.rs rename to crsn/src/asm/data/mask.rs index 1753ded..e56d598 100644 --- a/asm/src/data/mask.rs +++ b/crsn/src/asm/data/mask.rs @@ -1,6 +1,6 @@ //! Mask applied to a data source or destination -use crate::error::AsmError; +use crate::asm::error::AsmError; /// Bit mask to apply to a value #[derive(Debug, Clone, Copy, Eq, PartialEq)] diff --git a/asm/src/data/mod.rs b/crsn/src/asm/data/mod.rs similarity index 99% rename from asm/src/data/mod.rs rename to crsn/src/asm/data/mod.rs index 1103e1e..6fe35d7 100644 --- a/asm/src/data/mod.rs +++ b/crsn/src/asm/data/mod.rs @@ -6,7 +6,7 @@ use literal::Addr; pub use mask::Mask; pub use reg::Register; -use crate::data::literal::{as_signed, Value}; +use crate::asm::data::literal::{as_signed, Value}; use super::error::AsmError; diff --git a/asm/src/data/reg.rs b/crsn/src/asm/data/reg.rs similarity index 97% rename from asm/src/data/reg.rs rename to crsn/src/asm/data/reg.rs index 3554c09..d9333b8 100644 --- a/asm/src/data/reg.rs +++ b/crsn/src/asm/data/reg.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use crate::error::Error; +use crate::asm::error::Error; /// Register name #[derive(Debug, Clone, Copy, Eq, PartialEq)] diff --git a/asm/src/error.rs b/crsn/src/asm/error.rs similarity index 93% rename from asm/src/error.rs rename to crsn/src/asm/error.rs index f8af247..dc89b9e 100644 --- a/asm/src/error.rs +++ b/crsn/src/asm/error.rs @@ -2,9 +2,9 @@ use std::borrow::Cow; use thiserror::Error; -use crate::data::{Mask, Register}; -use crate::data::literal::Label; -use crate::instr::Cond; +use crate::asm::data::{Mask, Register}; +use crate::asm::data::literal::Label; +use crate::asm::instr::Cond; /// csn_asm unified error type #[derive(Error, Debug)] diff --git a/asm/src/instr/cond.rs b/crsn/src/asm/instr/cond.rs similarity index 99% rename from asm/src/instr/cond.rs rename to crsn/src/asm/instr/cond.rs index 5e4cae9..d3bc847 100644 --- a/asm/src/instr/cond.rs +++ b/crsn/src/asm/instr/cond.rs @@ -1,6 +1,7 @@ use std::fmt::{self, Display, Formatter}; use std::ops::Not; -use crate::error::Error; + +use crate::asm::error::Error; /// Condition flag #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] diff --git a/asm/src/instr/flatten.rs b/crsn/src/asm/instr/flatten.rs similarity index 94% rename from asm/src/instr/flatten.rs rename to crsn/src/asm/instr/flatten.rs index 001d22a..6c68079 100644 --- a/asm/src/instr/flatten.rs +++ b/crsn/src/asm/instr/flatten.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::sync::atomic::AtomicU32; -use crate::data::{Rd, SrcDisp}; -use crate::data::literal::{Label, Value}; -use crate::error::{AsmError, Error}; -use crate::instr::{Cond, HLOp, Instr, Op, Routine}; +use crate::asm::data::{Rd, SrcDisp}; +use crate::asm::data::literal::{Label, Value}; +use crate::asm::error::{AsmError, Error}; +use crate::asm::instr::{Cond, HLOp, Instr, Op, Routine}; /// A trait for something that can turn into multiple instructions pub trait Flatten { diff --git a/asm/src/instr/mod.rs b/crsn/src/asm/instr/mod.rs similarity index 80% rename from asm/src/instr/mod.rs rename to crsn/src/asm/instr/mod.rs index 66c9db5..2697af4 100644 --- a/asm/src/instr/mod.rs +++ b/crsn/src/asm/instr/mod.rs @@ -4,14 +4,14 @@ pub use flatten::lower; pub use op::HLOp; pub use op::Op; -use crate::data::literal::RoutineName; +use crate::asm::data::literal::RoutineName; -mod op; +pub mod op; pub mod cond; mod flatten; /// A higher-level instruction -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone)] pub struct Instr { pub op: HLOp, pub branches: Option)>>, diff --git a/asm/src/instr/op.rs b/crsn/src/asm/instr/op.rs similarity index 64% rename from asm/src/instr/op.rs rename to crsn/src/asm/instr/op.rs index 88ef47a..5f8429b 100644 --- a/asm/src/instr/op.rs +++ b/crsn/src/asm/instr/op.rs @@ -1,13 +1,22 @@ -use crate::data::{ +use std::fmt::Debug; + +use dyn_clonable::*; +use sexp::Sexp; + +use crate::asm::data::{ literal::DebugMsg, literal::Label, literal::RoutineName, Rd, Wr, }; -use crate::instr::Cond; +use crate::asm::error::Error; +use crate::asm::instr::Cond; +use crate::runtime::fault::Fault; +use crate::runtime::frame::{CallStack, StackFrame}; +use crate::runtime::program::Program; /// A higher level simple opration -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug)] pub enum HLOp { /// Mark a jump target. Label(Label), @@ -20,7 +29,7 @@ pub enum HLOp { } /// A low level instruction -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug)] pub enum Op { /// Do nothing Nop, @@ -45,32 +54,14 @@ pub enum Op { Barrier(Option), /// Generate a run-time fault with a debugger message Fault(Option), - + /// Copy value Move { dst: Wr, src: Rd }, - Test { a: Rd }, - Compare { a: Rd, b: Rd }, + /// Store runtime status to a register StoreStatus { dst: Wr }, + /// Load runtime status from a register LoadStatus { src: Rd }, - Add { dst: Wr, a: Rd, b: Rd }, - Sub { dst: Wr, a: Rd, b: Rd }, - Mul { dst: Wr, a: Rd, b: Rd }, - Div { dst: Wr, rem: Wr, a: Rd, div: Rd }, - // "Mod" is functionally equivalent to "Div" with the result discarded, - // but status flags are updated by the remainder - Mod { dst: Wr, a: Rd, div: Rd }, - - And { dst: Wr, a: Rd, b: Rd }, - Or { dst: Wr, a: Rd, b: Rd }, - Xor { dst: Wr, a: Rd, b: Rd }, - Cpl { dst: Wr, a: Rd }, - Rol { dst: Wr, a: Rd, n: Rd }, - // Rotate (with wrap-around) - Ror { dst: Wr, a: Rd, n: Rd }, - Lsl { dst: Wr, a: Rd, n: Rd }, - // Shift - Lsr { dst: Wr, a: Rd, n: Rd }, - Asr { dst: Wr, a: Rd, n: Rd }, + Extension(Box), } /// Make "into" work @@ -79,3 +70,13 @@ impl From for HLOp { HLOp::L(op) } } + +#[clonable] +pub trait OpTrait: Clone + Debug + Send + 'static { + fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<(), Fault>; +} + +#[clonable] +pub trait OpParser: Clone + Debug + Send + 'static { + fn parse_op(&self, keyword: &str, far: bool, arg_tokens: Vec) -> Result, Error>; +} diff --git a/asm/src/lib.rs b/crsn/src/asm/mod.rs similarity index 96% rename from asm/src/lib.rs rename to crsn/src/asm/mod.rs index f1e9c51..a8ae576 100644 --- a/asm/src/lib.rs +++ b/crsn/src/asm/mod.rs @@ -1,4 +1,5 @@ -use crate::instr::{lower, Op}; +use crate::asm::instr::{lower, Op}; +use crate::asm::instr::op::OpParser; pub mod data; pub mod error; @@ -7,8 +8,8 @@ pub mod parse; pub mod patches; /// Parse a program from string and assemble a low level instruction sequence from it. -pub fn assemble(source: &str) -> Result, error::Error> { - let parsed = parse::parse(source)?; +pub fn assemble(source: &str, parsers: &[Box]) -> Result, error::Error> { + let parsed = parse::parse(source, parsers)?; Ok(lower(parsed)?) } @@ -16,11 +17,11 @@ pub fn assemble(source: &str) -> Result, error::Error> { mod tests { use std::sync::atomic::AtomicU32; - use crate::data::{DstDisp, Rd, Register, SrcDisp, Wr}; - use crate::data::literal::{Addr, Label}; - use crate::instr::{Flatten, HLOp, Instr, lower, Op}; - use crate::instr::Cond; - use crate::parse::{parse, parse_instructions}; + use crate::asm::data::{DstDisp, Rd, Register, SrcDisp, Wr}; + use crate::asm::data::literal::{Addr, Label}; + use crate::asm::instr::{Flatten, HLOp, Instr, lower, Op}; + use crate::asm::instr::Cond; + use crate::asm::parse::{parse, parse_instructions}; #[test] fn test_parse_empty() { diff --git a/asm/src/parse/mod.rs b/crsn/src/asm/parse/mod.rs similarity index 58% rename from asm/src/parse/mod.rs rename to crsn/src/asm/parse/mod.rs index c9a2c2a..50244ac 100644 --- a/asm/src/parse/mod.rs +++ b/crsn/src/asm/parse/mod.rs @@ -3,21 +3,22 @@ use std::sync::atomic::AtomicU32; pub use parse_instr::parse_instructions; use parse_routines::parse_routines; -use crate::error::Error; -use crate::instr::{Flatten, HLOp, Routine}; -use crate::parse::sexp_expect::expect_list; +use crate::asm::error::Error; +use crate::asm::instr::{Flatten, HLOp, Routine}; +use crate::asm::instr::op::OpParser; +use crate::asm::parse::sexp_expect::expect_list; mod parse_cond; mod parse_instr; -mod parse_data; +pub mod parse_data; mod parse_routines; -mod sexp_expect; +pub mod sexp_expect; mod parse_op; -pub fn parse(source: &str) -> Result, Error> { +pub fn parse(source: &str, parsers: &[Box]) -> Result, Error> { let root = sexp::parse(source)?; - let subs: Vec = parse_routines(expect_list(Some(root), true)?)?; + let subs: Vec = parse_routines(expect_list(Some(root), true)?, parsers)?; let mut combined = vec![]; let label_num = AtomicU32::new(0); diff --git a/crsn/src/asm/parse/parse_cond.rs b/crsn/src/asm/parse/parse_cond.rs new file mode 100644 index 0000000..3d97580 --- /dev/null +++ b/crsn/src/asm/parse/parse_cond.rs @@ -0,0 +1,20 @@ +use sexp::Sexp; + +use crate::asm::error::Error; +use crate::asm::instr::{Cond, cond, Instr}; +use crate::asm::instr::op::OpParser; +use crate::asm::parse::parse_instr::parse_instructions; +use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom}; +use crate::asm::patches::TryRemove; + +pub fn parse_cond_branch(tok: Sexp, parsers: &[Box]) -> Result<(Cond, Vec), Error> { + let mut list = expect_list(Some(tok), false)?; + let kw = expect_string_atom(list.try_remove(0))?; + + if !kw.ends_with('?') { + return Err(Error::Parse(format!("Condition must end with '?': {}", kw).into())); + } + + Ok((cond::parse_cond(&kw)?, parse_instructions(list, parsers)?)) +} + diff --git a/asm/src/parse/parse_data.rs b/crsn/src/asm/parse/parse_data.rs similarity index 92% rename from asm/src/parse/parse_data.rs rename to crsn/src/asm/parse/parse_data.rs index 207ff61..e1c11a1 100644 --- a/asm/src/parse/parse_data.rs +++ b/crsn/src/asm/parse/parse_data.rs @@ -2,10 +2,10 @@ use std::convert::TryFrom; use sexp::{Atom, Sexp}; -use crate::data::{DataDisp, DstDisp, Rd, reg, SrcDisp, Wr}; -use crate::data::literal::{Addr, Label}; -use crate::error::Error; -use crate::parse::sexp_expect::expect_string_atom; +use crate::asm::data::{DataDisp, DstDisp, Rd, reg, SrcDisp, Wr}; +use crate::asm::data::literal::{Addr, Label}; +use crate::asm::error::Error; +use crate::asm::parse::sexp_expect::expect_string_atom; /// Parse a label pub fn parse_label(name: Option) -> Result { diff --git a/asm/src/parse/parse_instr.rs b/crsn/src/asm/parse/parse_instr.rs similarity index 65% rename from asm/src/parse/parse_instr.rs rename to crsn/src/asm/parse/parse_instr.rs index 551dc03..63b09e3 100644 --- a/asm/src/parse/parse_instr.rs +++ b/crsn/src/asm/parse/parse_instr.rs @@ -1,14 +1,15 @@ use sexp::Sexp; -use crate::error::Error; -use crate::instr::Instr; -use crate::parse::parse_cond::parse_cond_branch; -use crate::parse::sexp_expect::{expect_list, expect_string_atom}; -use crate::patches::SexpIsA; +use crate::asm::error::Error; +use crate::asm::instr::Instr; +use crate::asm::instr::op::OpParser; +use crate::asm::parse::parse_cond::parse_cond_branch; +use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom}; +use crate::asm::patches::SexpIsA; use super::parse_op::parse_op; -pub fn parse_instructions(instrs: Vec) -> Result, Error> { +pub fn parse_instructions(instrs: Vec, parsers: &[Box]) -> Result, Error> { let mut parsed = vec![]; for expr in instrs { let tokens = expect_list(Some(expr), false)?; @@ -32,7 +33,7 @@ pub fn parse_instructions(instrs: Vec) -> Result, Error> { let branches = { let mut branches = vec![]; for t in branch_tokens { - branches.push(parse_cond_branch(t)?); + branches.push(parse_cond_branch(t, parsers)?); } if branches.is_empty() { None @@ -42,7 +43,7 @@ pub fn parse_instructions(instrs: Vec) -> Result, Error> { }; parsed.push(Instr { - op: parse_op(name.as_str(), far, arg_tokens.into_iter())?, + op: parse_op(name.as_str(), far, arg_tokens, parsers)?, branches, }); } diff --git a/crsn/src/asm/parse/parse_op.rs b/crsn/src/asm/parse/parse_op.rs new file mode 100644 index 0000000..9936589 --- /dev/null +++ b/crsn/src/asm/parse/parse_op.rs @@ -0,0 +1,109 @@ +use sexp::Sexp; + +use crate::asm::data::literal::{Label, RoutineName}; +use crate::asm::error::{AsmError, Error}; +use crate::asm::instr::{HLOp, Op}; +use crate::asm::instr::cond::parse_cond; +use crate::asm::instr::op::OpParser; +use crate::asm::parse::parse_data::{parse_label, parse_rd, parse_wr}; +use crate::asm::parse::sexp_expect::expect_string_atom; + +pub fn parse_op(keyword: &str, far: bool, arg_tokens_slice: Vec, parsers: &[Box]) -> Result { + let mut arg_tokens = arg_tokens_slice.clone().into_iter(); + + Ok(match keyword { + "j" => { + let dest = parse_label(arg_tokens.next())?; + if far { + HLOp::L(Op::FarJump(dest)) + } else { + HLOp::Jump(dest) + } + } + + "call" => { + let dest = RoutineName(expect_string_atom(arg_tokens.next())?); + + let mut args = vec![]; + for t in arg_tokens { + args.push(parse_rd(Some(t))?); + } + HLOp::L(Op::Call(dest, args)) + } + + "ret" => { + let mut args = vec![]; + for t in arg_tokens { + args.push(parse_rd(Some(t))?); + } + HLOp::L(Op::Ret(args)) + } + + "routine" => { + let dest = RoutineName(expect_string_atom(arg_tokens.next())?); + HLOp::L(Op::Routine(dest)) + } + + "s" => { + HLOp::L(Op::Skip(parse_rd(arg_tokens.next())?)) + } + + "sif" => { + let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?; + let offs = parse_rd(arg_tokens.next())?; + HLOp::L(Op::SkipIf(cond, offs)) + } + + "jif" => { + let cond = parse_cond(&expect_string_atom(arg_tokens.next())?)?; + let dest = parse_label(arg_tokens.next())?; + HLOp::JumpIf(cond, dest) + } + + "barrier" => { + HLOp::L(Op::Barrier(match arg_tokens.next() { + None => None, + Some(s) => Some(expect_string_atom(Some(s))?.into()), + })) + } + + "fault" => { + HLOp::L(Op::Fault(match arg_tokens.next() { + None => None, + Some(s) => Some(expect_string_atom(Some(s))?.into()), + })) + } + + "ld" => { + HLOp::L(Op::Move { + dst: parse_wr(arg_tokens.next())?, + src: parse_rd(arg_tokens.next())?, + }) + } + + other => { + if let Some(label) = other.strip_prefix(':') { + let label = Label::Named(label.to_string()); + if far { + HLOp::L(Op::FarLabel(label)) + } else { + HLOp::Label(label) + } + } else { + for p in parsers { + match p.parse_op(keyword, far, arg_tokens_slice.clone()) { + Ok(op) => return Ok(HLOp::L(Op::Extension(op))), + Err(Error::Asm(AsmError::UnknownInstruction)) => { + /* ok, try another */ + } + Err(other) => { + return Err(other); + } + } + } + + return Err(Error::Parse(format!("Unknown instruction: {}", other).into())); + } + } + }) +} diff --git a/crsn/src/asm/parse/parse_routines.rs b/crsn/src/asm/parse/parse_routines.rs new file mode 100644 index 0000000..03fd98b --- /dev/null +++ b/crsn/src/asm/parse/parse_routines.rs @@ -0,0 +1,23 @@ +use sexp::Sexp; + +use crate::asm::data::literal::RoutineName; +use crate::asm::error::Error; +use crate::asm::instr::op::OpParser; +use crate::asm::instr::Routine; +use crate::asm::parse::parse_instr::parse_instructions; +use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom}; +use crate::asm::patches::TryRemove; + +pub fn parse_routines(routines: Vec, parsers: &[Box]) -> Result, Error> { + let mut parsed = vec![]; + for rt in routines { + let mut def = expect_list(Some(rt), false)?; + let name = expect_string_atom(def.try_remove(0))?; + let body = parse_instructions(def, parsers)?; + parsed.push(Routine { + name: RoutineName(name), + body, + }) + } + Ok(parsed) +} diff --git a/asm/src/parse/sexp_expect.rs b/crsn/src/asm/parse/sexp_expect.rs similarity index 98% rename from asm/src/parse/sexp_expect.rs rename to crsn/src/asm/parse/sexp_expect.rs index e6bd1b4..55c84e4 100644 --- a/asm/src/parse/sexp_expect.rs +++ b/crsn/src/asm/parse/sexp_expect.rs @@ -1,6 +1,6 @@ use sexp::{Atom, Sexp}; -use crate::error::Error; +use crate::asm::error::Error; pub fn expect_list(expr: Option, allow_empty: bool) -> Result, Error> { if let Some(expr) = expr { diff --git a/asm/src/patches/mod.rs b/crsn/src/asm/patches/mod.rs similarity index 100% rename from asm/src/patches/mod.rs rename to crsn/src/asm/patches/mod.rs diff --git a/asm/src/patches/sexp_is_a.rs b/crsn/src/asm/patches/sexp_is_a.rs similarity index 100% rename from asm/src/patches/sexp_is_a.rs rename to crsn/src/asm/patches/sexp_is_a.rs diff --git a/asm/src/patches/try_remove.rs b/crsn/src/asm/patches/try_remove.rs similarity index 100% rename from asm/src/patches/try_remove.rs rename to crsn/src/asm/patches/try_remove.rs diff --git a/crsn/src/lib.rs b/crsn/src/lib.rs new file mode 100644 index 0000000..7b3bc71 --- /dev/null +++ b/crsn/src/lib.rs @@ -0,0 +1,8 @@ +#[macro_use] +extern crate log; + +pub use sexp; + +pub mod asm; +pub mod runtime; + diff --git a/crsn/src/runtime/exec/mod.rs b/crsn/src/runtime/exec/mod.rs new file mode 100644 index 0000000..b7037e8 --- /dev/null +++ b/crsn/src/runtime/exec/mod.rs @@ -0,0 +1,131 @@ +use crate::asm::data::literal::Addr; +use crate::asm::instr::Op; +use crate::runtime::fault::Fault; +use crate::runtime::frame::StackFrame; +use crate::runtime::run_thread::RunThread; + +pub type CyclesSpent = usize; + +pub struct EvalRes { + pub cycles: u8, + pub advance: i64, +} + +impl RunThread { + // TODO unit tests + pub fn eval_op(&mut self) -> Result { + let mut cycles = 1; + let mut advance = 1; + + let frame = &mut self.frame; + + let op = self.program.read(frame.pc); + + debug!("------------------------"); + debug!("{} | {:?}", frame.pc, op); + + /* Operations can be given different execution times when run in slow mode. */ + /* Presently, all that do anything use 1 cycle. */ + + match op { + Op::Nop => {} + Op::FarLabel(_) | Op::Routine(_) => { + /* this is nop, but without any cost - just markers */ + cycles = 0; + } + Op::Barrier(msg) => { + return Err(Fault::Barrier { + msg: msg.clone().unwrap_or_else(|| "No msg".into()) + }); + } + Op::Fault(msg) => { + return Err(Fault::FaultInstr { + msg: msg.clone().unwrap_or_else(|| "No msg".into()) + }); + } + Op::FarJump(name) => { + debug!("Far jump to {}", name); + match self.program.find_far_label(name) { + Ok(pos) => { + debug!("label is at {}", pos); + self.frame.pc = pos; + } + Err(e) => { + return Err(e); + } + } + } + Op::Call(name, args) => { + debug!("Call routine {}", name); + match self.program.find_routine(name) { + Ok(pos) => { + debug!("routine is at {}", pos); + + let mut values = Vec::with_capacity(args.len()); + for arg in args { + values.push(self.frame.read(*arg)?); + } + + let mut frame2 = StackFrame::new(pos, &values); + std::mem::swap(&mut self.frame, &mut frame2); + self.call_stack.push(frame2); + advance = 0; + } + Err(e) => { + return Err(e); + } + } + } + Op::Ret(retvals) => { + match self.call_stack.pop() { + Some(previous) => { + let mut values = Vec::with_capacity(retvals.len()); + for arg in retvals { + values.push(frame.read(*arg)?); + } + *frame = previous; + frame.set_retvals(&values); + advance = 1; // advance past the call + } + None => { + return Err(Fault::CallStackUnderflow); + } + } + } + Op::Skip(val) => { + let steps = frame.read(*val)?; + advance = i64::from_ne_bytes(steps.to_ne_bytes()); + self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?; + } + Op::SkipIf(cond, val) => { + if frame.status.test(*cond) { + let steps = frame.read(*val)?; + advance = i64::from_ne_bytes(steps.to_ne_bytes()); + self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?; + } + } + Op::Move { dst, src } => { + frame.status.clear(); + let val = frame.read(*src)?; + frame.status.update(val); + frame.write(*dst, val)?; + } + Op::Extension(xop) => { + xop.execute(&self.program, &mut self.call_stack, frame)?; + } + Op::StoreStatus { dst } => { + let packed = frame.status.store(); + frame.write(*dst, packed)?; + } + Op::LoadStatus { src } => { + let x = frame.read(*src)?; + frame.status.load(x); + } + } + + Ok(EvalRes { + cycles, + advance, + }) + } +} diff --git a/runtime/src/fault.rs b/crsn/src/runtime/fault.rs similarity index 89% rename from runtime/src/fault.rs rename to crsn/src/runtime/fault.rs index 81ab773..4498342 100644 --- a/runtime/src/fault.rs +++ b/crsn/src/runtime/fault.rs @@ -1,10 +1,7 @@ use thiserror::Error; -// use super::span::MemorySpan; -// use crate::run_thread::ThreadToken; -// use crate::mlock::ClaimId; -use asm::data::literal::{DebugMsg, Label, RoutineName}; -use asm::data::Register; +use crate::asm::data::literal::{DebugMsg, Label, RoutineName}; +use crate::asm::data::Register; #[derive(Error, Debug)] pub enum Fault { diff --git a/runtime/src/frame.rs b/crsn/src/runtime/frame.rs similarity index 95% rename from runtime/src/frame.rs rename to crsn/src/runtime/frame.rs index 0617ca2..67680c3 100644 --- a/runtime/src/frame.rs +++ b/crsn/src/runtime/frame.rs @@ -1,13 +1,16 @@ -use asm::data::{DstDisp, Rd, Register, SrcDisp, Wr}; -use asm::data::literal::{Addr, Value}; use status::StatusFlags; -use crate::fault::Fault; +use crate::asm::data::{DstDisp, Rd, Register, SrcDisp, Wr}; +use crate::asm::data::literal::{Addr, Value}; + +use super::fault::Fault; mod status; pub const REG_COUNT: usize = 8; +pub type CallStack = Vec; + #[derive(Default, Clone, Debug)] pub struct StackFrame { /// Program counter, address of the executed instruction diff --git a/runtime/src/frame/status.rs b/crsn/src/runtime/frame/status.rs similarity index 97% rename from runtime/src/frame/status.rs rename to crsn/src/runtime/frame/status.rs index cf181fb..242a0c2 100644 --- a/runtime/src/frame/status.rs +++ b/crsn/src/runtime/frame/status.rs @@ -1,8 +1,8 @@ use std::fmt::{Display, Formatter}; use std::fmt; -use asm::data::literal::{is_negative, is_positive, Value}; -use asm::instr::Cond; +use crate::asm::data::literal::{is_negative, is_positive, Value}; +use crate::asm::instr::Cond; #[derive(Default, Clone, Debug)] pub struct StatusFlags { diff --git a/runtime/src/mlock.rs b/crsn/src/runtime/mlock.rs similarity index 95% rename from runtime/src/mlock.rs rename to crsn/src/runtime/mlock.rs index f984444..592571e 100644 --- a/runtime/src/mlock.rs +++ b/crsn/src/runtime/mlock.rs @@ -2,9 +2,9 @@ use std::fmt; use std::fmt::Formatter; use std::sync::atomic::{AtomicU32, Ordering}; -use crate::fault::Fault; -use crate::run_thread::ThreadToken; -use crate::span::MemorySpan; +use crate::runtime::fault::Fault; +use crate::runtime::run_thread::ThreadToken; +use crate::runtime::span::MemorySpan; /// Records memory claims and protects from illegal access #[derive(Debug, Default)] diff --git a/runtime/src/lib.rs b/crsn/src/runtime/mod.rs similarity index 87% rename from runtime/src/lib.rs rename to crsn/src/runtime/mod.rs index d8427f2..c89a37c 100644 --- a/runtime/src/lib.rs +++ b/crsn/src/runtime/mod.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate log; - pub mod run_thread; // pub mod mlock; // pub mod sparse; diff --git a/runtime/src/program.rs b/crsn/src/runtime/program.rs similarity index 95% rename from runtime/src/program.rs rename to crsn/src/runtime/program.rs index 85a3774..e172aa3 100644 --- a/runtime/src/program.rs +++ b/crsn/src/runtime/program.rs @@ -1,9 +1,8 @@ use std::collections::HashMap; -use asm::data::literal::{Addr, Label, RoutineName}; -use asm::instr::Op; - -use crate::fault::Fault; +use crate::asm::data::literal::{Addr, Label, RoutineName}; +use crate::asm::instr::Op; +use crate::runtime::fault::Fault; #[derive(Clone, Debug)] pub struct Program { diff --git a/runtime/src/run_thread.rs b/crsn/src/runtime/run_thread.rs similarity index 87% rename from runtime/src/run_thread.rs rename to crsn/src/runtime/run_thread.rs index 26d037c..146b050 100644 --- a/runtime/src/run_thread.rs +++ b/crsn/src/runtime/run_thread.rs @@ -1,11 +1,10 @@ use std::thread::JoinHandle; use std::time::Duration; -use asm::data::literal::Addr; - -use crate::exec::EvalRes; -use crate::frame::StackFrame; -use crate::program::Program; +use crate::asm::data::literal::Addr; +use crate::runtime::exec::EvalRes; +use crate::runtime::frame::{CallStack, StackFrame}; +use crate::runtime::program::Program; const CYCLE_TIME: Duration = Duration::from_millis(0); //const CYCLE_TIME : Duration = Duration::from_millis(100); @@ -19,7 +18,7 @@ pub struct RunThread { /// Active stack frame pub frame: StackFrame, /// Call stack - pub call_stack: Vec, + pub call_stack: CallStack, /// Program to run pub program: Program, } diff --git a/runtime/src/span.rs b/crsn/src/runtime/span.rs similarity index 96% rename from runtime/src/span.rs rename to crsn/src/runtime/span.rs index f20c720..e1a44ad 100644 --- a/runtime/src/span.rs +++ b/crsn/src/runtime/span.rs @@ -1,4 +1,4 @@ -use asm::data::literal::Addr; +use crate::asm::data::literal::Addr; #[derive(Debug, Clone, Copy)] pub struct MemorySpan { diff --git a/runtime/src/sparse.rs b/crsn/src/runtime/sparse.rs similarity index 100% rename from runtime/src/sparse.rs rename to crsn/src/runtime/sparse.rs diff --git a/runtime/Cargo.toml b/crsn_arith/Cargo.toml similarity index 70% rename from runtime/Cargo.toml rename to crsn_arith/Cargo.toml index 3321d8b..516c09c 100644 --- a/runtime/Cargo.toml +++ b/crsn_arith/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "runtime" +name = "crsn_arith" version = "0.1.0" authors = ["Ondřej Hruška "] edition = "2018" @@ -7,8 +7,5 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -asm = { path = "../asm" } -thiserror = "1.0.20" -anyhow = "1.0.32" -log = "0.4.11" +crsn = { path = "../crsn" } num-traits = "0.2.12" diff --git a/crsn_arith/src/defs.rs b/crsn_arith/src/defs.rs new file mode 100644 index 0000000..134cb0f --- /dev/null +++ b/crsn_arith/src/defs.rs @@ -0,0 +1,28 @@ +use crsn::asm::data::{Rd, Wr}; + +/// A low level instruction +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ArithOp { + Test { a: Rd }, + Compare { a: Rd, b: Rd }, + + Add { dst: Wr, a: Rd, b: Rd }, + Sub { dst: Wr, a: Rd, b: Rd }, + Mul { dst: Wr, a: Rd, b: Rd }, + Div { dst: Wr, rem: Wr, a: Rd, div: Rd }, + // "Mod" is functionally equivalent to "Div" with the result discarded, + // but status flags are updated by the remainder + Mod { dst: Wr, a: Rd, div: Rd }, + + And { dst: Wr, a: Rd, b: Rd }, + Or { dst: Wr, a: Rd, b: Rd }, + Xor { dst: Wr, a: Rd, b: Rd }, + Cpl { dst: Wr, a: Rd }, + Rol { dst: Wr, a: Rd, n: Rd }, + // Rotate (with wrap-around) + Ror { dst: Wr, a: Rd, n: Rd }, + Lsl { dst: Wr, a: Rd, n: Rd }, + // Shift + Lsr { dst: Wr, a: Rd, n: Rd }, + Asr { dst: Wr, a: Rd, n: Rd }, +} diff --git a/runtime/src/exec/mod.rs b/crsn_arith/src/exec.rs similarity index 54% rename from runtime/src/exec/mod.rs rename to crsn_arith/src/exec.rs index 8995fb0..c0ed51b 100644 --- a/runtime/src/exec/mod.rs +++ b/crsn_arith/src/exec.rs @@ -2,125 +2,22 @@ use std::ops::Rem; use num_traits::PrimInt; -use asm::data::literal::Addr; -use asm::instr::Op; +use crsn::asm::instr::op::OpTrait; +use crsn::runtime::fault::Fault; +use crsn::runtime::frame::{CallStack, StackFrame}; +use crsn::runtime::program::Program; -use crate::fault::Fault; -use crate::frame::StackFrame; -use crate::run_thread::RunThread; +use crate::defs::ArithOp; -pub type CyclesSpent = usize; - -pub struct EvalRes { - pub cycles: u8, - pub advance: i64, -} - -impl RunThread { - // TODO unit tests - pub fn eval_op(&mut self) -> Result { - let mut cycles = 1; - let mut advance = 1; - - let mut frame = &mut self.frame; - - let op = self.program.read(frame.pc); - - debug!("------------------------"); - debug!("{} | {:?}", frame.pc, op); - - /* Operations can be given different execution times when run in slow mode. */ - /* Presently, all that do anything use 1 cycle. */ - - match op { - Op::Nop => {} - Op::FarLabel(_) | Op::Routine(_) => { - /* this is nop, but without any cost - just markers */ - cycles = 0; - } - Op::Barrier(msg) => { - return Err(Fault::Barrier { - msg: msg.clone().unwrap_or_else(|| "No msg".into()) - }); - } - Op::Fault(msg) => { - return Err(Fault::FaultInstr { - msg: msg.clone().unwrap_or_else(|| "No msg".into()) - }); - } - Op::FarJump(name) => { - debug!("Far jump to {}", name); - match self.program.find_far_label(name) { - Ok(pos) => { - debug!("label is at {}", pos); - self.frame.pc = pos; - } - Err(e) => { - return Err(e); - } - } - } - Op::Call(name, args) => { - debug!("Call routine {}", name); - match self.program.find_routine(name) { - Ok(pos) => { - debug!("routine is at {}", pos); - - let mut values = Vec::with_capacity(args.len()); - for arg in args { - values.push(self.frame.read(*arg)?); - } - - let mut frame2 = StackFrame::new(pos, &values); - std::mem::swap(&mut self.frame, &mut frame2); - self.call_stack.push(frame2); - advance = 0; - } - Err(e) => { - return Err(e); - } - } - } - Op::Ret(retvals) => { - match self.call_stack.pop() { - Some(previous) => { - let mut values = Vec::with_capacity(retvals.len()); - for arg in retvals { - values.push(frame.read(*arg)?); - } - *frame = previous; - frame.set_retvals(&values); - advance = 1; // advance past the call - } - None => { - return Err(Fault::CallStackUnderflow); - } - } - } - Op::Skip(val) => { - let steps = frame.read(*val)?; - advance = i64::from_ne_bytes(steps.to_ne_bytes()); - self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?; - } - Op::SkipIf(cond, val) => { - if frame.status.test(*cond) { - let steps = frame.read(*val)?; - advance = i64::from_ne_bytes(steps.to_ne_bytes()); - self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?; - } - } - Op::Move { dst, src } => { - frame.status.clear(); - let val = frame.read(*src)?; - frame.status.update(val); - frame.write(*dst, val)?; - } - Op::Test { a } => { +impl OpTrait for ArithOp { + fn execute(&self, _program: &Program, _call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<(), Fault> { + match self { + ArithOp::Test { a } => { frame.status.clear(); let res = frame.read(*a)?; frame.status.update(res); } - Op::Compare { a, b } => { + ArithOp::Compare { a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; @@ -132,7 +29,7 @@ impl RunThread { frame.status.update(x); } } - Op::Add { dst, a, b } => { + ArithOp::Add { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; @@ -145,7 +42,7 @@ impl RunThread { frame.status.overflow = ov; frame.write(*dst, res)?; } - Op::Sub { dst, a, b } => { + ArithOp::Sub { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; @@ -158,7 +55,7 @@ impl RunThread { frame.status.overflow = ov; frame.write(*dst, res)?; } - Op::Mul { dst, a, b } => { + ArithOp::Mul { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; @@ -171,7 +68,7 @@ impl RunThread { frame.status.overflow = ov; frame.write(*dst, res)?; } - Op::Div { dst, rem, a, div } => { + ArithOp::Div { dst, rem, a, div } => { frame.status.clear(); let x = frame.read(*a)?; let d = frame.read(*div)?; @@ -189,7 +86,7 @@ impl RunThread { frame.write(*rem, remainder)?; } } - Op::Mod { dst, a, div } => { + ArithOp::Mod { dst, a, div } => { frame.status.clear(); let x = frame.read(*a)?; let d = frame.read(*div)?; @@ -206,7 +103,7 @@ impl RunThread { frame.write(*dst, remainder)?; } } - Op::And { dst, a, b } => { + ArithOp::And { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; @@ -214,7 +111,7 @@ impl RunThread { frame.status.update(res); frame.write(*dst, res)?; } - Op::Or { dst, a, b } => { + ArithOp::Or { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; @@ -222,7 +119,7 @@ impl RunThread { frame.status.update(res); frame.write(*dst, res)?; } - Op::Xor { dst, a, b } => { + ArithOp::Xor { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; @@ -230,14 +127,14 @@ impl RunThread { frame.status.update(res); frame.write(*dst, res)?; } - Op::Cpl { dst, a } => { + ArithOp::Cpl { dst, a } => { frame.status.clear(); let x = frame.read(*a)?; let res = !x; frame.status.update(res); frame.write(*dst, res)?; } - Op::Rol { dst, a, n } => { + ArithOp::Rol { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; @@ -249,7 +146,7 @@ impl RunThread { frame.write(*dst, res)?; } } - Op::Ror { dst, a, n } => { + ArithOp::Ror { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; @@ -261,7 +158,7 @@ impl RunThread { frame.write(*dst, res)?; } } - Op::Lsl { dst, a, n } => { + ArithOp::Lsl { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; @@ -269,7 +166,7 @@ impl RunThread { frame.status.update(res); frame.write(*dst, res)?; } - Op::Lsr { dst, a, n } => { + ArithOp::Lsr { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; @@ -277,7 +174,7 @@ impl RunThread { frame.status.update(res); frame.write(*dst, res)?; } - Op::Asr { dst, a, n } => { + ArithOp::Asr { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; @@ -289,19 +186,10 @@ impl RunThread { frame.write(*dst, res)?; } } - Op::StoreStatus { dst } => { - let packed = frame.status.store(); - frame.write(*dst, packed)?; - } - Op::LoadStatus { src } => { - let x = frame.read(*src)?; - frame.status.load(x); - } } - Ok(EvalRes { - cycles, - advance, - }) + Ok(()) } + // } + diff --git a/crsn_arith/src/lib.rs b/crsn_arith/src/lib.rs new file mode 100644 index 0000000..3913fd1 --- /dev/null +++ b/crsn_arith/src/lib.rs @@ -0,0 +1,6 @@ +pub use parse::ArithOpParser; + +mod defs; +mod parse; +mod exec; + diff --git a/crsn_arith/src/parse.rs b/crsn_arith/src/parse.rs new file mode 100644 index 0000000..9e2417b --- /dev/null +++ b/crsn_arith/src/parse.rs @@ -0,0 +1,452 @@ +use crsn::asm::data::{Rd, Wr}; +use crsn::asm::error::{AsmError, Error}; +use crsn::asm::instr::op::{OpParser, OpTrait}; +use crsn::asm::parse::parse_data::{parse_rd, parse_wr}; +use crsn::sexp::Sexp; + +use crate::defs::ArithOp; + +#[derive(Debug, Clone)] +pub struct ArithOpParser { + _internal: () +} + +impl ArithOpParser { + pub fn new() -> Box { + Box::new(Self { + _internal: () + }) + } +} + +impl OpParser for ArithOpParser { + fn parse_op(&self, keyword: &str, _far: bool, arg_tokens_sl: Vec) -> Result, Error> { + let mut arg_tokens = arg_tokens_sl.into_iter(); + Ok(Box::new(match keyword { + "cmp" => { + ArithOp::Compare { + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + + "tst" => { + let arg = parse_rd(arg_tokens.next())?; + ArithOp::Test { a: arg } + } + + "inc" => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Add { + dst, + a: dst.as_rd(), + b: Rd::immediate(1), + } + } + + "dec" => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Sub { + dst, + a: dst.as_rd(), + b: Rd::immediate(1), + } + } + + "add" => { + match arg_tokens.len() { + 3 => { + ArithOp::Add { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Add { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Add requires 2 or 3 arguments".into())); + } + } + } + + "sub" => { + match arg_tokens.len() { + 3 => { + ArithOp::Sub { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Sub { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Sub requires 2 or 3 arguments".into())); + } + } + } + + "mul" => { + match arg_tokens.len() { + 3 => { + ArithOp::Mul { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Mul { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Mul requires 2 or 3 arguments".into())); + } + } + } + + "divr" => { + match arg_tokens.len() { + 3 => { + let dst = parse_wr(arg_tokens.next())?; + let rem = parse_wr(arg_tokens.next())?; + let div = parse_rd(arg_tokens.next())?; + ArithOp::Div { + dst, + rem, + a: dst.as_rd(), + div, + } + } + 4 => { + ArithOp::Div { + dst: parse_wr(arg_tokens.next())?, + rem: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + div: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("DivR requires 3 or 4 arguments".into())); + } + } + } + + "div" => { + match arg_tokens.len() { + 3 => { + ArithOp::Div { + dst: parse_wr(arg_tokens.next())?, + rem: Wr::discard(), + a: parse_rd(arg_tokens.next())?, + div: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + let div = parse_rd(arg_tokens.next())?; + ArithOp::Div { + dst, + rem: Wr::discard(), + a: dst.as_rd(), + div, + } + } + _ => { + return Err(Error::Parse("Div requires 2 or 3 arguments".into())); + } + } + } + + "mod" => { + match arg_tokens.len() { + 3 => { + ArithOp::Mod { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + div: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + let div = parse_rd(arg_tokens.next())?; + ArithOp::Mod { + dst, + a: dst.as_rd(), + div, + } + } + _ => { + return Err(Error::Parse("Mod requires 2 or 3 arguments".into())); + } + } + } + + "and" => { + match arg_tokens.len() { + 3 => { + ArithOp::And { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::And { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("And requires 2 or 3 arguments".into())); + } + } + } + + "or" => { + match arg_tokens.len() { + 3 => { + ArithOp::Or { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Or { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Or requires 2 or 3 arguments".into())); + } + } + } + + "xor" => { + match arg_tokens.len() { + 3 => { + ArithOp::Xor { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + b: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Xor { + dst, + a: dst.as_rd(), + b: parse_rd(arg_tokens.next())?, + } + } + _ => { + return Err(Error::Parse("Xor requires 2 or 3 arguments".into())); + } + } + } + + "cpl" => { + match arg_tokens.len() { + 2 => { + ArithOp::Cpl { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Cpl { + dst, + a: dst.as_rd(), + } + } + _ => { + return Err(Error::Parse("Cpl requires 1 or 2 arguments".into())); + } + } + } + + "rol" => { + match arg_tokens.len() { + 3 => { + ArithOp::Rol { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Rol { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Rol { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Rol requires 1, 2 or 3 arguments".into())); + } + } + } + + "ror" => { + match arg_tokens.len() { + 3 => { + ArithOp::Ror { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Ror { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Ror { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Ror requires 1, 2 or 3 arguments".into())); + } + } + } + + "lsl" | "asl" => { + match arg_tokens.len() { + 3 => { + ArithOp::Lsl { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Lsl { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Lsl { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Lsl requires 1, 2 or 3 arguments".into())); + } + } + } + + "lsr" => { + match arg_tokens.len() { + 3 => { + ArithOp::Lsr { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Lsr { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Lsr { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Lsr requires 1, 2 or 3 arguments".into())); + } + } + } + + "asr" => { + match arg_tokens.len() { + 3 => { + ArithOp::Asr { + dst: parse_wr(arg_tokens.next())?, + a: parse_rd(arg_tokens.next())?, + n: parse_rd(arg_tokens.next())?, + } + } + 2 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Asr { + dst, + a: dst.as_rd(), + n: parse_rd(arg_tokens.next())?, + } + } + 1 => { + let dst = parse_wr(arg_tokens.next())?; + ArithOp::Asr { + dst, + a: dst.as_rd(), + n: Rd::immediate(1), + } + } + _ => { + return Err(Error::Parse("Asr requires 1, 2 or 3 arguments".into())); + } + } + } + + _other => { + return Err(Error::Asm(AsmError::UnknownInstruction)); + } + })) + } +} diff --git a/launcher/Cargo.toml b/launcher/Cargo.toml new file mode 100644 index 0000000..2d29b17 --- /dev/null +++ b/launcher/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "launcher" +version = "0.1.0" +authors = ["Ondřej Hruška "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +crsn = { path = "../crsn" } +crsn_arith = { path = "../crsn_arith" } + +simple_logger = "1.9.0" +log = "0.4.11" +thiserror = "1.0.20" +anyhow = "1.0.32" diff --git a/crsn/src/main.rs b/launcher/src/main.rs similarity index 81% rename from crsn/src/main.rs rename to launcher/src/main.rs index ddf2b50..abf871e 100644 --- a/crsn/src/main.rs +++ b/launcher/src/main.rs @@ -3,9 +3,10 @@ extern crate log; use simple_logger::SimpleLogger; -use asm::data::literal::Addr; -use runtime::program::Program; -use runtime::run_thread::{RunThread, ThreadToken}; +use crsn::asm::data::literal::Addr; +use crsn::runtime::program::Program; +use crsn::runtime::run_thread::{RunThread, ThreadToken}; +use crsn_arith::ArithOpParser; fn main() { SimpleLogger::new().init().unwrap(); @@ -61,7 +62,11 @@ fn main() { ) "; - let parsed = asm::assemble(program).unwrap(); + let parsers = vec![ + ArithOpParser::new() + ]; + + let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap(); debug!("---"); for op in &parsed {