Browse Source

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

pull/21/head
Ondřej Hruška 2 years ago
parent
commit
26616e20cb
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 52
      README.md
  2. 11
      compile_examples.sh
  3. 49
      crsn/src/builtin/defs.rs
  4. 38
      crsn_arith/src/defs.rs
  5. 101
      crsn_arith/src/exec.rs
  6. 312
      crsn_arith/src/parse.rs
  7. 0
      examples/test_arities.csn
  8. 0
      examples/test_bfio.csn
  9. 44
      examples/test_clz_clo_se.csn
  10. 0
      examples/test_globals.csn
  11. 0
      examples/test_globals_sym.csn
  12. 0
      examples/test_ldbits.csn
  13. 0
      examples/test_stacks.csn
  14. 4
      test_examples.sh

52
README.md

@ -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 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)
; 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)
; 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)

11
compile_examples.sh

@ -0,0 +1,11 @@
#!/bin/bash
set -e
cargo build
for file in examples/*.csn
do
echo "--- $file ---"
target/debug/launcher -P "$file"
done

49
crsn/src/builtin/defs.rs

@ -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()));

38
crsn_arith/src/defs.rs

@ -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 },
}

101
crsn_arith/src/exec.rs

@ -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 } => {
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 } => {
ArithOp::Clo { dst, src, slice } => {
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
} 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
let res = if 0 != (val & (1 << (slice.width - 1))) {
val | (((1 << (64 - slice.width)) - 1) << slice.width)
} 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),
}
}
}

312
crsn_arith/src/parse.rs

@ -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()?,
}
}
1 => {
let dst = args.next_rdwr()?;
ArithOp::Clz16 {
dst: dst.wr(),
src: dst.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 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));
}
}))

0
examples/arities.csn → examples/test_arities.csn

0
examples/buf_io.csn → examples/test_bfio.csn

44
examples/test_clz_clo_se.csn

@ -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")))
)

0
examples/globals.csn → examples/test_globals.csn

0
examples/globals_sym.csn → examples/test_globals_sym.csn

0
examples/ldbits.csn → examples/test_ldbits.csn

0
examples/stacks.csn → examples/test_stacks.csn

4
test_examples.sh

@ -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

Loading…
Cancel
Save