Skip to content

Commit

Permalink
fix: rgb isa instrs
Browse files Browse the repository at this point in the history
  • Loading branch information
crisdut committed Jan 15, 2024
1 parent 2b59903 commit 0d3e910
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 44 deletions.
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,6 @@ wasm-bindgen-test = "0.3"

[package.metadata.docs.rs]
features = [ "all" ]

[patch.crates-io]
aluvm = { git = "https://github.com/crisdut/rust-aluvm", branch = "fix/cnv" }
21 changes: 19 additions & 2 deletions src/vm/macroasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#[macro_export]
macro_rules! rgbasm {
($( $tt:tt )+) => {{ #[allow(unused_imports)] {
use $crate::AssignmentType;
use $crate::vm::{RgbIsa, ContractOp, TimechainOp};
use $crate::vm::aluasm_isa;
use $crate::isa_instr;
Expand All @@ -34,8 +35,24 @@ macro_rules! rgbasm {
macro_rules! isa_instr {
(pcvs $no:literal) => {{ RgbIsa::Contract(ContractOp::PcVs($no.into())) }};
(pccs $no1:literal, $no2:literal) => {{ RgbIsa::Contract(ContractOp::PcCs($no1.into(), $no2.into())) }};
(ldg $t:literal, $no:literal,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdG($t.into(), $no, RegS::from($s_idx))) }};
(lds $t:literal, $no:literal,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdS($t.into(), $no, RegS::from($s_idx))) }};
(cng $t:literal,a8[$a_idx:literal]) => {{ RgbIsa::Contract(ContractOp::CnG($t.into(), Reg32::from(RegS::from($a_idx)))) }};
(cnc $t:literal,a16[$a_idx:literal]) => {{ RgbIsa::Contract(ContractOp::CnC($t.into(), Reg32::from(RegS::from($a_idx)))) }};
(ldg $t:literal, $no:literal,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdGV($t.into(), $no, RegS::from($s_idx))) }};
(lds $t:literal, $no:literal,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdSV($t.into(), $no, RegS::from($s_idx))) }};
(ldp $t:literal, $no:literal,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdP($t.into(), $no, RegS::from($s_idx))) }};
(ldg $t:literal,a8[$a_idx:literal],s16[$s_idx:literal]) => {{
RgbIsa::Contract(ContractOp::LdG(
GlobalStateType::from($t as u16),
Reg32::from(RegS::from($a_idx)),
RegS::from($s_idx),
))
}};
(lds $t:literal,a16[$a_idx:literal],s16[$s_idx:literal]) => {{
RgbIsa::Contract(ContractOp::LdS(
AssignmentType::from($t as u16),
Reg32::from(RegS::from($a_idx)),
RegS::from($s_idx),
))
}};
($op:ident $($tt:tt)+) => {{ compile_error!(concat!("unknown RGB assembly opcode `", stringify!($op), "`")) }};
}
169 changes: 129 additions & 40 deletions src/vm/op_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use std::ops::RangeInclusive;
use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet};
use aluvm::library::{CodeEofError, LibSite, Read, Write};
use aluvm::reg::{CoreRegs, Reg, Reg32, RegA, RegS};
use amplify::num::{u3, u4};
use amplify::num::{u3, u4, u7};
use amplify::Wrapper;
use commit_verify::CommitVerify;

