diff --git a/src/isa/bytecode.rs b/src/isa/bytecode.rs index 92fda37..40b525a 100644 --- a/src/isa/bytecode.rs +++ b/src/isa/bytecode.rs @@ -218,7 +218,7 @@ impl Bytecode for ControlFlowOp { fn instr_byte(&self) -> u8 { match self { ControlFlowOp::Fail => INSTR_FAIL, - ControlFlowOp::Succ => INSTR_SUCC, + ControlFlowOp::Test => INSTR_TEST, ControlFlowOp::Jmp(_) => INSTR_JMP, ControlFlowOp::Jif(_) => INSTR_JIF, ControlFlowOp::Routine(_) => INSTR_ROUTINE, @@ -242,7 +242,7 @@ impl Bytecode for ControlFlowOp { { match self { ControlFlowOp::Fail => {} - ControlFlowOp::Succ => {} + ControlFlowOp::Test => {} ControlFlowOp::Jmp(pos) | ControlFlowOp::Jif(pos) | ControlFlowOp::Routine(pos) => { writer.write_u16(*pos)? } @@ -261,7 +261,7 @@ impl Bytecode for ControlFlowOp { { Ok(match reader.read_u8()? { INSTR_FAIL => Self::Fail, - INSTR_SUCC => Self::Succ, + INSTR_TEST => Self::Test, INSTR_JMP => Self::Jmp(reader.read_u16()?), INSTR_JIF => Self::Jif(reader.read_u16()?), INSTR_ROUTINE => Self::Routine(reader.read_u16()?), @@ -1043,8 +1043,8 @@ impl Bytecode for BytesOp { writer.write_bool(false)?; } BytesOp::Extr(src, dst, index, offset) | BytesOp::Inj(src, dst, index, offset) => { - writer.write_u5(src)?; - writer.write_u3(dst)?; + writer.write_u4(src)?; + writer.write_u4(dst)?; writer.write_u4(index)?; writer.write_u4(offset)?; } @@ -1126,14 +1126,14 @@ impl Bytecode for BytesOp { op } INSTR_EXTR => Self::Extr( - reader.read_u5()?.into(), - reader.read_u3()?.into(), + reader.read_u4()?.into(), + reader.read_u4()?.into(), reader.read_u4()?.into(), reader.read_u4()?.into(), ), INSTR_INJ => Self::Inj( - reader.read_u5()?.into(), - reader.read_u3()?.into(), + reader.read_u4()?.into(), + reader.read_u4()?.into(), reader.read_u4()?.into(), reader.read_u4()?.into(), ), diff --git a/src/isa/exec.rs b/src/isa/exec.rs index 42b6f56..ffc05d2 100644 --- a/src/isa/exec.rs +++ b/src/isa/exec.rs @@ -232,9 +232,12 @@ impl InstructionSet for ControlFlowOp { regs.st0 = false; ExecStep::Stop } - ControlFlowOp::Succ => { - regs.st0 = true; - ExecStep::Stop + ControlFlowOp::Test => { + if regs.st0 { + ExecStep::Next + } else { + ExecStep::Stop + } } ControlFlowOp::Jmp(offset) => { regs.jmp().map(|_| ExecStep::Jump(*offset)).unwrap_or(ExecStep::Stop) @@ -1317,7 +1320,7 @@ impl InstructionSet for BytesOp { let offset = regs.a16[*offset as u8 as usize].filter(|e| *e < s_len)?; let end = offset .checked_add(dst.layout().bytes()) - .filter(|e| *e < s_len) + .filter(|e| *e <= s_len) .unwrap_or_else(|| { regs.st0 = false; s_len @@ -1775,7 +1778,9 @@ mod tests { assert_eq!(register.get_n(RegA::A16, Reg32::Reg1), MaybeNumber::none()); assert_eq!(register.get_n(RegA::A16, Reg32::Reg2), MaybeNumber::none()); assert!(!register.st0); - ControlFlowOp::Succ.exec(&mut register, lib_site, &()); + CmpOp::StInv.exec(&mut register, lib_site, &()); + assert!(register.st0); + ControlFlowOp::Test.exec(&mut register, lib_site, &()); let s1 = [0u8; u16::MAX as usize]; let s2 = [0u8; u16::MAX as usize]; @@ -1903,8 +1908,8 @@ mod tests { &(), ); assert!(!register.st0); - ControlFlowOp::Succ.exec(&mut register, lib_site, &()); - assert!(register.st0); + ControlFlowOp::Test.exec(&mut register, lib_site, &()); + assert!(!register.st0); CmpOp::EqR(NoneEqFlag::NonEqual, RegR::R512, Reg32::Reg0, Reg32::Reg2).exec( &mut register, lib_site, diff --git a/src/isa/instr.rs b/src/isa/instr.rs index fd49953..8979e26 100644 --- a/src/isa/instr.rs +++ b/src/isa/instr.rs @@ -115,10 +115,10 @@ pub enum ControlFlowOp { #[display("fail")] Fail, - /// Completes program execution writing `true` to `st0` (indicating program success). Does not - /// modify value of call stack registers. - #[display("succ")] - Succ, + /// Checks the value of `st0` register. If the value is `false`, stops execution of the + /// program. Otherwise, it is a no-operation. + #[display("test")] + Test, /// Unconditionally jumps to an offset. Increments `cy0`. #[display("jmp {0:#06X}")] @@ -421,35 +421,35 @@ pub enum CmpOp { /// `wrap` flag is provided). #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)] pub enum ArithmeticOp { - /// Adds values from two integer arithmetic registers and puts result into the first register. + /// Adds values from two integer arithmetic registers and puts result into the second register. #[display("add.{0} {1}{2},{1}{3}")] AddA(IntFlags, RegA, Reg32, Reg32), - /// Adds values from two float arithmetic registers and puts result into the first register. + /// Adds values from two float arithmetic registers and puts result into the second register. #[display("add.{0} {1}{2},{1}{3}")] AddF(RoundingFlag, RegF, Reg32, Reg32), - /// Subtracts values from two integer arithmetic registers and puts result into the first + /// Subtracts values from two integer arithmetic registers and puts result into the second /// register. #[display("sub.{0} {1}{2},{1}{3}")] SubA(IntFlags, RegA, Reg32, Reg32), - /// Subtracts values from two float arithmetic registers and puts result into the first + /// Subtracts values from two float arithmetic registers and puts result into the second /// register. #[display("sub.{0} {1}{2},{1}{3}")] SubF(RoundingFlag, RegF, Reg32, Reg32), - /// Multiplies values from two integer arithmetic registers and puts result into the first + /// Multiplies values from two integer arithmetic registers and puts result into the second /// register. #[display("mul.{0} {1}{2},{1}{3}")] MulA(IntFlags, RegA, Reg32, Reg32), - /// Multiplies values from two float arithmetic registers and puts result into the first + /// Multiplies values from two float arithmetic registers and puts result into the second /// register. #[display("mul.{0} {1}{2},{1}{3}")] MulF(RoundingFlag, RegF, Reg32, Reg32), - /// Divides values from two integer arithmetic registers and puts result into the first + /// Divides values from two integer arithmetic registers and puts result into the second /// register. /// /// Since the division operation may not result in overflow, the overflow flag is used to @@ -462,14 +462,15 @@ pub enum ArithmeticOp { #[display("div.{0} {1}{2},{1}{3}")] DivA(IntFlags, RegA, Reg32, Reg32), - /// Divides values from two float arithmetic registers and puts result into the first register. + /// Divides values from two float arithmetic registers and puts result into the second + /// register. #[display("div.{0} {1}{2},{1}{3}")] DivF(RoundingFlag, RegF, Reg32, Reg32), /// Modulo division. /// /// Puts a reminder of the division of source register on destination register into the - /// the first register. + /// second register. #[display("rem {0}{1},{2}{3}")] Rem(RegA, Reg32, RegA, Reg32), @@ -697,18 +698,18 @@ pub enum BytesOp { /// If the source string register - or offset register is uninitialized, sets destination to /// uninitialized state and `st0` to `false`. #[display("extr {0},{1}{2},a16{3}")] - Extr(/** `s` register index */ RegS, RegR, Reg16, /** `a16` register with offset */ Reg16), + Extr(/** `s` register index */ RegS, RegAR, Reg16, /** `a16` register with offset */ Reg16), /// Inject general `R` register value at a given position to string register, replacing value /// of the corresponding bytes. If the insert offset is larger than the current length of the /// string, the length is extended and all bytes inbetween previous length and the new length /// are initialized with zeros. If the length of the inserted string plus insert offset exceeds - /// the maximum string register length (2^16 bytes), than the destination register is set to + /// the maximum string register length (2^16 bytes), then the destination register is set to /// `None` state and `st0` is set to `false`. Otherwise, `st0` value is not modified. #[display("inj {0},{1}{2},{1}{3}")] Inj( /** `s` register index acting as the source and destination */ RegS, - RegR, + RegAR, Reg16, /** `a16` register with offset */ Reg16, ), @@ -753,7 +754,7 @@ pub enum BytesOp { /// Rule on `st0` changes: if at least one of the destination registers is set to `None`, or /// `offset` value exceeds source string length, `st0` is set to `false`; otherwise its value /// is not modified - #[display("splt.{2} {0},a16{1},{3},{4}")] + #[display("splt.{0} {2},a16{1},{3},{4}")] Splt( SplitFlag, /** `a16` register index with offset value */ Reg32, @@ -791,7 +792,7 @@ pub enum BytesOp { /// /// /// In all of these cases `st0` is set to `false`. Otherwise, `st0` value is not modified. - #[display("ins.{3} {0},{1},a16{2}")] + #[display("ins.{0} {1},a16{2},{2}")] Ins( InsertFlag, /** `a16` register index with offset value for insert location */ Reg32, diff --git a/src/isa/macros.rs b/src/isa/macros.rs index d157a73..810508f 100644 --- a/src/isa/macros.rs +++ b/src/isa/macros.rs @@ -71,7 +71,7 @@ macro_rules! aluasm_isa { MergeFlag, MoveOp, PutOp, RoundingFlag, Secp256k1Op, SignFlag, NoneEqFlag }; use ::aluvm::reg::{ - Reg16, Reg32, Reg8, RegA, RegA2, RegBlockAFR, RegBlockAR, RegF, RegR, RegS, + Reg16, Reg32, Reg8, RegA, RegA2, RegAR, RegBlockAFR, RegBlockAR, RegF, RegR, RegS, NumericRegister, }; use ::aluvm::library::LibSite; @@ -93,7 +93,11 @@ macro_rules! aluasm_inner { $code.push($crate::instr!{ $op }); $crate::aluasm_inner! { $code => $( $tt )* } }; - { $code:ident => $op:ident $arg:literal @ $lib:ident ; $($tt:tt)* } => { + { $code:ident => $op:ident $arg:literal @ $lib:literal ; $($tt:tt)* } => { + $code.push($crate::instr!{ $op $arg @ $lib }); + $crate::aluasm_inner! { $code => $( $tt )* } + }; + { $code:ident => $op:ident $arg:ident @ $lib:ident ; $($tt:tt)* } => { $code.push($crate::instr!{ $op $arg @ $lib }); $crate::aluasm_inner! { $code => $( $tt )* } }; @@ -121,6 +125,10 @@ macro_rules! aluasm_inner { $code.push($crate::instr!{ $op $arglit, $( $arg [ $idx ] ),+ }); $crate::aluasm_inner! { $code => $( $tt )* } }; + { $code:ident => $op:ident $arglit:ident, $( $arg:ident [ $idx:literal ] ),+ ; $($tt:tt)* } => { + $code.push($crate::instr!{ $op $arglit, $( $arg [ $idx ] ),+ }); + $crate::aluasm_inner! { $code => $( $tt )* } + }; { $code:ident => $op:ident . $flag:ident $arglit:literal, $( $arg:ident [ $idx:literal ] ),+ ; $($tt:tt)* } => { $code.push($crate::instr!{ $op . $flag $arglit, $( $arg [ $idx ] ),+ }); $crate::aluasm_inner! { $code => $( $tt )* } @@ -137,6 +145,10 @@ macro_rules! aluasm_inner { $code.push($crate::instr!{ $op $arg [ $idx ] , $arglit }); $crate::aluasm_inner! { $code => $( $tt )* } }; + { $code:ident => $op:ident $arg:ident [ $idx:literal ] , $arglit:ident ; $($tt:tt)* } => { + $code.push($crate::instr!{ $op $arg [ $idx ] , $arglit }); + $crate::aluasm_inner! { $code => $( $tt )* } + }; { $code:ident => $op:ident . $flag:ident $arg:ident [ $idx:literal ], $arglit:expr ; $($tt:tt)* } => { $code.push($crate::instr!{ $op . $flag $arg [ $idx ], $arglit }); $crate::aluasm_inner! { $code => $( $tt )* } @@ -149,28 +161,49 @@ macro_rules! instr { (fail) => { Instr::ControlFlow(ControlFlowOp::Fail) }; - (succ) => { - Instr::ControlFlow(ControlFlowOp::Succ) + (test) => { + Instr::ControlFlow(ControlFlowOp::Test) }; (jmp $offset:literal) => { Instr::ControlFlow(ControlFlowOp::Jmp($offset)) }; + (jmp $offset:ident) => { + Instr::ControlFlow(ControlFlowOp::Jmp($offset)) + }; (jif $offset:literal) => { Instr::ControlFlow(ControlFlowOp::Jif($offset)) }; + (jif $offset:ident) => { + Instr::ControlFlow(ControlFlowOp::Jif($offset)) + }; (routine $offset:literal) => { Instr::ControlFlow(ControlFlowOp::Reutine($offset)) }; - (call $offset:literal @ $lib:ident) => { + (routine $offset:ident) => { + Instr::ControlFlow(ControlFlowOp::Reutine($offset)) + }; + (call $offset:literal @ $lib:literal) => { Instr::ControlFlow(ControlFlowOp::Call(LibSite::with( $offset, - stringify!($lib).parse().expect("wrong library reference"), + $lib.parse().expect("wrong library reference"), ))) }; - (exec $offset:literal @ $lib:ident) => { + (call $offset:ident @ $lib:ident) => { + Instr::ControlFlow(ControlFlowOp::Call(LibSite::with( + $offset, + $lib + ))) + }; + (exec $offset:literal @ $lib:literal) => { Instr::ControlFlow(ControlFlowOp::Exec(LibSite::with( $offset, - stringify!($lib).parse().expect("wrong library reference"), + $lib.parse().expect("wrong library reference"), + ))) + }; + (exec $offset:ident @ $lib:ident) => { + Instr::ControlFlow(ControlFlowOp::Exec(LibSite::with( + $offset, + $lib ))) }; (ret) => { @@ -184,14 +217,25 @@ macro_rules! instr { )) }; - (extr s16[$idx:literal], $regr:ident[$regr_idx:literal],a16[$offset_idx:literal]) => { + (extr s16[$idx:literal], $reg:ident[$reg_idx:literal], a16[$offset_idx:literal]) => { Instr::Bytes(BytesOp::Extr( RegS::from($idx), - $crate::_reg_ty!(Reg, $regr), - $crate::_reg_idx16!($regr_idx), + $crate::_reg_tyar!($reg), + $crate::_reg_idx16!($reg_idx), + $crate::_reg_idx16!($offset_idx), + )) + }; + (inj s16[$idx:literal], $reg:ident[$reg_idx:literal], a16[$offset_idx:literal]) => { + Instr::Bytes(BytesOp::Inj( + RegS::from($idx), + $crate::_reg_tyar!($reg), + $crate::_reg_idx16!($reg_idx), $crate::_reg_idx16!($offset_idx), )) }; + (put s16[$idx:literal], $val:ident) => {{ + Instr::Bytes(BytesOp::Put(RegS::from($idx), Box::new(ByteStr::with(&$val)), false)) + }}; (put s16[$idx:literal], $val:literal) => {{ Instr::Bytes(BytesOp::Put(RegS::from($idx), Box::new(ByteStr::with(&$val)), false)) }}; @@ -252,6 +296,12 @@ macro_rules! instr { num.reshape(reg.layout()); Instr::Put($crate::_reg_sfx!(PutOp, Put, $reg)(reg, $crate::_reg_idx!($idx), Box::new(num))) }}; + (put $reg:ident[$idx:literal], $val:ident) => {{ + let mut num = MaybeNumber::from($val); + let reg = $crate::_reg_ty!(Reg, $reg); + num.reshape(reg.layout()); + Instr::Put($crate::_reg_sfx!(PutOp, Put, $reg)(reg, $crate::_reg_idx!($idx), Box::new(num))) + }}; (putif $reg:ident[$idx:literal], $val:literal) => {{ let s = stringify!($val); let mut num = s.parse::().expect(&format!("invalid number literal `{}`", s)); @@ -263,6 +313,16 @@ macro_rules! instr { Box::new(num), )) }}; + (putif $reg:ident[$idx:literal], $val:ident) => {{ + let mut num = MaybeNumber::from($val); + let reg = $crate::_reg_ty!(Reg, $reg); + num.reshape(reg.layout()); + Instr::Put($crate::_reg_sfx!(PutOp, PutIf, $reg)( + reg, + $crate::_reg_idx!($idx), + Box::new(num), + )) + }}; (swp $reg1:ident[$idx1:literal], $reg2:ident[$idx2:literal]) => {{ if $crate::_reg_ty!(Reg, $reg1) != $crate::_reg_ty!(Reg, $reg2) { @@ -1295,6 +1355,60 @@ macro_rules! _reg_tyr { }; } +#[doc(hidden)] +#[macro_export] +macro_rules! _reg_tyar { + (a8) => { + RegAR::A(RegA::A8) + }; + (a16) => { + RegAR::A(RegA::A16) + }; + (a32) => { + RegAR::A(RegA::A32) + }; + (a64) => { + RegAR::A(RegA::A64) + }; + (a128) => { + RegAR::A(RegA::A128) + }; + (a256) => { + RegAR::A(RegA::A256) + }; + (a512) => { + RegAR::A(RegA::A512) + }; + (a1024) => { + RegAR::A(RegA::A1024) + }; + + (r128) => { + RegAR::R(RegR::R128) + }; + (r160) => { + RegAR::R(RegR::R160) + }; + (r256) => { + RegAR::R(RegR::R256) + }; + (r512) => { + RegAR::R(RegR::R512) + }; + (r1024) => { + RegAR::R(RegR::R1024) + }; + (r2048) => { + RegAR::R(RegR::R2048) + }; + (r4096) => { + RegAR::R(RegR::R4096) + }; + (r8192) => { + RegAR::R(RegR::R8192) + }; +} + #[doc(hidden)] #[macro_export] macro_rules! _reg_idx { diff --git a/src/isa/opcodes.rs b/src/isa/opcodes.rs index 75385f8..46f1bf4 100644 --- a/src/isa/opcodes.rs +++ b/src/isa/opcodes.rs @@ -26,7 +26,7 @@ // Control-flow instructions pub const INSTR_FAIL: u8 = 0b00_000_000; -pub const INSTR_SUCC: u8 = 0b00_000_001; +pub const INSTR_TEST: u8 = 0b00_000_001; pub const INSTR_JMP: u8 = 0b00_000_010; pub const INSTR_JIF: u8 = 0b00_000_011; pub const INSTR_ROUTINE: u8 = 0b00_000_100; diff --git a/src/library/lib.rs b/src/library/lib.rs index 09e323b..d8bf84b 100644 --- a/src/library/lib.rs +++ b/src/library/lib.rs @@ -32,7 +32,7 @@ use core::str::FromStr; use amplify::confinement::SmallBlob; use amplify::{confinement, ByteArray, Bytes32}; -use baid58::{Baid58ParseError, FromBaid58, ToBaid58}; +use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32}; use sha2::{Digest, Sha256}; use strict_encoding::{StrictDeserialize, StrictSerialize}; @@ -67,7 +67,9 @@ pub struct LibId( impl ToBaid58<32> for LibId { const HRI: &'static str = "alu"; + const CHUNKING: Option = CHUNKING_32; fn to_baid58_payload(&self) -> [u8; 32] { self.to_byte_array() } + fn to_baid58_string(&self) -> String { self.to_string() } } impl FromBaid58<32> for LibId {} @@ -79,10 +81,13 @@ impl FromStr for LibId { } impl Display for LibId { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if f.alternate() { + f.write_str("urn:ubideco:alu:")?; + } if f.sign_minus() { - write!(f, "urn:ubideco:{::<}", self.to_baid58()) + write!(f, "{:.2}", self.to_baid58()) } else { - write!(f, "urn:ubideco:{::<#}", self.to_baid58()) + write!(f, "{:#.2}", self.to_baid58()) } } } @@ -484,11 +489,13 @@ mod test { let id = LibId::with("FLOAT", b"", b"", &none!()); assert_eq!( format!("{id}"), - "urn:ubideco:alu:GrjjwmeTsibiEeYYtjokmc8j4Jn1KWL2SX8NugG6T5kZ#pinball-eternal-colombo" + "Grjjwm-eTsibiEe-YYtjokmc-8j4Jn1KW-L2SX8Nug-G6T5kZ#pinball-eternal-colombo" ); + assert_eq!(format!("{id:-}"), "Grjjwm-eTsibiEe-YYtjokmc-8j4Jn1KW-L2SX8Nug-G6T5kZ"); assert_eq!( - format!("{id:-}"), - "urn:ubideco:alu:GrjjwmeTsibiEeYYtjokmc8j4Jn1KWL2SX8NugG6T5kZ" + format!("{id:#}"), + "urn:ubideco:alu:Grjjwm-eTsibiEe-YYtjokmc-8j4Jn1KW-L2SX8Nug-G6T5kZ#\ + pinball-eternal-colombo" ); }