re-arrange modules, add "plug-in" system so instructions can be defined in multiple crates

This commit is contained in:
2020-09-26 00:29:33 +02:00
parent 547beed847
commit f015104b95
45 changed files with 984 additions and 843 deletions
+28
View File
@@ -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 },
}
+195
View File
@@ -0,0 +1,195 @@
use std::ops::Rem;
use num_traits::PrimInt;
use crsn::asm::instr::op::OpTrait;
use crsn::runtime::fault::Fault;
use crsn::runtime::frame::{CallStack, StackFrame};
use crsn::runtime::program::Program;
use crate::defs::ArithOp;
impl OpTrait for ArithOp {
fn execute(&self, _program: &Program, _call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<(), Fault> {
match self {
ArithOp::Test { a } => {
frame.status.clear();
let res = frame.read(*a)?;
frame.status.update(res);
}
ArithOp::Compare { a, b } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*b)?;
frame.status.equal = x == y;
frame.status.lower = x < y;
frame.status.greater = x > y;
// Test flags are set when both arguments have the property
if x == y {
frame.status.update(x);
}
}
ArithOp::Add { dst, a, b } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*b)?;
let (res, ov) = if let Some(v) = x.checked_add(y) {
(v, false)
} else {
(x.wrapping_add(y), true)
};
frame.status.update(res);
frame.status.overflow = ov;
frame.write(*dst, res)?;
}
ArithOp::Sub { dst, a, b } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*b)?;
let (res, ov) = if let Some(v) = x.checked_sub(y) {
(v, false)
} else {
(x.wrapping_sub(y), true)
};
frame.status.update(res);
frame.status.overflow = ov;
frame.write(*dst, res)?;
}
ArithOp::Mul { dst, a, b } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*b)?;
let (res, ov) = if let Some(v) = x.checked_mul(y) {
(v, false)
} else {
(x.wrapping_mul(y), true)
};
frame.status.update(res);
frame.status.overflow = ov;
frame.write(*dst, res)?;
}
ArithOp::Div { dst, rem, a, div } => {
frame.status.clear();
let x = frame.read(*a)?;
let d = frame.read(*div)?;
if d == 0 {
frame.status.invalid = true;
} else {
let (res, remainder, ov) = if let Some(v) = x.checked_div(d) {
(v, x.rem(d), false)
} else {
(x.wrapping_div(d), x.wrapping_rem(d), true)
};
frame.status.update(res);
frame.status.overflow = ov;
frame.write(*dst, res)?;
frame.write(*rem, remainder)?;
}
}
ArithOp::Mod { dst, a, div } => {
frame.status.clear();
let x = frame.read(*a)?;
let d = frame.read(*div)?;
if d == 0 {
frame.status.invalid = true;
} else {
let (remainder, ov) = if let Some(v) = x.checked_rem(d) {
(v, false)
} else {
(x.wrapping_rem(d), true)
};
frame.status.update(remainder);
frame.status.overflow = ov;
frame.write(*dst, remainder)?;
}
}
ArithOp::And { dst, a, b } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*b)?;
let res = x & y;
frame.status.update(res);
frame.write(*dst, res)?;
}
ArithOp::Or { dst, a, b } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*b)?;
let res = x | y;
frame.status.update(res);
frame.write(*dst, res)?;
}
ArithOp::Xor { dst, a, b } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*b)?;
let res = x ^ y;
frame.status.update(res);
frame.write(*dst, res)?;
}
ArithOp::Cpl { dst, a } => {
frame.status.clear();
let x = frame.read(*a)?;
let res = !x;
frame.status.update(res);
frame.write(*dst, res)?;
}
ArithOp::Rol { dst, a, n } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*n)?;
if y > u32::MAX as u64 {
frame.status.invalid = true;
} else {
let res = x.rotate_left(y as u32);
frame.status.update(res);
frame.write(*dst, res)?;
}
}
ArithOp::Ror { dst, a, n } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*n)?;
if y > u32::MAX as u64 {
frame.status.invalid = true;
} else {
let res = x.rotate_right(y as u32);
frame.status.update(res);
frame.write(*dst, res)?;
}
}
ArithOp::Lsl { dst, a, n } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*n)?;
let res = x << y;
frame.status.update(res);
frame.write(*dst, res)?;
}
ArithOp::Lsr { dst, a, n } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*n)?;
let res = x >> y;
frame.status.update(res);
frame.write(*dst, res)?;
}
ArithOp::Asr { dst, a, n } => {
frame.status.clear();
let x = frame.read(*a)?;
let y = frame.read(*n)?;
if y > u32::MAX as u64 {
frame.status.invalid = true;
} else {
let res = x.signed_shr(y as u32);
frame.status.update(res);
frame.write(*dst, res)?;
}
}
}
Ok(())
}
//
}
+6
View File
@@ -0,0 +1,6 @@
pub use parse::ArithOpParser;
mod defs;
mod parse;
mod exec;
+452
View File
@@ -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));
}
}))
}
}