Expand Down Expand Up @@ -61,6 +61,25 @@ pub enum ContractOp {
#[display("cnc {0},a16{1}")]
CnC(AssignmentType, Reg32),

/// Loads global state from the current operation with type id from the
/// first argument and dynamic index from the second argument into a
/// register provided in the third argument.
///
/// If the state is absent sets `st0` to `false` and terminates the program.
#[display("ldg {0},{1},{2}")]
LdG(GlobalStateType, Reg32, RegS),

/// Loads owned structured state with type id from the first argument and
/// dynamic index from the second argument into a register provided in
/// the third argument.
///
/// If the state is absent or is not a structured state sets `st0` to
/// `false` and terminates the program.
///
/// If the state at the index is concealed, sets destination to `None`.
#[display("lds {0},{1},{2}")]
LdS(AssignmentType, Reg32, RegS),

/// Loads input (previous) state with type id from the first argument and
/// index from the second argument into a register provided in the third
/// argument.
Expand All @@ -81,7 +100,7 @@ pub enum ContractOp {
///
/// If the state at the index is concealed, sets destination to `None`.
#[display("lds {0},{1},{2}")]
LdS(AssignmentType, u16, RegS),
LdSV(AssignmentType, u16, RegS),

/// Loads owned fungible state with type id from the first argument and
/// index from the second argument into `a64` register provided in the third
Expand All @@ -100,7 +119,7 @@ pub enum ContractOp {
///
/// If the state is absent sets `st0` to `false` and terminates the program.
#[display("ldg {0},{1},{2}")]
LdG(GlobalStateType, u8, RegS),
LdGV(GlobalStateType, u8, RegS),

/// Loads part of the contract global state with type id from the first
/// argument at the depth from the second argument into a register
Expand Down Expand Up @@ -161,18 +180,21 @@ impl InstructionSet for ContractOp {

fn dst_regs(&self) -> HashSet<Reg> {
match self {
ContractOp::CnP(_, reg) |
ContractOp::CnS(_, reg) |
ContractOp::CnG(_, reg) |
ContractOp::CnC(_, reg) => {
ContractOp::CnP(_, reg) | ContractOp::CnS(_, reg) | ContractOp::CnC(_, reg) => {
set![Reg::A(RegA::A16, *reg)]
}
ContractOp::CnG(_, reg) => {
set![Reg::A(RegA::A8, *reg)]
}
ContractOp::LdF(_, _, reg) => {
set![Reg::A(RegA::A64, *reg)]
}
ContractOp::LdP(_, _, reg) |
ContractOp::LdS(_, _, reg) |

ContractOp::LdG(_, _, reg) |
ContractOp::LdS(_, _, reg) |
ContractOp::LdGV(_, _, reg) |
ContractOp::LdP(_, _, reg) |
ContractOp::LdSV(_, _, reg) |
ContractOp::LdC(_, _, reg) |
ContractOp::LdM(reg) => {
set![Reg::S(*reg)]
Expand All @@ -199,8 +221,8 @@ impl InstructionSet for ContractOp {
return ExecStep::Next;
}
let Some(prev_state) = context.prev_state.get($state_type) else {
fail!()
};
fail!()
};
match prev_state {
TypedAssigns::Fungible(state) => state
.iter()
Expand All @@ -217,8 +239,8 @@ impl InstructionSet for ContractOp {
return ExecStep::Next;
}
let Some(new_state) = context.owned_state.get(*$state_type) else {
fail!()
};
fail!()
};
match new_state {
TypedAssigns::Fungible(state) => state
.iter()
Expand Down Expand Up @@ -246,11 +268,14 @@ impl InstructionSet for ContractOp {
);
}
ContractOp::CnG(state_type, reg) => {
regs.set_n(RegA::A16, *reg, context.global.get(state_type).map(|a| a.len_u16()));
regs.set_n(RegA::A8, *reg, context.global.get(state_type).map(|a| a.len_u16()));
}
ContractOp::CnC(_state_type, _reg) => {
// TODO: implement global contract state
fail!()
ContractOp::CnC(state_type, reg) => {
regs.set_n(
RegA::A16,
*reg,
context.owned_state.get(*state_type).map(|a| a.len_u16()),
);
}
ContractOp::LdP(state_type, index, reg) => {
let Some(Ok(state)) = context
Expand All @@ -263,28 +288,31 @@ impl InstructionSet for ContractOp {
let state = state.map(|s| s.value.as_inner());
regs.set_s(*reg, state);
}
ContractOp::LdS(state_type, index, reg) => {

ContractOp::LdF(state_type, index, reg) => {
let Some(Ok(state)) = context
.owned_state
.get(*state_type)
.map(|a| a.into_structured_state_at(*index))
.map(|a| a.into_fungible_state_at(*index))
else {
fail!()
};
let state = state.map(|s| s.value.into_inner());
regs.set_s(*reg, state);
regs.set_n(RegA::A64, *reg, state.map(|s| s.value.as_u64()));
}
ContractOp::LdF(state_type, index, reg) => {
let Some(Ok(state)) = context
.owned_state
.get(*state_type)
.map(|a| a.into_fungible_state_at(*index))
ContractOp::LdG(state_type, reg_32, reg_s) => {
let reg_32 = regs.get_n(RegA::A8, *reg_32);
let index: u8 = reg_32.unwrap_or_default().into();

let Some(state) = context
.global
.get(state_type)
.and_then(|a| a.get(index as usize))
else {
fail!()
};
regs.set_n(RegA::A64, *reg, state.map(|s| s.value.as_u64()));
regs.set_s(*reg_s, Some(state.value.as_inner()));
}
ContractOp::LdG(state_type, index, reg) => {
ContractOp::LdGV(state_type, index, reg) => {
let Some(state) = context
.global
.get(state_type)
Expand All @@ -294,6 +322,32 @@ impl InstructionSet for ContractOp {
};
regs.set_s(*reg, Some(state.value.as_inner()));
}
ContractOp::LdS(state_type, reg_32, reg) => {
let reg_32 = regs.get_n(RegA::A16, *reg_32);
let index: u16 = reg_32.unwrap_or_default().into();

let Some(Ok(state)) = context
.owned_state
.get(*state_type)
.map(|a| a.into_structured_state_at(index))
else {
fail!()
};
let state = state.map(|s| s.value.into_inner());
regs.set_s(*reg, state);
}
ContractOp::LdSV(state_type, index, reg) => {
let Some(Ok(state)) = context
.owned_state
.get(*state_type)
.map(|a| a.into_structured_state_at(*index))
else {
fail!()
};
let state = state.map(|s| s.value.into_inner());
regs.set_s(*reg, state);
}

ContractOp::LdC(_state_type, _index, _reg) => {
// TODO: implement global contract state
fail!()
Expand Down Expand Up @@ -360,11 +414,12 @@ impl Bytecode for ContractOp {
ContractOp::CnG(_, _) |
ContractOp::CnC(_, _) => 4,

ContractOp::LdP(_, _, _) |
ContractOp::LdS(_, _, _) |
ContractOp::LdSV(_, _, _) |
ContractOp::LdP(_, _, _) |
ContractOp::LdF(_, _, _) |
ContractOp::LdC(_, _, _) => 6,
ContractOp::LdG(_, _, _) => 5,
ContractOp::LdG(_, _, _) | ContractOp::LdGV(_, _, _) => 5,
ContractOp::LdM(_) => 2,

ContractOp::PcVs(_) => 3,
Expand All @@ -383,10 +438,12 @@ impl Bytecode for ContractOp {
ContractOp::CnG(_, _) => INSTR_CNG,
ContractOp::CnC(_, _) => INSTR_CNC,

ContractOp::LdG(_, _, _) => INSTR_DLDG,
ContractOp::LdS(_, _, _) => INSTR_DLDS,
ContractOp::LdP(_, _, _) => INSTR_LDP,
ContractOp::LdS(_, _, _) => INSTR_LDS,
ContractOp::LdSV(_, _, _) => INSTR_LDS,
ContractOp::LdF(_, _, _) => INSTR_LDF,
ContractOp::LdG(_, _, _) => INSTR_LDG,
ContractOp::LdGV(_, _, _) => INSTR_LDG,
ContractOp::LdC(_, _, _) => INSTR_LDC,
ContractOp::LdM(_) => INSTR_LDM,

Expand Down Expand Up @@ -426,7 +483,14 @@ impl Bytecode for ContractOp {
writer.write_u4(reg)?;
writer.write_u4(u4::ZERO)?;
}
ContractOp::LdS(state_type, index, reg) => {
ContractOp::LdS(state_type, reg_32, reg_s) => {
writer.write_u16(*state_type)?;
writer.write_u5(reg_32)?;
writer.write_u8(reg_s)?;
writer.write_u4(u4::ZERO)?;
writer.write_u7(u7::ZERO)?;
}
ContractOp::LdSV(state_type, index, reg) => {
writer.write_u16(*state_type)?;
writer.write_u16(*index)?;
writer.write_u4(reg)?;
Expand All @@ -438,7 +502,13 @@ impl Bytecode for ContractOp {
writer.write_u5(reg)?;
writer.write_u3(u3::ZERO)?;
}
ContractOp::LdG(state_type, index, reg) => {
ContractOp::LdG(state_type, reg_a, reg_s) => {
writer.write_u16(*state_type)?;
writer.write_u5(*reg_a)?;
writer.write_u8(*reg_s)?;
writer.write_u3(u3::ZERO)?;
}
ContractOp::LdGV(state_type, index, reg) => {
writer.write_u16(*state_type)?;
writer.write_u8(*index)?;
writer.write_u4(reg)?;
Expand Down Expand Up @@ -474,22 +544,22 @@ impl Bytecode for ContractOp {
Ok(match reader.read_u8()? {
INSTR_CNP => {
let i = Self::CnP(reader.read_u16()?.into(), reader.read_u5()?.into());
reader.read_u4()?; // Discard garbage bits
reader.read_u3()?; // Discard garbage bits
i
}
INSTR_CNS => {
let i = Self::CnS(reader.read_u16()?.into(), reader.read_u5()?.into());
reader.read_u4()?; // Discard garbage bits
reader.read_u3()?; // Discard garbage bits
i
}
INSTR_CNG => {
let i = Self::CnG(reader.read_u16()?.into(), reader.read_u5()?.into());
reader.read_u4()?; // Discard garbage bits
reader.read_u3()?; // Discard garbage bits
i
}
INSTR_CNC => {
let i = Self::CnC(reader.read_u16()?.into(), reader.read_u5()?.into());
reader.read_u4()?; // Discard garbage bits
reader.read_u3()?; // Discard garbage bits
i
}

Expand All @@ -503,7 +573,7 @@ impl Bytecode for ContractOp {
i
}
INSTR_LDS => {
let i = Self::LdS(
let i = Self::LdSV(
reader.read_u16()?.into(),
reader.read_u16()?,
reader.read_u4()?.into(),
Expand All @@ -521,14 +591,33 @@ impl Bytecode for ContractOp {
i
}
INSTR_LDG => {
let i = Self::LdG(
let i = Self::LdGV(
reader.read_u16()?.into(),
reader.read_u8()?,
reader.read_u4()?.into(),
);
reader.read_u4()?; // Discard garbage bits
i
}
INSTR_DLDG => {
let i = Self::LdG(
reader.read_u16()?.into(),
reader.read_u5()?.into(),
reader.read_u8()?.into(),
);
reader.read_u3()?; // Discard garbage bits
i
}
INSTR_DLDS => {
let i = Self::LdS(
reader.read_u16()?.into(),
reader.read_u5()?.into(),
reader.read_u8()?.into(),
);
reader.read_u4()?; // Discard garbage bits
reader.read_u7()?;
i
}
INSTR_LDC => {
let i = Self::LdC(
reader.read_u16()?.into(),
Expand Down
2 changes: 2 additions & 0 deletions src/vm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub const INSTR_LDF: u8 = 0b11_000_110;
pub const INSTR_LDG: u8 = 0b11_001_000;
pub const INSTR_LDC: u8 = 0b11_001_001;
pub const INSTR_LDM: u8 = 0b11_001_010;
pub const INSTR_DLDG: u8 = 0b11_001_011;
pub const INSTR_DLDS: u8 = 0b11_001_100;
// Reserved 0b11_001_111

pub const INSTR_PCVS: u8 = 0b11_010_000;
Expand Down

0 comments on commit 0d3e910

Please sign in to comment.