pull/21/head
parent
547beed847
commit
f015104b95
@ -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) |
|
||||||
} |
|
@ -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)] |
@ -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)] |
@ -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 { |
@ -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)?)) |
||||||
|
} |
||||||
|
|
@ -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 { |
@ -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,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 { |
@ -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 }, |
||||||
|
} |
@ -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" |
Loading…
Reference in new issue