Simplify {clz,clo,se}XX parsing and exec, add simple unit test example scripts

This commit is contained in:
2020-10-16 00:18:38 +02:00
parent 768f36ae18
commit 26616e20cb
14 changed files with 233 additions and 376 deletions
+27 -11
View File
@@ -1,4 +1,5 @@
use crsn::asm::data::{Rd, Wr};
use crsn::builtin::defs::BitSlice;
/// A low level instruction
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -8,22 +9,22 @@ pub enum ArithOp {
RangeTest { val: Rd, a: Rd, b: Rd },
Rng { dst: Wr, min: Rd, max: Rd },
/// Swap halves
Sw32 { dst: Wr, src: Rd },
/// Swap adjacent half-words
Sw16 { dst: Wr, src: Rd },
/// Swap neighbouring bytes
Sw8 { dst: Wr, src: Rd },
/// Reverse bytes
Rev { dst: Wr, src: Rd },
/// Reverse bits
Rbit { dst: Wr, src: Rd },
Clz { dst: Wr, src: Rd },
Clz32 { dst: Wr, src: Rd },
Clz16 { dst: Wr, src: Rd },
Clz8 { dst: Wr, src: Rd },
Clo { dst: Wr, src: Rd },
Clo32 { dst: Wr, src: Rd },
Clo16 { dst: Wr, src: Rd },
Clo8 { dst: Wr, src: Rd },
SignExtend32 { dst: Wr, src: Rd },
SignExtend16 { dst: Wr, src: Rd },
SignExtend8 { dst: Wr, src: Rd },
/// Count leading zeros in a slice
Clz { dst: Wr, src: Rd, slice: BitSlice },
/// Count leading ones in a slice
Clo { dst: Wr, src: Rd, slice: BitSlice },
/// Sign extend a slice (zero aligned)
SignExtend { dst: Wr, src: Rd, slice: BitSlice },
Add { dst: Wr, a: Rd, b: Rd },
Sub { dst: Wr, a: Rd, b: Rd },
@@ -44,4 +45,19 @@ pub enum ArithOp {
// Shift
Lsr { dst: Wr, a: Rd, n: Rd },
Asr { dst: Wr, a: Rd, n: Rd },
// IntToFloat { dst: Wr, a: Rd },
// FloatToInt { dst: Wr, a: Rd },
// FloatTest { a: Rd },
// FloatCompare { a: Rd, b: Rd },
// FloatRangeTest { val: Rd, a: Rd, b: Rd },
// FloatRng { dst: Wr, min: Rd, max: Rd },
// FloatRound { dst: Wr, a: Rd, b: Rd },
// FloatCeil { dst: Wr, a: Rd, b: Rd },
// FloatFloor { dst: Wr, a: Rd, b: Rd },
// FloatAdd { dst: Wr, a: Rd, b: Rd },
// FloatSub { dst: Wr, a: Rd, b: Rd },
// FloatMul { dst: Wr, a: Rd, b: Rd },
// FloatDiv { dst: Wr, rem: Wr, a: Rd, div: Rd },
// FloatMod { dst: Wr, a: Rd, div: Rd },
}
+18 -83
View File
@@ -250,91 +250,34 @@ impl OpTrait for ArithOp {
let res = val.reverse_bits();
state.write(dst, res)?;
}
ArithOp::Clz { dst, src } => {
ArithOp::Clz { dst, src, slice } => {
state.clear_status();
let val = state.read(src)?;
let mut val = ((state.read(src)? >> slice.src_pos) << (64 - slice.width));
if !slice.is_full() {
val |= ((1 << slice.width) - 1);
}
let res = val.leading_zeros() as u64;
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::Clz32 { dst, src } => {
ArithOp::Clo { dst, src, slice } => {
state.clear_status();
let val = state.read(src)?;
let res = (((val & 0xFFFF_FFFF) << 32) | 0xFFFF_FFFF).leading_zeros() as u64;
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::Clz16 { dst, src } => {
state.clear_status();
let val = state.read(src)?;
let res = (((val & 0xFFFF) << 48) | 0xFFFF_FFFF_FFFF).leading_zeros() as u64;
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::Clz8 { dst, src } => {
state.clear_status();
let val = state.read(src)?;
let res = (((val & 0xFF) << 56) | 0x00FF_FFFF_FFFF_FFFF).leading_zeros() as u64;
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::Clo { dst, src } => {
state.clear_status();
let val = state.read(src)?;
let mut val = ((state.read(src)? >> slice.src_pos) << (64 - slice.width));
if !slice.is_full() {
val &= ((1 << slice.width) - 1) << slice.src_pos;
}
let res = val.leading_ones() as u64;
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::Clo32 { dst, src } => {
ArithOp::SignExtend { dst, src, slice } => {
state.clear_status();
let val = state.read(src)?;
let res = ((val & 0xFFFF_FFFF) << 32).leading_ones() as u64;
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::Clo16 { dst, src } => {
state.clear_status();
let val = state.read(src)?;
let res = ((val & 0xFFFF) << 48).leading_ones() as u64;
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::Clo8 { dst, src } => {
state.clear_status();
let val = state.read(src)?;
let res = ((val & 0xFF) << 56).leading_ones() as u64;
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::SignExtend32 { dst, src } => {
state.clear_status();
let val = state.read(src)?;
let res = if 0 != (val & 0x8000_0000) {
0xFFFF_FFFF_0000_0000 | val
let res = if 0 != (val & (1 << (slice.width - 1))) {
val | (((1 << (64 - slice.width)) - 1) << slice.width)
} else {
val & 0xFFFF_FFFF
};
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::SignExtend16 { dst, src } => {
state.clear_status();
let val = state.read(src)?;
let res = if 0 != (val & 0x8000) {
0xFFFF_FFFF_FFFF_0000 | val
} else {
val & 0xFFFF
};
state.update_status(res);
state.write(dst, res)?;
}
ArithOp::SignExtend8 { dst, src } => {
state.clear_status();
let val = state.read(src)?;
let res = if 0 != (val & 0x80) {
0xFFFF_FFFF_FFFF_FF00 | val
} else {
val & 0xFF
val & ((1 << slice.width) - 1)
};
state.update_status(res);
state.write(dst, res)?;
@@ -387,17 +330,9 @@ impl OpTrait for ArithOp {
ArithOp::Sw8 { dst, src } => to_sexp_1_or_2("sw8", dst, src),
ArithOp::Rev { dst, src } => to_sexp_1_or_2("rev", dst, src),
ArithOp::Rbit { dst, src } => to_sexp_1_or_2("rbit", dst, src),
ArithOp::Clz { dst, src } => to_sexp_1_or_2("clz", dst, src),
ArithOp::Clz32 { dst, src } => to_sexp_1_or_2("clz32", dst, src),
ArithOp::Clz16 { dst, src } => to_sexp_1_or_2("clz16", dst, src),
ArithOp::Clz8 { dst, src } => to_sexp_1_or_2("clz8", dst, src),
ArithOp::Clo { dst, src } => to_sexp_1_or_2("clo", dst, src),
ArithOp::Clo32 { dst, src } => to_sexp_1_or_2("clo32", dst, src),
ArithOp::Clo16 { dst, src } => to_sexp_1_or_2("clo16", dst, src),
ArithOp::Clo8 { dst, src } => to_sexp_1_or_2("clo8", dst, src),
ArithOp::SignExtend32 { dst, src } => to_sexp_1_or_2("se32", dst, src),
ArithOp::SignExtend16 { dst, src } => to_sexp_1_or_2("se16", dst, src),
ArithOp::SignExtend8 { dst, src } => to_sexp_1_or_2("se8", dst, src),
ArithOp::Clz { dst, src, slice } => to_sexp_1_or_2(&format!("clz{}", slice), dst, src),
ArithOp::Clo { dst, src, slice } => to_sexp_1_or_2(&format!("clo{}", slice), dst, src),
ArithOp::SignExtend { dst, src, slice } => to_sexp_1_or_2(&format!("se{}", slice), dst, src),
}
}
}
+68 -244
View File
@@ -6,8 +6,9 @@ use crsn::module::ParseRes;
use crsn::sexp::SourcePosition;
use crate::defs::ArithOp;
use crsn::builtin::defs::BitSlice;
pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
Ok(ParseRes::ext(match keyword {
"cmp" => {
ArithOp::Compare {
@@ -53,7 +54,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Rng requires 1, 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Rng requires 1, 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -94,7 +95,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -117,7 +118,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -140,7 +141,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -167,7 +168,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("DivR requires 3 or 4 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("DivR requires 3 or 4 arguments".into(), op_pos.clone()));
}
}
}
@@ -193,7 +194,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -217,7 +218,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -240,7 +241,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("And requires 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("And requires 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -263,7 +264,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Or requires 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Or requires 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -286,7 +287,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Xor requires 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Xor requires 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -307,7 +308,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into(), op_pos.clone()));
}
}
}
@@ -338,7 +339,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Rol requires 1, 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Rol requires 1, 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -369,7 +370,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -400,7 +401,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Lsl requires 1, 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Lsl requires 1, 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -431,7 +432,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -462,7 +463,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("Asr requires 1, 2 or 3 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("Asr requires 1, 2 or 3 arguments".into(), op_pos.clone()));
}
}
}
@@ -483,7 +484,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("SW32 requires 1 or 2 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("SW32 requires 1 or 2 arguments".into(), op_pos.clone()));
}
}
}
@@ -504,7 +505,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("SW16 requires 1 or 2 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("SW16 requires 1 or 2 arguments".into(), op_pos.clone()));
}
}
}
@@ -525,7 +526,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("SW8 requires 1 or 2 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("SW8 requires 1 or 2 arguments".into(), op_pos.clone()));
}
}
}
@@ -546,7 +547,7 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("REV requires 1 or 2 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("REV requires 1 or 2 arguments".into(), op_pos.clone()));
}
}
}
@@ -567,243 +568,66 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
}
}
_ => {
return Err(CrsnError::Parse("RBIT requires 1 or 2 arguments".into(), pos.clone()));
return Err(CrsnError::Parse("RBIT requires 1 or 2 arguments".into(), op_pos.clone()));
}
}
}
"clz" => {
match args.len() {
2 => {
ArithOp::Clz {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clz {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), pos.clone()));
other => {
if let Some(s) = other.strip_prefix("clz") {
if let Some(slice) = BitSlice::parse2(s, op_pos)? {
return Ok(ParseRes::ext(match args.len() {
2 => {
ArithOp::Clz { dst: args.next_wr()?, src: args.next_rd()?, slice }
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clz { dst: dst.wr(), src: dst.rd(), slice }
}
_ => {
return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), op_pos.clone()));
}
}));
}
}
}
"clz32" => {
match args.len() {
2 => {
ArithOp::Clz32 {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clz32 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("Clz32 requires 1 or 2 arguments".into(), pos.clone()));
if let Some(s) = other.strip_prefix("clo") {
if let Some(slice) = BitSlice::parse2(s, op_pos)? {
return Ok(ParseRes::ext(match args.len() {
2 => {
ArithOp::Clo { dst: args.next_wr()?, src: args.next_rd()?, slice }
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clo { dst: dst.wr(), src: dst.rd(), slice }
}
_ => {
return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), op_pos.clone()));
}
}));
}
}
}
"clz16" => {
match args.len() {
2 => {
ArithOp::Clz16 {
dst: args.next_wr()?,
src: args.next_rd()?,
if let Some(s) = other.strip_prefix("se") {
if let Some(slice) = BitSlice::parse1(s, op_pos)? {
if slice.is_full() {
return Err(CrsnError::Parse("Sign extend requires a bit size (< 64)".into(), op_pos.clone()));
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clz16 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("Clz16 requires 1 or 2 arguments".into(), pos.clone()));
return Ok(ParseRes::ext(match args.len() {
2 => {
ArithOp::SignExtend { dst: args.next_wr()?, src: args.next_rd()?, slice }
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::SignExtend { dst: dst.wr(), src: dst.rd(), slice }
}
_ => {
return Err(CrsnError::Parse("Sign extend requires 1 or 2 arguments".into(), op_pos.clone()));
}
}));
}
}
}
"clz8" => {
match args.len() {
2 => {
ArithOp::Clz8 {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clz8 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("Clz8 requires 1 or 2 arguments".into(), pos.clone()));
}
}
}
"clo" => {
match args.len() {
2 => {
ArithOp::Clo {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clo {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("Clo requires 1 or 2 arguments".into(), pos.clone()));
}
}
}
"clo32" => {
match args.len() {
2 => {
ArithOp::Clo32 {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clo32 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("Clo32 requires 1 or 2 arguments".into(), pos.clone()));
}
}
}
"clo16" => {
match args.len() {
2 => {
ArithOp::Clo16 {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clo16 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("Clo16 requires 1 or 2 arguments".into(), pos.clone()));
}
}
}
"clo8" => {
match args.len() {
2 => {
ArithOp::Clo8 {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clo8 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("Clo8 requires 1 or 2 arguments".into(), pos.clone()));
}
}
}
"se32" => {
match args.len() {
2 => {
ArithOp::SignExtend32 {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::SignExtend32 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("SignExtend32 requires 1 or 2 arguments".into(), pos.clone()));
}
}
}
"se16" => {
match args.len() {
2 => {
ArithOp::SignExtend16 {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::SignExtend16 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("SignExtend16 requires 1 or 2 arguments".into(), pos.clone()));
}
}
}
"se8" => {
match args.len() {
2 => {
ArithOp::SignExtend8 {
dst: args.next_wr()?,
src: args.next_rd()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::SignExtend8 {
dst: dst.wr(),
src: dst.rd(),
}
}
_ => {
return Err(CrsnError::Parse("SignExtend8 requires 1 or 2 arguments".into(), pos.clone()));
}
}
}
_other => {
return Ok(ParseRes::Unknown(args));
}
}))