aluvm/isa/instr.rs
1// Reference rust implementation of AluVM (arithmetic logic unit virtual machine).
2// To find more on AluVM please check <https://aluvm.org>
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Designed in 2021-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
7// Written in 2021-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
8//
9// Copyright (C) 2021-2024 LNP/BP Standards Association, Switzerland.
10// Copyright (C) 2024-2025 Laboratories for Ubiquitous Deterministic Computing (UBIDECO),
11// Institute for Distributed and Cognitive Systems (InDCS), Switzerland.
12// Copyright (C) 2021-2025 Dr Maxim Orlovsky.
13// All rights under the above copyrights are reserved.
14//
15// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
16// in compliance with the License. You may obtain a copy of the License at
17//
18// http://www.apache.org/licenses/LICENSE-2.0
19//
20// Unless required by applicable law or agreed to in writing, software distributed under the License
21// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
22// or implied. See the License for the specific language governing permissions and limitations under
23// the License.
24
25use alloc::collections::BTreeSet;
26use core::fmt::{Debug, Display};
27
28use amplify::confinement::TinyOrdSet;
29
30use crate::core::{Core, Register, Site, SiteId};
31use crate::isa::Bytecode;
32use crate::{CoreExt, IsaId};
33
34/// Turing machine movement after instruction execution
35#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
36pub enum ExecStep<Site> {
37 /// Stop program execution.
38 Stop,
39
40 /// Set `CK` to `Fail`. The program execution will halt if `CH` is set.
41 Fail,
42
43 /// Move to the next instruction.
44 Next,
45
46 /// Jump to the offset from the origin.
47 Jump(u16),
48
49 /// Jump to another code fragment.
50 Call(Site),
51
52 /// Return to the next instruction after the original caller position.
53 Ret(Site),
54}
55
56/// A local goto position for the jump instructions.
57#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
58pub enum GotoTarget<'a> {
59 /// The instruction does not perform a local jump.
60 ///
61 /// NB: It still may call a code from an external library, use [`Instruction::remote_goto_pos`]
62 /// to check that.
63 None,
64
65 /// An absolute offset in the code segment of the library.
66 Absolute(&'a mut u16),
67
68 /// An offset relative to the current position.
69 Relative(&'a mut i8),
70}
71
72/// Trait for instructions
73pub trait Instruction<Id: SiteId>: Display + Debug + Bytecode<Id> + Clone + Eq {
74 /// The names of the ISA extension set these instructions cover.
75 const ISA_EXT: &'static [&'static str];
76
77 /// Extensions to the AluVM core unit provided by this instruction set.
78 type Core: CoreExt;
79 /// Context: external data which are accessible to the ISA.
80 type Context<'ctx>;
81
82 /// Convert the set of ISA extensions from [`Self::ISA_EXT`] into a set of [`IsaId`].
83 fn isa_ext() -> TinyOrdSet<IsaId> {
84 let iter = Self::ISA_EXT.iter().copied().map(IsaId::from);
85 TinyOrdSet::from_iter_checked(iter)
86 }
87
88 /// Whether the instruction can be used as a goto-target.
89 fn is_goto_target(&self) -> bool;
90
91 /// If an instruction is a jump operation inside the library, it should return its goto target
92 /// position number.
93 fn local_goto_pos(&mut self) -> GotoTarget;
94
95 /// If an instruction is a jump operation into an external library, it should return its remote
96 /// target.
97 fn remote_goto_pos(&mut self) -> Option<&mut Site<Id>>;
98
99 /// Lists all registers which are used by the instruction.
100 fn regs(&self) -> BTreeSet<<Self::Core as CoreExt>::Reg> {
101 let mut regs = self.src_regs();
102 regs.extend(self.dst_regs());
103 regs
104 }
105
106 /// List of registers which value is taken into account by the instruction.
107 fn src_regs(&self) -> BTreeSet<<Self::Core as CoreExt>::Reg>;
108
109 /// List of registers which value may be changed by the instruction.
110 fn dst_regs(&self) -> BTreeSet<<Self::Core as CoreExt>::Reg>;
111
112 /// The number of bytes in the source registers.
113 fn src_reg_bytes(&self) -> u16 {
114 self.src_regs()
115 .into_iter()
116 .map(<Self::Core as CoreExt>::Reg::bytes)
117 .sum()
118 }
119
120 /// The number of bytes in the destination registers.
121 fn dst_reg_bytes(&self) -> u16 {
122 self.dst_regs()
123 .into_iter()
124 .map(<Self::Core as CoreExt>::Reg::bytes)
125 .sum()
126 }
127
128 /// The size of the data coming as an instruction operand (i.e., except data coming from
129 /// registers or read from outside the instruction operands).
130 fn op_data_bytes(&self) -> u16;
131
132 /// The size of the data read by the instruction from outside the registers (except data coming
133 /// as a parameter).
134 fn ext_data_bytes(&self) -> u16;
135
136 /// Computes base (non-adjusted) complexity of the instruction.
137 ///
138 /// Called by the default [`Self::complexity`] implementation. See it for more details.
139 fn base_complexity(&self) -> u64 {
140 (self.op_data_bytes() as u64
141 + self.src_reg_bytes() as u64
142 + self.dst_reg_bytes() as u64
143 + self.ext_data_bytes() as u64 * 2)
144 * 8 // per bit
145 * 1000 // by default use large unit
146 }
147
148 /// Returns computational complexity of the instruction.
149 ///
150 /// Computational complexity is the number of "CPU ticks" required to process the instruction.
151 fn complexity(&self) -> u64 { self.base_complexity() }
152
153 /// Executes the given instruction taking all registers as input and output.
154 ///
155 /// # Arguments
156 ///
157 /// The method is provided with the current code position which may be used by the instruction
158 /// for constructing call stack.
159 ///
160 /// # Returns
161 ///
162 /// Returns whether further execution should be stopped.
163 fn exec(
164 &self,
165 site: Site<Id>,
166 core: &mut Core<Id, Self::Core>,
167 context: &Self::Context<'_>,
168 ) -> ExecStep<Site<Id>>;
169}