Add ld{32,16,8},sw{32,16,8},clz{,32,16,8},clo{,32,16,8},rng,rev,rbit; rename swap->xch

floats
Ondřej Hruška 4 years ago
parent 4062ff4d09
commit c953e39b34
Signed by untrusted user: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 1
      Cargo.lock
  2. 77
      README.md
  3. 9
      crsn/src/asm/data/rd.rs
  4. 12
      crsn/src/builtin/defs.rs
  5. 30
      crsn/src/builtin/exec.rs
  6. 45
      crsn/src/builtin/parse.rs
  7. 1
      crsn_arith/Cargo.toml
  8. 15
      crsn_arith/src/defs.rs
  9. 149
      crsn_arith/src/exec.rs
  10. 302
      crsn_arith/src/parse.rs
  11. 9
      examples/random.csn

1
Cargo.lock generated

@ -189,6 +189,7 @@ version = "0.1.0"
dependencies = [
"crsn",
"num-traits",
"rand 0.7.3",
]
[[package]]

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

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

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

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

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

@ -9,3 +9,4 @@ edition = "2018"
[dependencies]
crsn = { path = "../crsn" }
num-traits = "0.2.12"
rand = "0.7.3"

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

@ -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<EvalRes, Fault> {
@ -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)])
}
}

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

@ -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')
)
Loading…
Cancel
Save