From 26616e20cb4be45aa4f78bab84354e52e53e249e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 16 Oct 2020 00:18:38 +0200 Subject: [PATCH] Simplify {clz,clo,se}XX parsing and exec, add simple unit test example scripts --- README.md | 52 +-- compile_examples.sh | 11 + crsn/src/builtin/defs.rs | 49 ++- crsn_arith/src/defs.rs | 38 ++- crsn_arith/src/exec.rs | 101 +----- crsn_arith/src/parse.rs | 312 ++++-------------- examples/{arities.csn => test_arities.csn} | 0 examples/{buf_io.csn => test_bfio.csn} | 0 examples/test_clz_clo_se.csn | 44 +++ examples/{globals.csn => test_globals.csn} | 0 .../{globals_sym.csn => test_globals_sym.csn} | 0 examples/{ldbits.csn => test_ldbits.csn} | 0 examples/{stacks.csn => test_stacks.csn} | 0 test_examples.sh | 4 +- 14 files changed, 234 insertions(+), 377 deletions(-) create mode 100755 compile_examples.sh rename examples/{arities.csn => test_arities.csn} (100%) rename examples/{buf_io.csn => test_bfio.csn} (100%) create mode 100644 examples/test_clz_clo_se.csn rename examples/{globals.csn => test_globals.csn} (100%) rename examples/{globals_sym.csn => test_globals_sym.csn} (100%) rename examples/{ldbits.csn => test_ldbits.csn} (100%) rename examples/{stacks.csn => test_stacks.csn} (100%) diff --git a/README.md b/README.md index 89e987c..6c2ebb7 100644 --- a/README.md +++ b/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) diff --git a/compile_examples.sh b/compile_examples.sh new file mode 100755 index 0000000..cdc0960 --- /dev/null +++ b/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 diff --git a/crsn/src/builtin/defs.rs b/crsn/src/builtin/defs.rs index 86adb3d..3bf1b65 100644 --- a/crsn/src/builtin/defs.rs +++ b/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, 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, 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, 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())); diff --git a/crsn_arith/src/defs.rs b/crsn_arith/src/defs.rs index 562395e..e15ecce 100644 --- a/crsn_arith/src/defs.rs +++ b/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 }, } diff --git a/crsn_arith/src/exec.rs b/crsn_arith/src/exec.rs index 64722e2..967812a 100644 --- a/crsn_arith/src/exec.rs +++ b/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), } } } diff --git a/crsn_arith/src/parse.rs b/crsn_arith/src/parse.rs index 67b42e6..8501dfe 100644 --- a/crsn_arith/src/parse.rs +++ b/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, CrsnError> { +pub(crate) fn parse<'a>(op_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result, 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)); } })) diff --git a/examples/arities.csn b/examples/test_arities.csn similarity index 100% rename from examples/arities.csn rename to examples/test_arities.csn diff --git a/examples/buf_io.csn b/examples/test_bfio.csn similarity index 100% rename from examples/buf_io.csn rename to examples/test_bfio.csn diff --git a/examples/test_clz_clo_se.csn b/examples/test_clz_clo_se.csn new file mode 100644 index 0000000..8f336a3 --- /dev/null +++ b/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"))) +) diff --git a/examples/globals.csn b/examples/test_globals.csn similarity index 100% rename from examples/globals.csn rename to examples/test_globals.csn diff --git a/examples/globals_sym.csn b/examples/test_globals_sym.csn similarity index 100% rename from examples/globals_sym.csn rename to examples/test_globals_sym.csn diff --git a/examples/ldbits.csn b/examples/test_ldbits.csn similarity index 100% rename from examples/ldbits.csn rename to examples/test_ldbits.csn diff --git a/examples/stacks.csn b/examples/test_stacks.csn similarity index 100% rename from examples/stacks.csn rename to examples/test_stacks.csn diff --git a/test_examples.sh b/test_examples.sh index cdc0960..8486f3a 100755 --- a/test_examples.sh +++ b/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