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
|
; Count leading zeros
|
||||||
(clz Wr Rd)
|
(clz Wr Rd)
|
||||||
(clz RW)
|
(clz RW)
|
||||||
|
; Count leading zeros in the lower XX bits
|
||||||
; Count leading zeros in the lower 32 bits
|
(clzXX Wr Rd)
|
||||||
(clz32 Wr Rd)
|
(clzXX RW)
|
||||||
(clz32 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)
|
||||||
; Count leading zeros in the lower 16 bits
|
(clzXX/YY RW)
|
||||||
(clz16 Wr Rd)
|
|
||||||
(clz16 RW)
|
|
||||||
|
|
||||||
; Count leading zeros in the lower byte
|
|
||||||
(clz8 Wr Rd)
|
|
||||||
(clz8 RW)
|
|
||||||
|
|
||||||
; Count leading ones
|
; Count leading ones
|
||||||
(clo Wr Rd)
|
(clo Wr Rd)
|
||||||
(clo RW)
|
(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
|
; Sign extend a XX-bit value to 64 bits, XX in range 1..63)
|
||||||
(clo32 Wr Rd)
|
(seXX Wr Rd)
|
||||||
(clo32 RW)
|
(seXX 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)
|
|
||||||
|
|
||||||
; AND A&B
|
; AND A&B
|
||||||
(and Wr Rd Rd)
|
(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),
|
Chars(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub struct BitSlice {
|
pub struct BitSlice {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub src_pos: u32,
|
pub src_pos: u32,
|
||||||
@@ -80,7 +80,50 @@ impl BitSlice {
|
|||||||
Self::default()
|
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> {
|
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()) {
|
if !src.starts_with(|c: char| c.is_ascii_digit()) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
@@ -97,6 +140,10 @@ impl BitSlice {
|
|||||||
dst_pos: numbers.get(1).copied().unwrap_or(0)
|
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
|
// Validation
|
||||||
if slice.src_pos + slice.width > 64 {
|
if slice.src_pos + slice.width > 64 {
|
||||||
return Err(CrsnError::Parse("Invalid source bit slice".into(), pos.clone()));
|
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::asm::data::{Rd, Wr};
|
||||||
|
use crsn::builtin::defs::BitSlice;
|
||||||
|
|
||||||
/// A low level instruction
|
/// A low level instruction
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -8,22 +9,22 @@ pub enum ArithOp {
|
|||||||
RangeTest { val: Rd, a: Rd, b: Rd },
|
RangeTest { val: Rd, a: Rd, b: Rd },
|
||||||
Rng { dst: Wr, min: Rd, max: Rd },
|
Rng { dst: Wr, min: Rd, max: Rd },
|
||||||
|
|
||||||
|
/// Swap halves
|
||||||
Sw32 { dst: Wr, src: Rd },
|
Sw32 { dst: Wr, src: Rd },
|
||||||
|
/// Swap adjacent half-words
|
||||||
Sw16 { dst: Wr, src: Rd },
|
Sw16 { dst: Wr, src: Rd },
|
||||||
|
/// Swap neighbouring bytes
|
||||||
Sw8 { dst: Wr, src: Rd },
|
Sw8 { dst: Wr, src: Rd },
|
||||||
|
/// Reverse bytes
|
||||||
Rev { dst: Wr, src: Rd },
|
Rev { dst: Wr, src: Rd },
|
||||||
|
/// Reverse bits
|
||||||
Rbit { dst: Wr, src: Rd },
|
Rbit { dst: Wr, src: Rd },
|
||||||
Clz { dst: Wr, src: Rd },
|
/// Count leading zeros in a slice
|
||||||
Clz32 { dst: Wr, src: Rd },
|
Clz { dst: Wr, src: Rd, slice: BitSlice },
|
||||||
Clz16 { dst: Wr, src: Rd },
|
/// Count leading ones in a slice
|
||||||
Clz8 { dst: Wr, src: Rd },
|
Clo { dst: Wr, src: Rd, slice: BitSlice },
|
||||||
Clo { dst: Wr, src: Rd },
|
/// Sign extend a slice (zero aligned)
|
||||||
Clo32 { dst: Wr, src: Rd },
|
SignExtend { dst: Wr, src: Rd, slice: BitSlice },
|
||||||
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 },
|
|
||||||
|
|
||||||
Add { dst: Wr, a: Rd, b: Rd },
|
Add { dst: Wr, a: Rd, b: Rd },
|
||||||
Sub { dst: Wr, a: Rd, b: Rd },
|
Sub { dst: Wr, a: Rd, b: Rd },
|
||||||
@@ -44,4 +45,19 @@ pub enum ArithOp {
|
|||||||
// Shift
|
// Shift
|
||||||
Lsr { dst: Wr, a: Rd, n: Rd },
|
Lsr { dst: Wr, a: Rd, n: Rd },
|
||||||
Asr { 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
@@ -250,91 +250,34 @@ impl OpTrait for ArithOp {
|
|||||||
let res = val.reverse_bits();
|
let res = val.reverse_bits();
|
||||||
state.write(dst, res)?;
|
state.write(dst, res)?;
|
||||||
}
|
}
|
||||||
ArithOp::Clz { dst, src } => {
|
ArithOp::Clz { dst, src, slice } => {
|
||||||
state.clear_status();
|
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;
|
let res = val.leading_zeros() as u64;
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
state.write(dst, res)?;
|
state.write(dst, res)?;
|
||||||
}
|
}
|
||||||
ArithOp::Clz32 { dst, src } => {
|
ArithOp::Clo { dst, src, slice } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let val = state.read(src)?;
|
let mut val = ((state.read(src)? >> slice.src_pos) << (64 - slice.width));
|
||||||
let res = (((val & 0xFFFF_FFFF) << 32) | 0xFFFF_FFFF).leading_zeros() as u64;
|
if !slice.is_full() {
|
||||||
state.update_status(res);
|
val &= ((1 << slice.width) - 1) << slice.src_pos;
|
||||||
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 res = val.leading_ones() as u64;
|
let res = val.leading_ones() as u64;
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
state.write(dst, res)?;
|
state.write(dst, res)?;
|
||||||
}
|
}
|
||||||
ArithOp::Clo32 { dst, src } => {
|
ArithOp::SignExtend { dst, src, slice } => {
|
||||||
state.clear_status();
|
state.clear_status();
|
||||||
let val = state.read(src)?;
|
let val = state.read(src)?;
|
||||||
let res = ((val & 0xFFFF_FFFF) << 32).leading_ones() as u64;
|
|
||||||
state.update_status(res);
|
let res = if 0 != (val & (1 << (slice.width - 1))) {
|
||||||
state.write(dst, res)?;
|
val | (((1 << (64 - slice.width)) - 1) << slice.width)
|
||||||
}
|
|
||||||
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
|
|
||||||
} else {
|
} else {
|
||||||
val & 0xFFFF_FFFF
|
val & ((1 << slice.width) - 1)
|
||||||
};
|
|
||||||
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
|
|
||||||
};
|
};
|
||||||
state.update_status(res);
|
state.update_status(res);
|
||||||
state.write(dst, 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::Sw8 { dst, src } => to_sexp_1_or_2("sw8", dst, src),
|
||||||
ArithOp::Rev { dst, src } => to_sexp_1_or_2("rev", 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::Rbit { dst, src } => to_sexp_1_or_2("rbit", dst, src),
|
||||||
ArithOp::Clz { dst, src } => to_sexp_1_or_2("clz", dst, src),
|
ArithOp::Clz { dst, src, slice } => to_sexp_1_or_2(&format!("clz{}", slice), dst, src),
|
||||||
ArithOp::Clz32 { dst, src } => to_sexp_1_or_2("clz32", dst, src),
|
ArithOp::Clo { dst, src, slice } => to_sexp_1_or_2(&format!("clo{}", slice), dst, src),
|
||||||
ArithOp::Clz16 { dst, src } => to_sexp_1_or_2("clz16", dst, src),
|
ArithOp::SignExtend { dst, src, slice } => to_sexp_1_or_2(&format!("se{}", slice), 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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+68
-244
@@ -6,8 +6,9 @@ use crsn::module::ParseRes;
|
|||||||
use crsn::sexp::SourcePosition;
|
use crsn::sexp::SourcePosition;
|
||||||
|
|
||||||
use crate::defs::ArithOp;
|
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 {
|
Ok(ParseRes::ext(match keyword {
|
||||||
"cmp" => {
|
"cmp" => {
|
||||||
ArithOp::Compare {
|
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" => {
|
other => {
|
||||||
match args.len() {
|
if let Some(s) = other.strip_prefix("clz") {
|
||||||
2 => {
|
if let Some(slice) = BitSlice::parse2(s, op_pos)? {
|
||||||
ArithOp::Clz {
|
return Ok(ParseRes::ext(match args.len() {
|
||||||
dst: args.next_wr()?,
|
2 => {
|
||||||
src: args.next_rd()?,
|
ArithOp::Clz { dst: args.next_wr()?, src: args.next_rd()?, slice }
|
||||||
}
|
}
|
||||||
}
|
1 => {
|
||||||
1 => {
|
let dst = args.next_rdwr()?;
|
||||||
let dst = args.next_rdwr()?;
|
ArithOp::Clz { dst: dst.wr(), src: dst.rd(), slice }
|
||||||
ArithOp::Clz {
|
}
|
||||||
dst: dst.wr(),
|
_ => {
|
||||||
src: dst.rd(),
|
return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), op_pos.clone()));
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
_ => {
|
|
||||||
return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), pos.clone()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
"clz32" => {
|
if let Some(s) = other.strip_prefix("clo") {
|
||||||
match args.len() {
|
if let Some(slice) = BitSlice::parse2(s, op_pos)? {
|
||||||
2 => {
|
return Ok(ParseRes::ext(match args.len() {
|
||||||
ArithOp::Clz32 {
|
2 => {
|
||||||
dst: args.next_wr()?,
|
ArithOp::Clo { dst: args.next_wr()?, src: args.next_rd()?, slice }
|
||||||
src: args.next_rd()?,
|
}
|
||||||
}
|
1 => {
|
||||||
}
|
let dst = args.next_rdwr()?;
|
||||||
1 => {
|
ArithOp::Clo { dst: dst.wr(), src: dst.rd(), slice }
|
||||||
let dst = args.next_rdwr()?;
|
}
|
||||||
ArithOp::Clz32 {
|
_ => {
|
||||||
dst: dst.wr(),
|
return Err(CrsnError::Parse("Clz requires 1 or 2 arguments".into(), op_pos.clone()));
|
||||||
src: dst.rd(),
|
}
|
||||||
}
|
}));
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(CrsnError::Parse("Clz32 requires 1 or 2 arguments".into(), pos.clone()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
"clz16" => {
|
if let Some(s) = other.strip_prefix("se") {
|
||||||
match args.len() {
|
if let Some(slice) = BitSlice::parse1(s, op_pos)? {
|
||||||
2 => {
|
if slice.is_full() {
|
||||||
ArithOp::Clz16 {
|
return Err(CrsnError::Parse("Sign extend requires a bit size (< 64)".into(), op_pos.clone()));
|
||||||
dst: args.next_wr()?,
|
|
||||||
src: args.next_rd()?,
|
|
||||||
}
|
}
|
||||||
}
|
return Ok(ParseRes::ext(match args.len() {
|
||||||
1 => {
|
2 => {
|
||||||
let dst = args.next_rdwr()?;
|
ArithOp::SignExtend { dst: args.next_wr()?, src: args.next_rd()?, slice }
|
||||||
ArithOp::Clz16 {
|
}
|
||||||
dst: dst.wr(),
|
1 => {
|
||||||
src: dst.rd(),
|
let dst = args.next_rdwr()?;
|
||||||
}
|
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));
|
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
|
cargo build
|
||||||
|
|
||||||
for file in examples/*.csn
|
for file in examples/test_*.csn
|
||||||
do
|
do
|
||||||
echo "--- $file ---"
|
echo "--- $file ---"
|
||||||
target/debug/launcher -P "$file"
|
target/debug/launcher "$file"
|
||||||
done
|
done
|
||||||
|
|||||||
Reference in New Issue
Block a user