forked from MightyPork/crsn
re-arrange modules, add "plug-in" system so instructions can be defined in multiple crates
This commit is contained in:
Generated
+50
-23
@@ -6,15 +6,6 @@ version = "1.0.32"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
|
checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "asm"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"sexp",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@@ -65,13 +56,48 @@ name = "crsn"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"asm",
|
"dyn-clonable",
|
||||||
"log",
|
"log",
|
||||||
"runtime",
|
"num-traits",
|
||||||
"simple_logger",
|
"sexp",
|
||||||
"thiserror",
|
"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]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
@@ -81,6 +107,18 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "launcher"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"crsn",
|
||||||
|
"crsn_arith",
|
||||||
|
"log",
|
||||||
|
"simple_logger",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -139,17 +177,6 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "runtime"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"asm",
|
|
||||||
"log",
|
|
||||||
"num-traits",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sexp"
|
name = "sexp"
|
||||||
version = "1.1.4"
|
version = "1.1.4"
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"asm",
|
"launcher",
|
||||||
"runtime",
|
"crsn",
|
||||||
"crsn"
|
"crsn_arith",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "asm"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
sexp = "1.1.4"
|
|
||||||
thiserror = "1.0.20"
|
|
||||||
anyhow = "1.0.32"
|
|
||||||
@@ -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<Instr>), 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)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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<Item=Sexp> + Clone) -> Result<HLOp, Error> {
|
|
||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -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<Sexp>) -> Result<Vec<Routine>, 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)
|
|
||||||
}
|
|
||||||
+5
-6
@@ -3,13 +3,12 @@ name = "crsn"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
publish = false
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
asm = { path = "../asm" }
|
sexp = "1.1.4"
|
||||||
runtime = { path = "../runtime" }
|
|
||||||
simple_logger = "1.9.0"
|
|
||||||
log = "0.4.11"
|
|
||||||
thiserror = "1.0.20"
|
thiserror = "1.0.20"
|
||||||
anyhow = "1.0.32"
|
anyhow = "1.0.32"
|
||||||
|
dyn-clonable = "0.9.0"
|
||||||
|
log = "0.4.11"
|
||||||
|
num-traits = "0.2.12"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! Mask applied to a data source or destination
|
//! Mask applied to a data source or destination
|
||||||
|
|
||||||
use crate::error::AsmError;
|
use crate::asm::error::AsmError;
|
||||||
|
|
||||||
/// Bit mask to apply to a value
|
/// Bit mask to apply to a value
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
@@ -6,7 +6,7 @@ use literal::Addr;
|
|||||||
pub use mask::Mask;
|
pub use mask::Mask;
|
||||||
pub use reg::Register;
|
pub use reg::Register;
|
||||||
|
|
||||||
use crate::data::literal::{as_signed, Value};
|
use crate::asm::data::literal::{as_signed, Value};
|
||||||
|
|
||||||
use super::error::AsmError;
|
use super::error::AsmError;
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::asm::error::Error;
|
||||||
|
|
||||||
/// Register name
|
/// Register name
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
@@ -2,9 +2,9 @@ use std::borrow::Cow;
|
|||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::data::{Mask, Register};
|
use crate::asm::data::{Mask, Register};
|
||||||
use crate::data::literal::Label;
|
use crate::asm::data::literal::Label;
|
||||||
use crate::instr::Cond;
|
use crate::asm::instr::Cond;
|
||||||
|
|
||||||
/// csn_asm unified error type
|
/// csn_asm unified error type
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
use crate::error::Error;
|
|
||||||
|
use crate::asm::error::Error;
|
||||||
|
|
||||||
/// Condition flag
|
/// Condition flag
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::atomic::AtomicU32;
|
use std::sync::atomic::AtomicU32;
|
||||||
|
|
||||||
use crate::data::{Rd, SrcDisp};
|
use crate::asm::data::{Rd, SrcDisp};
|
||||||
use crate::data::literal::{Label, Value};
|
use crate::asm::data::literal::{Label, Value};
|
||||||
use crate::error::{AsmError, Error};
|
use crate::asm::error::{AsmError, Error};
|
||||||
use crate::instr::{Cond, HLOp, Instr, Op, Routine};
|
use crate::asm::instr::{Cond, HLOp, Instr, Op, Routine};
|
||||||
|
|
||||||
/// 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 {
|
||||||
@@ -4,14 +4,14 @@ pub use flatten::lower;
|
|||||||
pub use op::HLOp;
|
pub use op::HLOp;
|
||||||
pub use op::Op;
|
pub use op::Op;
|
||||||
|
|
||||||
use crate::data::literal::RoutineName;
|
use crate::asm::data::literal::RoutineName;
|
||||||
|
|
||||||
mod op;
|
pub mod op;
|
||||||
pub mod cond;
|
pub mod cond;
|
||||||
mod flatten;
|
mod flatten;
|
||||||
|
|
||||||
/// A higher-level instruction
|
/// A higher-level instruction
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Instr {
|
pub struct Instr {
|
||||||
pub op: HLOp,
|
pub op: HLOp,
|
||||||
pub branches: Option<Vec<(Cond, Vec<Instr>)>>,
|
pub branches: Option<Vec<(Cond, Vec<Instr>)>>,
|
||||||
@@ -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::DebugMsg, literal::Label,
|
||||||
literal::RoutineName,
|
literal::RoutineName,
|
||||||
Rd,
|
Rd,
|
||||||
Wr,
|
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
|
/// A higher level simple opration
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum HLOp {
|
pub enum HLOp {
|
||||||
/// Mark a jump target.
|
/// Mark a jump target.
|
||||||
Label(Label),
|
Label(Label),
|
||||||
@@ -20,7 +29,7 @@ pub enum HLOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A low level instruction
|
/// A low level instruction
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Op {
|
pub enum Op {
|
||||||
/// Do nothing
|
/// Do nothing
|
||||||
Nop,
|
Nop,
|
||||||
@@ -45,32 +54,14 @@ pub enum Op {
|
|||||||
Barrier(Option<DebugMsg>),
|
Barrier(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>),
|
||||||
|
/// Copy value
|
||||||
Move { dst: Wr, src: Rd },
|
Move { dst: Wr, src: Rd },
|
||||||
Test { a: Rd },
|
/// Store runtime status to a register
|
||||||
Compare { a: Rd, b: Rd },
|
|
||||||
StoreStatus { dst: Wr },
|
StoreStatus { dst: Wr },
|
||||||
|
/// Load runtime status from a register
|
||||||
LoadStatus { src: Rd },
|
LoadStatus { src: Rd },
|
||||||
|
|
||||||
Add { dst: Wr, a: Rd, b: Rd },
|
Extension(Box<dyn OpTrait>),
|
||||||
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 },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make "into" work
|
/// Make "into" work
|
||||||
@@ -79,3 +70,13 @@ impl From<Op> for HLOp {
|
|||||||
HLOp::L(op)
|
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<Sexp>) -> Result<Box<dyn OpTrait>, Error>;
|
||||||
|
}
|
||||||
@@ -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 data;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
@@ -7,8 +8,8 @@ pub mod parse;
|
|||||||
pub mod patches;
|
pub mod patches;
|
||||||
|
|
||||||
/// Parse a program from string and assemble a low level instruction sequence from it.
|
/// Parse a program from string and assemble a low level instruction sequence from it.
|
||||||
pub fn assemble(source: &str) -> Result<Vec<Op>, error::Error> {
|
pub fn assemble(source: &str, parsers: &[Box<dyn OpParser>]) -> Result<Vec<Op>, error::Error> {
|
||||||
let parsed = parse::parse(source)?;
|
let parsed = parse::parse(source, parsers)?;
|
||||||
Ok(lower(parsed)?)
|
Ok(lower(parsed)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,11 +17,11 @@ pub fn assemble(source: &str) -> Result<Vec<Op>, error::Error> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::atomic::AtomicU32;
|
use std::sync::atomic::AtomicU32;
|
||||||
|
|
||||||
use crate::data::{DstDisp, Rd, Register, SrcDisp, Wr};
|
use crate::asm::data::{DstDisp, Rd, Register, SrcDisp, Wr};
|
||||||
use crate::data::literal::{Addr, Label};
|
use crate::asm::data::literal::{Addr, Label};
|
||||||
use crate::instr::{Flatten, HLOp, Instr, lower, Op};
|
use crate::asm::instr::{Flatten, HLOp, Instr, lower, Op};
|
||||||
use crate::instr::Cond;
|
use crate::asm::instr::Cond;
|
||||||
use crate::parse::{parse, parse_instructions};
|
use crate::asm::parse::{parse, parse_instructions};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_empty() {
|
fn test_parse_empty() {
|
||||||
@@ -3,21 +3,22 @@ use std::sync::atomic::AtomicU32;
|
|||||||
pub use parse_instr::parse_instructions;
|
pub use parse_instr::parse_instructions;
|
||||||
use parse_routines::parse_routines;
|
use parse_routines::parse_routines;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::asm::error::Error;
|
||||||
use crate::instr::{Flatten, HLOp, Routine};
|
use crate::asm::instr::{Flatten, HLOp, Routine};
|
||||||
use crate::parse::sexp_expect::expect_list;
|
use crate::asm::instr::op::OpParser;
|
||||||
|
use crate::asm::parse::sexp_expect::expect_list;
|
||||||
|
|
||||||
mod parse_cond;
|
mod parse_cond;
|
||||||
mod parse_instr;
|
mod parse_instr;
|
||||||
mod parse_data;
|
pub mod parse_data;
|
||||||
mod parse_routines;
|
mod parse_routines;
|
||||||
mod sexp_expect;
|
pub mod sexp_expect;
|
||||||
mod parse_op;
|
mod parse_op;
|
||||||
|
|
||||||
pub fn parse(source: &str) -> Result<Vec<HLOp>, Error> {
|
pub fn parse(source: &str, parsers: &[Box<dyn OpParser>]) -> Result<Vec<HLOp>, Error> {
|
||||||
let root = sexp::parse(source)?;
|
let root = sexp::parse(source)?;
|
||||||
|
|
||||||
let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?)?;
|
let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?, parsers)?;
|
||||||
|
|
||||||
let mut combined = vec![];
|
let mut combined = vec![];
|
||||||
let label_num = AtomicU32::new(0);
|
let label_num = AtomicU32::new(0);
|
||||||
@@ -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<dyn OpParser>]) -> Result<(Cond, Vec<Instr>), 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)?))
|
||||||
|
}
|
||||||
|
|
||||||
@@ -2,10 +2,10 @@ use std::convert::TryFrom;
|
|||||||
|
|
||||||
use sexp::{Atom, Sexp};
|
use sexp::{Atom, Sexp};
|
||||||
|
|
||||||
use crate::data::{DataDisp, DstDisp, Rd, reg, SrcDisp, Wr};
|
use crate::asm::data::{DataDisp, DstDisp, Rd, reg, SrcDisp, Wr};
|
||||||
use crate::data::literal::{Addr, Label};
|
use crate::asm::data::literal::{Addr, Label};
|
||||||
use crate::error::Error;
|
use crate::asm::error::Error;
|
||||||
use crate::parse::sexp_expect::expect_string_atom;
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
|
|
||||||
/// Parse a label
|
/// Parse a label
|
||||||
pub fn parse_label(name: Option<Sexp>) -> Result<Label, Error> {
|
pub fn parse_label(name: Option<Sexp>) -> Result<Label, Error> {
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
use sexp::Sexp;
|
use sexp::Sexp;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::asm::error::Error;
|
||||||
use crate::instr::Instr;
|
use crate::asm::instr::Instr;
|
||||||
use crate::parse::parse_cond::parse_cond_branch;
|
use crate::asm::instr::op::OpParser;
|
||||||
use crate::parse::sexp_expect::{expect_list, expect_string_atom};
|
use crate::asm::parse::parse_cond::parse_cond_branch;
|
||||||
use crate::patches::SexpIsA;
|
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
||||||
|
use crate::asm::patches::SexpIsA;
|
||||||
|
|
||||||
use super::parse_op::parse_op;
|
use super::parse_op::parse_op;
|
||||||
|
|
||||||
pub fn parse_instructions(instrs: Vec<Sexp>) -> Result<Vec<Instr>, Error> {
|
pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn OpParser>]) -> Result<Vec<Instr>, Error> {
|
||||||
let mut parsed = vec![];
|
let mut parsed = vec![];
|
||||||
for expr in instrs {
|
for expr in instrs {
|
||||||
let tokens = expect_list(Some(expr), false)?;
|
let tokens = expect_list(Some(expr), false)?;
|
||||||
@@ -32,7 +33,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>) -> Result<Vec<Instr>, Error> {
|
|||||||
let branches = {
|
let branches = {
|
||||||
let mut branches = vec![];
|
let mut branches = vec![];
|
||||||
for t in branch_tokens {
|
for t in branch_tokens {
|
||||||
branches.push(parse_cond_branch(t)?);
|
branches.push(parse_cond_branch(t, parsers)?);
|
||||||
}
|
}
|
||||||
if branches.is_empty() {
|
if branches.is_empty() {
|
||||||
None
|
None
|
||||||
@@ -42,7 +43,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>) -> Result<Vec<Instr>, Error> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
parsed.push(Instr {
|
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,
|
branches,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -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<Sexp>, parsers: &[Box<dyn OpParser>]) -> Result<HLOp, Error> {
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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<Sexp>, parsers: &[Box<dyn OpParser>]) -> Result<Vec<Routine>, 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)
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use sexp::{Atom, Sexp};
|
use sexp::{Atom, Sexp};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::asm::error::Error;
|
||||||
|
|
||||||
pub fn expect_list(expr: Option<Sexp>, allow_empty: bool) -> Result<Vec<Sexp>, Error> {
|
pub fn expect_list(expr: Option<Sexp>, allow_empty: bool) -> Result<Vec<Sexp>, Error> {
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
pub use sexp;
|
||||||
|
|
||||||
|
pub mod asm;
|
||||||
|
pub mod runtime;
|
||||||
|
|
||||||
@@ -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<EvalRes, Fault> {
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
// use super::span::MemorySpan;
|
use crate::asm::data::literal::{DebugMsg, Label, RoutineName};
|
||||||
// use crate::run_thread::ThreadToken;
|
use crate::asm::data::Register;
|
||||||
// use crate::mlock::ClaimId;
|
|
||||||
use asm::data::literal::{DebugMsg, Label, RoutineName};
|
|
||||||
use asm::data::Register;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Fault {
|
pub enum Fault {
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
use asm::data::{DstDisp, Rd, Register, SrcDisp, Wr};
|
|
||||||
use asm::data::literal::{Addr, Value};
|
|
||||||
use status::StatusFlags;
|
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;
|
mod status;
|
||||||
|
|
||||||
pub const REG_COUNT: usize = 8;
|
pub const REG_COUNT: usize = 8;
|
||||||
|
|
||||||
|
pub type CallStack = Vec<StackFrame>;
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct StackFrame {
|
pub struct StackFrame {
|
||||||
/// Program counter, address of the executed instruction
|
/// Program counter, address of the executed instruction
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use asm::data::literal::{is_negative, is_positive, Value};
|
use crate::asm::data::literal::{is_negative, is_positive, Value};
|
||||||
use asm::instr::Cond;
|
use crate::asm::instr::Cond;
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct StatusFlags {
|
pub struct StatusFlags {
|
||||||
@@ -2,9 +2,9 @@ use std::fmt;
|
|||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
use crate::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
use crate::run_thread::ThreadToken;
|
use crate::runtime::run_thread::ThreadToken;
|
||||||
use crate::span::MemorySpan;
|
use crate::runtime::span::MemorySpan;
|
||||||
|
|
||||||
/// Records memory claims and protects from illegal access
|
/// Records memory claims and protects from illegal access
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
|
|
||||||
pub mod run_thread;
|
pub mod run_thread;
|
||||||
// pub mod mlock;
|
// pub mod mlock;
|
||||||
// pub mod sparse;
|
// pub mod sparse;
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use asm::data::literal::{Addr, Label, RoutineName};
|
use crate::asm::data::literal::{Addr, Label, RoutineName};
|
||||||
use asm::instr::Op;
|
use crate::asm::instr::Op;
|
||||||
|
use crate::runtime::fault::Fault;
|
||||||
use crate::fault::Fault;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
use std::thread::JoinHandle;
|
use std::thread::JoinHandle;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use asm::data::literal::Addr;
|
use crate::asm::data::literal::Addr;
|
||||||
|
use crate::runtime::exec::EvalRes;
|
||||||
use crate::exec::EvalRes;
|
use crate::runtime::frame::{CallStack, StackFrame};
|
||||||
use crate::frame::StackFrame;
|
use crate::runtime::program::Program;
|
||||||
use crate::program::Program;
|
|
||||||
|
|
||||||
const CYCLE_TIME: Duration = Duration::from_millis(0);
|
const CYCLE_TIME: Duration = Duration::from_millis(0);
|
||||||
//const CYCLE_TIME : Duration = Duration::from_millis(100);
|
//const CYCLE_TIME : Duration = Duration::from_millis(100);
|
||||||
@@ -19,7 +18,7 @@ pub struct RunThread {
|
|||||||
/// Active stack frame
|
/// Active stack frame
|
||||||
pub frame: StackFrame,
|
pub frame: StackFrame,
|
||||||
/// Call stack
|
/// Call stack
|
||||||
pub call_stack: Vec<StackFrame>,
|
pub call_stack: CallStack,
|
||||||
/// Program to run
|
/// Program to run
|
||||||
pub program: Program,
|
pub program: Program,
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use asm::data::literal::Addr;
|
use crate::asm::data::literal::Addr;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct MemorySpan {
|
pub struct MemorySpan {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "runtime"
|
name = "crsn_arith"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
@@ -7,8 +7,5 @@ edition = "2018"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
asm = { path = "../asm" }
|
crsn = { path = "../crsn" }
|
||||||
thiserror = "1.0.20"
|
|
||||||
anyhow = "1.0.32"
|
|
||||||
log = "0.4.11"
|
|
||||||
num-traits = "0.2.12"
|
num-traits = "0.2.12"
|
||||||
@@ -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 },
|
||||||
|
}
|
||||||
@@ -2,125 +2,22 @@ use std::ops::Rem;
|
|||||||
|
|
||||||
use num_traits::PrimInt;
|
use num_traits::PrimInt;
|
||||||
|
|
||||||
use asm::data::literal::Addr;
|
use crsn::asm::instr::op::OpTrait;
|
||||||
use asm::instr::Op;
|
use crsn::runtime::fault::Fault;
|
||||||
|
use crsn::runtime::frame::{CallStack, StackFrame};
|
||||||
|
use crsn::runtime::program::Program;
|
||||||
|
|
||||||
use crate::fault::Fault;
|
use crate::defs::ArithOp;
|
||||||
use crate::frame::StackFrame;
|
|
||||||
use crate::run_thread::RunThread;
|
|
||||||
|
|
||||||
pub type CyclesSpent = usize;
|
impl OpTrait for ArithOp {
|
||||||
|
fn execute(&self, _program: &Program, _call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<(), Fault> {
|
||||||
pub struct EvalRes {
|
match self {
|
||||||
pub cycles: u8,
|
ArithOp::Test { a } => {
|
||||||
pub advance: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RunThread {
|
|
||||||
// TODO unit tests
|
|
||||||
pub fn eval_op(&mut self) -> Result<EvalRes, Fault> {
|
|
||||||
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 } => {
|
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let res = frame.read(*a)?;
|
let res = frame.read(*a)?;
|
||||||
frame.status.update(res);
|
frame.status.update(res);
|
||||||
}
|
}
|
||||||
Op::Compare { a, b } => {
|
ArithOp::Compare { a, b } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*b)?;
|
let y = frame.read(*b)?;
|
||||||
@@ -132,7 +29,7 @@ impl RunThread {
|
|||||||
frame.status.update(x);
|
frame.status.update(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Op::Add { dst, a, b } => {
|
ArithOp::Add { dst, a, b } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*b)?;
|
let y = frame.read(*b)?;
|
||||||
@@ -145,7 +42,7 @@ impl RunThread {
|
|||||||
frame.status.overflow = ov;
|
frame.status.overflow = ov;
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Sub { dst, a, b } => {
|
ArithOp::Sub { dst, a, b } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*b)?;
|
let y = frame.read(*b)?;
|
||||||
@@ -158,7 +55,7 @@ impl RunThread {
|
|||||||
frame.status.overflow = ov;
|
frame.status.overflow = ov;
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Mul { dst, a, b } => {
|
ArithOp::Mul { dst, a, b } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*b)?;
|
let y = frame.read(*b)?;
|
||||||
@@ -171,7 +68,7 @@ impl RunThread {
|
|||||||
frame.status.overflow = ov;
|
frame.status.overflow = ov;
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Div { dst, rem, a, div } => {
|
ArithOp::Div { dst, rem, a, div } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let d = frame.read(*div)?;
|
let d = frame.read(*div)?;
|
||||||
@@ -189,7 +86,7 @@ impl RunThread {
|
|||||||
frame.write(*rem, remainder)?;
|
frame.write(*rem, remainder)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Op::Mod { dst, a, div } => {
|
ArithOp::Mod { dst, a, div } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let d = frame.read(*div)?;
|
let d = frame.read(*div)?;
|
||||||
@@ -206,7 +103,7 @@ impl RunThread {
|
|||||||
frame.write(*dst, remainder)?;
|
frame.write(*dst, remainder)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Op::And { dst, a, b } => {
|
ArithOp::And { dst, a, b } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*b)?;
|
let y = frame.read(*b)?;
|
||||||
@@ -214,7 +111,7 @@ impl RunThread {
|
|||||||
frame.status.update(res);
|
frame.status.update(res);
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Or { dst, a, b } => {
|
ArithOp::Or { dst, a, b } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*b)?;
|
let y = frame.read(*b)?;
|
||||||
@@ -222,7 +119,7 @@ impl RunThread {
|
|||||||
frame.status.update(res);
|
frame.status.update(res);
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Xor { dst, a, b } => {
|
ArithOp::Xor { dst, a, b } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*b)?;
|
let y = frame.read(*b)?;
|
||||||
@@ -230,14 +127,14 @@ impl RunThread {
|
|||||||
frame.status.update(res);
|
frame.status.update(res);
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Cpl { dst, a } => {
|
ArithOp::Cpl { dst, a } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let res = !x;
|
let res = !x;
|
||||||
frame.status.update(res);
|
frame.status.update(res);
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Rol { dst, a, n } => {
|
ArithOp::Rol { dst, a, n } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*n)?;
|
let y = frame.read(*n)?;
|
||||||
@@ -249,7 +146,7 @@ impl RunThread {
|
|||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Op::Ror { dst, a, n } => {
|
ArithOp::Ror { dst, a, n } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*n)?;
|
let y = frame.read(*n)?;
|
||||||
@@ -261,7 +158,7 @@ impl RunThread {
|
|||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Op::Lsl { dst, a, n } => {
|
ArithOp::Lsl { dst, a, n } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*n)?;
|
let y = frame.read(*n)?;
|
||||||
@@ -269,7 +166,7 @@ impl RunThread {
|
|||||||
frame.status.update(res);
|
frame.status.update(res);
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Lsr { dst, a, n } => {
|
ArithOp::Lsr { dst, a, n } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*n)?;
|
let y = frame.read(*n)?;
|
||||||
@@ -277,7 +174,7 @@ impl RunThread {
|
|||||||
frame.status.update(res);
|
frame.status.update(res);
|
||||||
frame.write(*dst, res)?;
|
frame.write(*dst, res)?;
|
||||||
}
|
}
|
||||||
Op::Asr { dst, a, n } => {
|
ArithOp::Asr { dst, a, n } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
let x = frame.read(*a)?;
|
let x = frame.read(*a)?;
|
||||||
let y = frame.read(*n)?;
|
let y = frame.read(*n)?;
|
||||||
@@ -289,19 +186,10 @@ impl RunThread {
|
|||||||
frame.write(*dst, res)?;
|
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 {
|
Ok(())
|
||||||
cycles,
|
|
||||||
advance,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
pub use parse::ArithOpParser;
|
||||||
|
|
||||||
|
mod defs;
|
||||||
|
mod parse;
|
||||||
|
mod exec;
|
||||||
|
|
||||||
@@ -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<dyn OpParser> {
|
||||||
|
Box::new(Self {
|
||||||
|
_internal: ()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpParser for ArithOpParser {
|
||||||
|
fn parse_op(&self, keyword: &str, _far: bool, arg_tokens_sl: Vec<Sexp>) -> Result<Box<dyn OpTrait>, 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));
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "launcher"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
||||||
|
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"
|
||||||
@@ -3,9 +3,10 @@ extern crate log;
|
|||||||
|
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
|
|
||||||
use asm::data::literal::Addr;
|
use crsn::asm::data::literal::Addr;
|
||||||
use runtime::program::Program;
|
use crsn::runtime::program::Program;
|
||||||
use runtime::run_thread::{RunThread, ThreadToken};
|
use crsn::runtime::run_thread::{RunThread, ThreadToken};
|
||||||
|
use crsn_arith::ArithOpParser;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
SimpleLogger::new().init().unwrap();
|
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!("---");
|
debug!("---");
|
||||||
for op in &parsed {
|
for op in &parsed {
|
||||||
Reference in New Issue
Block a user