From c953e39b3404e3095b918bc2fe4c2518f7415fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 11 Oct 2020 22:01:12 +0200 Subject: [PATCH] Add ld{32,16,8},sw{32,16,8},clz{,32,16,8},clo{,32,16,8},rng,rev,rbit; rename swap->xch --- Cargo.lock | 1 + README.md | 77 +++++++++- crsn/src/asm/data/rd.rs | 9 ++ crsn/src/builtin/defs.rs | 12 +- crsn/src/builtin/exec.rs | 30 +++- crsn/src/builtin/parse.rs | 45 ++++-- crsn_arith/Cargo.toml | 1 + crsn_arith/src/defs.rs | 15 ++ crsn_arith/src/exec.rs | 149 +++++++++++++++++-- crsn_arith/src/parse.rs | 302 ++++++++++++++++++++++++++++++++++++++ examples/random.csn | 9 ++ 11 files changed, 619 insertions(+), 31 deletions(-) create mode 100644 examples/random.csn diff --git a/Cargo.lock b/Cargo.lock index 224f89d..22f235e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,6 +189,7 @@ version = "0.1.0" dependencies = [ "crsn", "num-traits", + "rand 0.7.3", ] [[package]] diff --git a/README.md b/README.md index b403e4b..0c14bfb 100644 --- a/README.md +++ b/README.md @@ -311,14 +311,23 @@ Jumping to a label is always safer than a manual skip. ; Skip backward or forward (s Rd) -; Copy value +; Copy a value (ld Wr Rd) -; Copy N values. This is especially useful when used with stream handles or buffers. +; Copy a value N times. This is useful when used with stream handles or buffers. (ldn Wr Rd Rd:count) -; Swap values -(swap RW RW) +; Copy 32 bits of a value +(ld32 Wr Rd) + +; Copy 16 bits of a value +(ld16 Wr Rd) + +; Copy 8 bits of a value +(ld8 Wr Rd) + +; Exchange two register's values +(xch RW RW) ; Store status flags to a register (stf Wr) @@ -373,6 +382,11 @@ Many instructions have two forms: ; Sets the EQ, LT and GT flags. Also sets Z, POS and NEG based on the value. (rcmp Rd:val Rd:start Rd:end) +; Get a random number +(rng Wr) ; the value will fill all 64 bits of the target +(rng Wr Rd:max) ; 0 to max, max is inclusive +(rng Wr Rd:min Rd:max) ; min to max, both are inclusive + ; Add A+B (add Wr Rd Rd) (add RW Rd) @@ -400,6 +414,61 @@ Many instructions have two forms: (mod Wr Rd Rd:divider) (mod RW Rd:divider) +; Swap the 32-bit halves of a value +; 0x01234567_89abcdef -> 0x89abcdef_01234567 +(sw32 Wr Rd) +(sw32 RW) + +; Swap 16-bit halves of each 32-bit part +; 0x0123_4567_89ab_cdef -> 0x4567_0123_cdef_89ab +(sw16 Wr Rd) +(sw16 RW) + +; Swap bytes in each 16-bit part +; 0x01_23_45_67_89_ab_cd_ef -> 0x23_01_67_45_ab_89_ef_cd +(sw8 Wr Rd) +(sw8 RW) + +; Reverse endian (byte order) +(rev Wr Rd) +(rev RW) + +; Reverse bit order +(rbit Wr Rd) +(rbit RW) + +; 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 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) + ; AND A&B (and Wr Rd Rd) (and RW Rd) diff --git a/crsn/src/asm/data/rd.rs b/crsn/src/asm/data/rd.rs index 73b12e5..5631f2e 100644 --- a/crsn/src/asm/data/rd.rs +++ b/crsn/src/asm/data/rd.rs @@ -15,6 +15,15 @@ impl Rd { pub const fn immediate(val: Value) -> Rd { Rd(RdData::Immediate(val)) } + + pub fn is_immediate_equal(self, other: Value) -> bool { + match self.0 { + RdData::Immediate(val) => { + val == other + } + _ => false + } + } } impl From<&Rd> for Rd { diff --git a/crsn/src/builtin/defs.rs b/crsn/src/builtin/defs.rs index 0724379..f01b30d 100644 --- a/crsn/src/builtin/defs.rs +++ b/crsn/src/builtin/defs.rs @@ -71,11 +71,17 @@ pub enum BuiltinOp { /// The object is released and the handle becomes invalid. Delete(RdObj), /// Move a value - MoveValue { dst: Wr, src: Rd }, + Move { dst: Wr, src: Rd }, + /// Move lower 32 bits + Move32 { dst: RdWr, src: Rd }, + /// Move lower 16 bits + Move16 { dst: RdWr, src: Rd }, + /// Move lower 8 bits + Move8 { dst: RdWr, src: Rd }, /// Move N values - MoveMultipleValues { dst: Wr, src: Rd, count: Rd }, + MoveMultiple { dst: Wr, src: Rd, count: Rd }, /// Swap two registers - SwapValues { a: RdWr, b: RdWr }, + Exchange { a: RdWr, b: RdWr }, /// Store runtime status to a register StoreFlags { dst: Wr }, /// Load runtime status from a register diff --git a/crsn/src/builtin/exec.rs b/crsn/src/builtin/exec.rs index 4e174cf..5d05eba 100644 --- a/crsn/src/builtin/exec.rs +++ b/crsn/src/builtin/exec.rs @@ -103,13 +103,13 @@ impl OpTrait for BuiltinOp { let pc = state.get_pc(); program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?; } - BuiltinOp::MoveValue { dst, src } => { + BuiltinOp::Move { dst, src } => { state.clear_status(); let val = state.read(src)?; state.update_status(val); state.write(dst, val)?; } - BuiltinOp::MoveMultipleValues { dst, src, count } => { + BuiltinOp::MoveMultiple { dst, src, count } => { state.clear_status(); let mut count = state.read(count)?; let mut last = 0; @@ -120,7 +120,31 @@ impl OpTrait for BuiltinOp { } state.update_status(last); } - BuiltinOp::SwapValues { a, b } => { + BuiltinOp::Move32 { dst, src } => { + state.clear_status(); + let new = state.read(src)?; + let old = state.read(dst)?; + let val = (old & !0xFFFFFFFF) | (new & 0xFFFFFFFF); + state.update_status(val); + state.write(dst, val)?; + } + BuiltinOp::Move16 { dst, src } => { + state.clear_status(); + let new = state.read(src)?; + let old = state.read(dst)?; + let val = (old & !0xFFFF) | (new & 0xFFFF); + state.update_status(val); + state.write(dst, val)?; + } + BuiltinOp::Move8 { dst, src } => { + state.clear_status(); + let new = state.read(src)?; + let old = state.read(dst)?; + let val = (old & !0xFF) | (new & 0xFF); + state.update_status(val); + state.write(dst, val)?; + } + BuiltinOp::Exchange { a, b } => { let aa = state.read(a)?; let bb = state.read(b)?; state.write(a, bb)?; diff --git a/crsn/src/builtin/parse.rs b/crsn/src/builtin/parse.rs index 9e965aa..de5bd44 100644 --- a/crsn/src/builtin/parse.rs +++ b/crsn/src/builtin/parse.rs @@ -183,22 +183,43 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok } "ld" => { - BuiltinOp::MoveValue { + BuiltinOp::Move { dst: args.next_wr()?, src: args.next_rd()?, } } + "ld32" => { + BuiltinOp::Move32 { + dst: args.next_rdwr()?, + src: args.next_rd()?, + } + } + + "ld16" => { + BuiltinOp::Move16 { + dst: args.next_rdwr()?, + src: args.next_rd()?, + } + } + + "ld8" => { + BuiltinOp::Move8 { + dst: args.next_rdwr()?, + src: args.next_rd()?, + } + } + "ldn" => { - BuiltinOp::MoveMultipleValues { + BuiltinOp::MoveMultiple { dst: args.next_wr()?, src: args.next_rd()?, count: args.next_rd()?, } } - "swap" => { - BuiltinOp::SwapValues { + "xch" => { + BuiltinOp::Exchange { a: args.next_rdwr()?, b: args.next_rdwr()?, } @@ -316,11 +337,14 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { } } BuiltinOp::Delete(obj) => sexp::list(&[A("del"), A(obj)]), - BuiltinOp::MoveValue { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]), - BuiltinOp::MoveMultipleValues { dst, src, count } => sexp::list(&[A("ldn"), A(dst), A(src), A(count)]), - BuiltinOp::SwapValues { a, b } => sexp::list(&[A("swap"), A(a), A(b)]), + BuiltinOp::Move { dst, src } => sexp::list(&[A("ld"), A(dst), A(src)]), + BuiltinOp::Move32 { dst, src } => sexp::list(&[A("ld32"), A(dst), A(src)]), + BuiltinOp::Move16 { dst, src } => sexp::list(&[A("ld16"), A(dst), A(src)]), + BuiltinOp::Move8 { dst, src } => sexp::list(&[A("ld8"), A(dst), A(src)]), + BuiltinOp::MoveMultiple { dst, src, count } => sexp::list(&[A("ldn"), A(dst), A(src), A(count)]), + BuiltinOp::Exchange { a, b } => sexp::list(&[A("xch"), A(a), A(b)]), BuiltinOp::StoreFlags { dst } => sexp::list(&[A("stf"), A(dst)]), - BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)]) + BuiltinOp::LoadFlags { src } => sexp::list(&[A("ldf"), A(src)]), } } @@ -387,8 +411,11 @@ mod test { ("(fault)", "(fault)"), ("(fault kur*a)", "(fault kur*a)"), ("(fault \"do pr*ele\")", "(fault \"do pr*ele\")"), - ("(swap r0 r1)", "(swap r0 r1)"), + ("(xchxch r0 r1)", "(xch r0 r1)"), ("(ld r0 r0)", "(ld r0 r0)"), + ("(ld8 r0 r1)", "(ld8 r0 r1)"), + ("(ld16 r0 r1)", "(ld16 r0 r1)"), + ("(ld32 r0 r1)", "(ld32 r0 r1)"), ("(ld r0 156)", "(ld r0 156)"), ("(ld _ -32767)", "(ld _ -32767)"), ("(ldn _ @r0 7)", "(ldn _ @r0 7)"), diff --git a/crsn_arith/Cargo.toml b/crsn_arith/Cargo.toml index 516c09c..7504dfa 100644 --- a/crsn_arith/Cargo.toml +++ b/crsn_arith/Cargo.toml @@ -9,3 +9,4 @@ edition = "2018" [dependencies] crsn = { path = "../crsn" } num-traits = "0.2.12" +rand = "0.7.3" diff --git a/crsn_arith/src/defs.rs b/crsn_arith/src/defs.rs index f8423a1..a9470db 100644 --- a/crsn_arith/src/defs.rs +++ b/crsn_arith/src/defs.rs @@ -6,6 +6,21 @@ pub enum ArithOp { Test { a: Rd }, Compare { a: Rd, b: Rd }, RangeTest { val: Rd, a: Rd, b: Rd }, + Rng { dst: Wr, min: Rd, max: Rd }, + + Sw32 { dst: Wr, src: Rd }, + Sw16 { dst: Wr, src: Rd }, + Sw8 { dst: Wr, src: Rd }, + Rev { dst: Wr, src: Rd }, + 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 }, Add { dst: Wr, a: Rd, b: Rd }, Sub { dst: Wr, a: Rd, b: Rd }, diff --git a/crsn_arith/src/exec.rs b/crsn_arith/src/exec.rs index 09cb6e3..e9bd165 100644 --- a/crsn_arith/src/exec.rs +++ b/crsn_arith/src/exec.rs @@ -12,6 +12,7 @@ use crsn::utils::A; use crate::defs::ArithOp; use crsn::asm::instr::cond::Flag; +use rand::Rng; impl OpTrait for ArithOp { fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result { @@ -44,6 +45,29 @@ impl OpTrait for ArithOp { state.set_flag(Flag::Greater, val > b); state.update_status(val); } + ArithOp::Rng { dst, min, max } => { + state.clear_status(); + let min = state.read(min)?; + let mut max = state.read(max)?; + + let val = if min == max { + min + } else if min > max { + state.set_flag(Flag::Invalid, true); + min + } else { + let offset = min; + max -= min; + + offset + if max == u64::MAX { + rand::thread_rng().gen() + } else { + rand::thread_rng().gen_range(0, max) + } + }; + state.write(dst, val)?; + state.update_status(val); + } ArithOp::Add { dst, a, b } => { state.clear_status(); let x = state.read(a)?; @@ -201,6 +225,87 @@ impl OpTrait for ArithOp { state.write(dst, res)?; } } + ArithOp::Sw32 { dst, src } => { + let val = state.read(src)?; + let res = ((val & 0xFFFF_FFFF) << 32) | ((val & !0xFFFF_FFFF) >> 32); + state.write(dst, res)?; + } + ArithOp::Sw16 { dst, src } => { + let val = state.read(src)?; + let res = ((val & 0x0000_FFFF_0000_FFFF) << 16) | ((val & 0xFFFF_0000_FFFF_0000) >> 16); + state.write(dst, res)?; + } + ArithOp::Sw8 { dst, src } => { + let val = state.read(src)?; + let res = ((val & 0x00FF_00FF_00FF_00FF) << 8) | ((val & 0xFF00_FF00_FF00_FF00) >> 8); + state.write(dst, res)?; + } + ArithOp::Rev { dst, src } => { + let val = state.read(src)?; + let res = val.swap_bytes(); + state.write(dst, res)?; + } + ArithOp::Rbit { dst, src } => { + let val = state.read(src)?; + let res = val.reverse_bits(); + state.write(dst, res)?; + } + ArithOp::Clz { dst, src } => { + state.clear_status(); + let val = state.read(src)?; + 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 } => { + 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 } => { + 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)?; + } } Ok(eres) @@ -212,15 +317,20 @@ impl OpTrait for ArithOp { ArithOp::Test { a } => sexp::list(&[A("test"), A(a)]), ArithOp::Compare { a, b } => sexp::list(&[A("cmp"), A(a), A(b)]), ArithOp::RangeTest { val, a: start, b: end } => sexp::list(&[A("rcmp"), A(val), A(start), A(end)]), + ArithOp::Rng { dst, min, max } => { + if min.is_immediate_equal(0) && max.is_immediate_equal(u64::MAX) { + sexp::list(&[A("rng"), A(dst)]) + } else if min.is_immediate_equal(0) { + sexp::list(&[A("rng"), A(dst), A(max)]) + } else { + sexp::list(&[A("rng"), A(dst), A(min), A(max)]) + } + } ArithOp::Sub { dst, a, b } => to_sexp_2_or_3("sub", dst, a, b), ArithOp::Mul { dst, a, b } => to_sexp_2_or_3("mul", dst, a, b), ArithOp::Div { dst, rem, a, div } => { if rem.is_discard() { - if &dst.as_rd() == a { - sexp::list(&[A("div"), A(dst), A(div)]) - } else { - sexp::list(&[A("div"), A(dst), A(a), A(div)]) - } + to_sexp_2_or_3("div", dst, a, div) } else { if &dst.as_rd() == a { sexp::list(&[A("divr"), A(dst), A(rem), A(div)]) @@ -233,18 +343,25 @@ impl OpTrait for ArithOp { ArithOp::And { dst, a, b } => to_sexp_2_or_3("and", dst, a, b), ArithOp::Or { dst, a, b } => to_sexp_2_or_3("or", dst, a, b), ArithOp::Xor { dst, a, b } => to_sexp_2_or_3("xor", dst, a, b), - ArithOp::Cpl { dst, a } => { - if &dst.as_rd() == a { - sexp::list(&[A("cpl"), A(dst)]) - } else { - sexp::list(&[A("cpl"), A(dst), A(a)]) - } - } + ArithOp::Cpl { dst, a } => to_sexp_1_or_2("cpl", dst, a), ArithOp::Rol { dst, a, n } => to_sexp_2_or_3("rol", dst, a, n), ArithOp::Ror { dst, a, n } => to_sexp_2_or_3("ror", dst, a, n), ArithOp::Lsl { dst, a, n } => to_sexp_2_or_3("lsl", dst, a, n), ArithOp::Lsr { dst, a, n } => to_sexp_2_or_3("lsr", dst, a, n), ArithOp::Asr { dst, a, n } => to_sexp_2_or_3("asr", dst, a, n), + ArithOp::Sw32 { dst, src } => to_sexp_1_or_2("sw32", dst, src), + ArithOp::Sw16 { dst, src } => to_sexp_1_or_2("sw16", 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::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), } } } @@ -256,3 +373,11 @@ fn to_sexp_2_or_3(name: &str, dst: &Wr, a: &Rd, b: &Rd) -> Sexp { sexp::list(&[A(name), A(dst), A(a), A(b)]) } } + +fn to_sexp_1_or_2(name: &str, dst: &Wr, src: &Rd) -> Sexp { + if &dst.as_rd() == src { + sexp::list(&[A(name), A(dst)]) + } else { + sexp::list(&[A(name), A(dst), A(src)]) + } +} diff --git a/crsn_arith/src/parse.rs b/crsn_arith/src/parse.rs index d00d1a9..5a26bf6 100644 --- a/crsn_arith/src/parse.rs +++ b/crsn_arith/src/parse.rs @@ -29,6 +29,35 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars ArithOp::Test { a: arg } } + "rng" => { + match args.len() { + 1 => { + ArithOp::Rng { + dst: args.next_wr()?, + min: Rd::immediate(0), + max: Rd::immediate(u64::MAX), + } + } + 2 => { + ArithOp::Rng { + dst: args.next_wr()?, + min: Rd::immediate(0), + max: args.next_rd()?, + } + } + 3 => { + ArithOp::Rng { + dst: args.next_wr()?, + min: args.next_rd()?, + max: args.next_rd()?, + } + } + _ => { + return Err(CrsnError::Parse("Rng requires 1, 2 or 3 arguments".into(), pos.clone())); + } + } + } + "inc" => { let dst = args.next_rdwr()?; ArithOp::Add { @@ -438,6 +467,279 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars } } + "sw32" => { + match args.len() { + 2 => { + ArithOp::Sw32 { + dst: args.next_wr()?, + src: args.next_rd()?, + } + } + 1 => { + let dst = args.next_rdwr()?; + ArithOp::Sw32 { + dst: dst.wr(), + src: dst.rd(), + } + } + _ => { + return Err(CrsnError::Parse("SW32 requires 1 or 2 arguments".into(), pos.clone())); + } + } + } + + "sw16" => { + match args.len() { + 2 => { + ArithOp::Sw16 { + dst: args.next_wr()?, + src: args.next_rd()?, + } + } + 1 => { + let dst = args.next_rdwr()?; + ArithOp::Sw16 { + dst: dst.wr(), + src: dst.rd(), + } + } + _ => { + return Err(CrsnError::Parse("SW16 requires 1 or 2 arguments".into(), pos.clone())); + } + } + } + + "sw8" => { + match args.len() { + 2 => { + ArithOp::Sw8 { + dst: args.next_wr()?, + src: args.next_rd()?, + } + } + 1 => { + let dst = args.next_rdwr()?; + ArithOp::Sw8 { + dst: dst.wr(), + src: dst.rd(), + } + } + _ => { + return Err(CrsnError::Parse("SW8 requires 1 or 2 arguments".into(), pos.clone())); + } + } + } + + "rev" => { + match args.len() { + 2 => { + ArithOp::Rev { + dst: args.next_wr()?, + src: args.next_rd()?, + } + } + 1 => { + let dst = args.next_rdwr()?; + ArithOp::Rev { + dst: dst.wr(), + src: dst.rd(), + } + } + _ => { + return Err(CrsnError::Parse("REV requires 1 or 2 arguments".into(), pos.clone())); + } + } + } + + "rbit" => { + match args.len() { + 2 => { + ArithOp::Rbit { + dst: args.next_wr()?, + src: args.next_rd()?, + } + } + 1 => { + let dst = args.next_rdwr()?; + ArithOp::Rbit { + dst: dst.wr(), + src: dst.rd(), + } + } + _ => { + return Err(CrsnError::Parse("RBIT requires 1 or 2 arguments".into(), 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())); + } + } + } + + "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())); + } + } + } + + "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(), + } + } + _ => { + return Err(CrsnError::Parse("Clz16 requires 1 or 2 arguments".into(), 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())); + } + } + } + _other => { return Ok(ParseRes::Unknown(args)); } diff --git a/examples/random.csn b/examples/random.csn new file mode 100644 index 0000000..1c0a73c --- /dev/null +++ b/examples/random.csn @@ -0,0 +1,9 @@ +( + ; Print 2000 random ascii characters + (ld r0 2000) + (:n) + (rng @cout 32 126) + (dec r0) + (j.nz :n) + (ld @cout '\n') +)