From 5b163e969f00af3c60b53900f97493f21a676afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 15 Oct 2020 00:53:59 +0200 Subject: [PATCH] add the "lds" instruction --- README.md | 6 ++++++ crsn/src/builtin/defs.rs | 8 ++++++++ crsn/src/builtin/exec.rs | 19 ++++++++++++++++-- crsn/src/builtin/parse.rs | 41 +++++++++++++++++++++++++++++++++++++-- examples/lds.csn | 4 ++++ 5 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 examples/lds.csn diff --git a/README.md b/README.md index ab6bbb0..25c17aa 100644 --- a/README.md +++ b/README.md @@ -326,6 +326,12 @@ Jumping to a label is always safer than a manual skip. ; Copy 8 bits of a value (ld8 Wr Rd) +; Write a sequence of values, or all codepoints from a string, into the destination. +; This is most useful with object handles, such as a buffer or @cout. +; Functionally, this instruction is equivalent to a sequence of "ld" +(lds Wr (Rd...)) ; example - (lds @cout (65 66 67)) +(lds Wr "string") + ; Exchange two register's values (xch RW RW) diff --git a/crsn/src/builtin/defs.rs b/crsn/src/builtin/defs.rs index f01b30d..173d710 100644 --- a/crsn/src/builtin/defs.rs +++ b/crsn/src/builtin/defs.rs @@ -30,6 +30,12 @@ impl SleepUnit { } } +#[derive(Clone, Debug, PartialEq)] +pub enum LdsValue { + Values(Vec), + Chars(String), +} + #[derive(Debug)] pub enum BuiltinOp { /// Do nothing (costs one cycle) @@ -80,6 +86,8 @@ pub enum BuiltinOp { Move8 { dst: RdWr, src: Rd }, /// Move N values MoveMultiple { dst: Wr, src: Rd, count: Rd }, + /// Move values from a string or integer list + MoveSequence { dst: Wr, value: LdsValue }, /// Swap two registers Exchange { a: RdWr, b: RdWr }, /// Store runtime status to a register diff --git a/crsn/src/builtin/exec.rs b/crsn/src/builtin/exec.rs index 5d05eba..02c798c 100644 --- a/crsn/src/builtin/exec.rs +++ b/crsn/src/builtin/exec.rs @@ -3,8 +3,8 @@ use std::time::Duration; use sexp::Sexp; use crate::asm::data::{Rd, RdData}; -use crate::asm::data::literal::Addr; -use crate::builtin::defs::{Barrier, BuiltinOp}; +use crate::asm::data::literal::{Addr, Value}; +use crate::builtin::defs::{Barrier, BuiltinOp, LdsValue}; use crate::module::{EvalRes, OpTrait}; use crate::runtime::fault::Fault; use crate::runtime::frame::StackFrame; @@ -144,6 +144,21 @@ impl OpTrait for BuiltinOp { state.update_status(val); state.write(dst, val)?; } + BuiltinOp::MoveSequence { dst, value } => { + match value { + LdsValue::Values(vals) => { + for val in vals { + let v = state.read(val)?; + state.write(dst, v)?; + } + } + LdsValue::Chars(string) => { + for val in string.chars() { + state.write(dst, val as Value)?; + } + } + } + } BuiltinOp::Exchange { a, b } => { let aa = state.read(a)?; let bb = state.read(b)?; diff --git a/crsn/src/builtin/parse.rs b/crsn/src/builtin/parse.rs index 779fde4..719c1d8 100644 --- a/crsn/src/builtin/parse.rs +++ b/crsn/src/builtin/parse.rs @@ -1,4 +1,4 @@ -use sexp::{Atom, Sexp, SourcePosition}; +use sexp::{Atom, Sexp, SourcePosition, atom_qs}; use crate::asm::data::literal::{RoutineName}; use crate::asm::data::reg::parse_reg; @@ -8,7 +8,7 @@ use crate::asm::parse::arg_parser::TokenParser; use crate::asm::parse::parse_data::{parse_constant_name, parse_label, parse_label_str, parse_rd, parse_reg_alias, parse_value}; use crate::asm::parse::sexp_expect::{expect_any_string_atom}; use crate::asm::patches::ErrWithPos; -use crate::builtin::defs::{Barrier, BuiltinOp, SleepUnit}; +use crate::builtin::defs::{Barrier, BuiltinOp, SleepUnit, LdsValue}; use crate::module::ParseRes; use crate::utils::A; @@ -218,6 +218,28 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok } } + "lds" => { + let dst = args.next_wr()?; + + let value = match args.next_or_err()? { + Sexp::Atom(Atom::QS(s), _) => { + LdsValue::Chars(s) + } + Sexp::List(list, _) => { + let mut vals = vec![]; + for v in list { + vals.push(parse_rd(v, args.pcx)?); + } + LdsValue::Values(vals) + } + other => { + return Err(CrsnError::Parse("Expected quoted string or a tuple of values".into(), other.pos().clone())); + } + }; + + BuiltinOp::MoveSequence { dst, value } + } + "xch" => { BuiltinOp::Exchange { a: args.next_rdwr()?, @@ -345,6 +367,19 @@ pub(crate) fn to_sexp(op: &BuiltinOp) -> Sexp { 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::MoveSequence { dst, value } => { + match value { + LdsValue::Values(vals) => { + let mut vals: Vec<_> = vals.iter().map(A).collect(); + vals.insert(0, A(dst)); + vals.insert(0, A("lds")); + sexp::list(&vals) + } + LdsValue::Chars(str) => { + sexp::list(&[A("lds"), A(dst), atom_qs(str)]) + } + } + } } } @@ -419,6 +454,8 @@ mod test { ("(ld r0 156)", "(ld r0 156)"), ("(ld _ -32767)", "(ld _ -32767)"), ("(ldn _ @r0 7)", "(ldn _ @r0 7)"), + ("(lds @r0 \"ahoj jak se mas\")", "(lds @r0 \"ahoj jak se mas\")"), + ("(lds @r0 (1 2 3 4 0x123 r6))", "(lds @r0 (1 2 3 4 0x123 r6))"), ("(stf r0)", "(stf r0)"), ("(ldf r0)", "(ldf r0)"), ("(far :label)", "(far :label)"), diff --git a/examples/lds.csn b/examples/lds.csn new file mode 100644 index 0000000..dc2ca57 --- /dev/null +++ b/examples/lds.csn @@ -0,0 +1,4 @@ +( + (lds @cout "ahoj jak se mas\n") + (lds @cout (65 66 67 68 69 70 10)) +)