Simplify {clz,clo,se}XX parsing and exec, add simple unit test example scripts
This commit is contained in:
@@ -467,46 +467,26 @@ Many instructions have two forms:
|
||||
; Count leading zeros
|
||||
(clz Wr Rd)
|
||||
(clz RW)
|
||||
|
||||
; Count leading zeros in the lower 32 bits
|
||||
(clz32 Wr Rd)
|
||||
(clz32 RW)
|
||||
|
||||
; Count leading zeros in the lower 16 bits
|
||||
(clz16 Wr Rd)
|
||||
(clz16 RW)
|
||||
|
||||
; Count leading zeros in the lower byte
|
||||
(clz8 Wr Rd)
|
||||
(clz8 RW)
|
||||
; Count leading zeros in the lower XX bits
|
||||
(clzXX Wr Rd)
|
||||
(clzXX RW)
|
||||
; Count leading zeros in the XX bits starting at YY (e.g. 16/32 is the lower 16 bits of the higher 32 bits)
|
||||
(clzXX/YY Wr Rd)
|
||||
(clzXX/YY RW)
|
||||
|
||||
; Count leading ones
|
||||
(clo Wr Rd)
|
||||
(clo RW)
|
||||
; Count leading ones in the lower XX bits
|
||||
(cloXX Wr Rd)
|
||||
(cloXX RW)
|
||||
; Count leading ones in the XX bits starting at YY
|
||||
(cloXX/YY Wr Rd)
|
||||
(cloXX/YY RW)
|
||||
|
||||
; Count leading ones in the lower 32 bits
|
||||
(clo32 Wr Rd)
|
||||
(clo32 RW)
|
||||
|
||||
; Count leading ones in the lower 16 bits
|
||||
(clo16 Wr Rd)
|
||||
(clo16 RW)
|
||||
|
||||
; Count leading ones in the lower byte
|
||||
(clo8 Wr Rd)
|
||||
(clo8 RW)
|
||||
|
||||
; Sign extend 32-bit to 64 bits
|
||||
(se32 Wr Rd)
|
||||
(se32 RW)
|
||||
|
||||
; Sign extend 16-bit to 64 bits
|
||||
(se16 Wr Rd)
|
||||
(se16 RW)
|
||||
|
||||
; Sign extend 8-bit to 64 bits
|
||||
(se8 Wr Rd)
|
||||
(se8 RW)
|
||||
; Sign extend a XX-bit value to 64 bits, XX in range 1..63)
|
||||
(seXX Wr Rd)
|
||||
(seXX RW)
|
||||
|
||||
; AND A&B
|
||||
(and Wr Rd Rd)
|
||||
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cargo build
|
||||
|
||||
for file in examples/*.csn
|
||||
do
|
||||
echo "--- $file ---"
|
||||
target/debug/launcher -P "$file"
|
||||
done
|
||||
@@ -41,7 +41,7 @@ pub enum LdsValue {
|
||||
Chars(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct BitSlice {
|
||||
pub width: u32,
|
||||
pub src_pos: u32,
|
||||
@@ -80,7 +80,50 @@ impl BitSlice {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Parse LEN (no SRC and DST)
|
||||
pub fn parse1(src: &str, pos: &SourcePosition) -> Result<Option<Self>, CrsnError> {
|
||||
match Self::parse(src, pos) {
|
||||
Ok(Some(slice)) => {
|
||||
if slice.src_pos != 0 || slice.dst_pos != 0 {
|
||||
return Err(CrsnError::Parse("Excess bit slice modifiers".into(), pos.clone()));
|
||||
}
|
||||
|
||||
Ok(Some(BitSlice {
|
||||
width: slice.width,
|
||||
src_pos: 0,
|
||||
dst_pos: 0
|
||||
}))
|
||||
}
|
||||
other => other
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse LEN/SRC
|
||||
pub fn parse2(src: &str, pos: &SourcePosition) -> Result<Option<Self>, CrsnError> {
|
||||
match Self::parse(src, pos) {
|
||||
Ok(Some(slice)) => {
|
||||
if slice.src_pos != 0 {
|
||||
return Err(CrsnError::Parse("Excess bit slice modifiers".into(), pos.clone()));
|
||||
}
|
||||
|
||||
Ok(Some(BitSlice {
|
||||
width: slice.width,
|
||||
src_pos: slice.dst_pos,
|
||||
dst_pos: 0
|
||||
}))
|
||||
}
|
||||
other => other
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a bit slice LEN/DST/SRC
|
||||
/// - String not starting with a digit is rejected as `Ok(None)`
|
||||
/// - Empty string is parsed as a full slice
|
||||
pub fn parse(src: &str, pos: &SourcePosition) -> Result<Option<Self>, CrsnError> {
|
||||
if src.is_empty() {
|
||||
return Ok(Some(BitSlice::full()));
|
||||
}
|
||||
|
||||
if !src.starts_with(|c: char| c.is_ascii_digit()) {
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -97,6 +140,10 @@ impl BitSlice {
|
||||
dst_pos: numbers.get(1).copied().unwrap_or(0)
|
||||
};
|
||||
|
||||
if slice.width == 0 || slice.width > 64 {
|
||||
return Err(CrsnError::Parse("Bit slice width must be 1-64".into(), pos.clone()));
|
||||
}
|
||||
|
||||
// Validation
|
||||
if slice.src_pos + slice.width > 64 {
|
||||
return Err(CrsnError::Parse("Invalid source bit slice".into(), pos.clone()));
|
||||
|
||||
+27
-11
@@ -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 },
|
||||
}
|
||||
|
||||
+17
-82
@@ -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)?;
|
||||
let mut val = ((state.read(src)? >> slice.src_pos) << (64 - slice.width));
|
||||
if !slice.is_full() {
|
||||
val &= ((1 << slice.width) - 1) << slice.src_pos;
|
||||
}
|
||||
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 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+48
-224
@@ -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() {
|
||||
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()?,
|
||||
}
|
||||
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(),
|
||||
}
|
||||
ArithOp::Clz { dst: dst.wr(), src: dst.rd(), slice }
|
||||
}
|
||||
_ => {
|
||||
return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), pos.clone()));
|
||||
return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), op_pos.clone()));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
"clz32" => {
|
||||
match args.len() {
|
||||
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::Clz32 {
|
||||
dst: args.next_wr()?,
|
||||
src: args.next_rd()?,
|
||||
}
|
||||
ArithOp::Clo { dst: args.next_wr()?, src: args.next_rd()?, slice }
|
||||
}
|
||||
1 => {
|
||||
let dst = args.next_rdwr()?;
|
||||
ArithOp::Clz32 {
|
||||
dst: dst.wr(),
|
||||
src: dst.rd(),
|
||||
}
|
||||
ArithOp::Clo { dst: dst.wr(), src: dst.rd(), slice }
|
||||
}
|
||||
_ => {
|
||||
return Err(CrsnError::Parse("Clz32 requires 1 or 2 arguments".into(), pos.clone()));
|
||||
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()));
|
||||
}
|
||||
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::Clz16 {
|
||||
dst: dst.wr(),
|
||||
src: dst.rd(),
|
||||
}
|
||||
ArithOp::SignExtend { dst: dst.wr(), src: dst.rd(), slice }
|
||||
}
|
||||
_ => {
|
||||
return Err(CrsnError::Parse("Clz16 requires 1 or 2 arguments".into(), pos.clone()));
|
||||
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));
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
(
|
||||
(se32 r0 0x01)
|
||||
(cmp r0 0x01 (ne? (fault "1")))
|
||||
|
||||
(se4 r0 0x0f)
|
||||
(cmp r0 0xffff_ffff_ffff_ffff (ne? (fault "2")))
|
||||
|
||||
(se8 r0 0x0f)
|
||||
(cmp r0 0x0f (ne? (fault "3")))
|
||||
|
||||
(se32 r0 0x8000_0000)
|
||||
(cmp r0 0xffff_ffff_8000_0000 (ne? (fault "4")))
|
||||
|
||||
(se32 r0 0x7000_0000)
|
||||
(cmp r0 0x7000_0000 (ne? (fault "5")))
|
||||
|
||||
(clz r0 0xFF)
|
||||
(cmp r0 56 (ne? (fault "6")))
|
||||
|
||||
(clz r0 0)
|
||||
(cmp r0 64 (ne? (fault "7")))
|
||||
|
||||
(clz r0 0x0FFF_FFFF_FFFF_FFFF)
|
||||
(cmp r0 4 (ne? (fault "8")))
|
||||
|
||||
(clz32 r0 0xFF)
|
||||
(cmp r0 24 (ne? (fault "9")))
|
||||
|
||||
(clz32/16 r0 0x00ff_0000_0000)
|
||||
(cmp r0 8 (ne? (fault "10")))
|
||||
|
||||
(clz32/16 r0 0x0000_0000_0000)
|
||||
(cmp r0 32 (ne? (fault "11")))
|
||||
|
||||
(clo r0 0)
|
||||
(cmp r0 0 (ne? (fault "12")))
|
||||
(clo16 r0 0)
|
||||
(cmp r0 0 (ne? (fault "12b")))
|
||||
(clo r0 123456)
|
||||
(cmp r0 0 (ne? (fault "13")))
|
||||
|
||||
(clo r0 0xff00_0000_0000_0000)
|
||||
(cmp r0 8 (ne? (fault "14")))
|
||||
)
|
||||
+2
-2
@@ -4,8 +4,8 @@ set -e
|
||||
|
||||
cargo build
|
||||
|
||||
for file in examples/*.csn
|
||||
for file in examples/test_*.csn
|
||||
do
|
||||
echo "--- $file ---"
|
||||
target/debug/launcher -P "$file"
|
||||
target/debug/launcher "$file"
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user