Skip to main content

ab_contract_file/
instruction.rs

1use ab_riscv_interpreter::prelude::*;
2use ab_riscv_macros::{instruction, instruction_execution};
3use ab_riscv_primitives::prelude::*;
4use core::fmt;
5use core::ops::ControlFlow;
6
7/// Registers used by contracts
8#[derive(Debug, Default, Clone, Copy)]
9pub struct ContractRegisters {
10    regs: [u64; 32],
11}
12
13impl const RegisterFile<ContractRegister> for ContractRegisters {
14    #[inline(always)]
15    fn read(&self, reg: ContractRegister) -> u64 {
16        if reg == ContractRegister::Zero {
17            // Always zero
18            return 0;
19        }
20
21        // SAFETY: register offset is always within bounds
22        *unsafe { self.regs.get_unchecked(usize::from(reg as u8)) }
23    }
24
25    #[inline(always)]
26    fn write(&mut self, reg: ContractRegister, value: u64) {
27        // SAFETY: register offset is always within bounds
28        *unsafe { self.regs.get_unchecked_mut(usize::from(reg as u8)) } = value;
29    }
30}
31
32/// A register type used by contracts.
33///
34/// `gp` and `tp` registers are excluded because they are not present in contracts.
35#[derive(Clone, Copy)]
36#[repr(u8)]
37pub enum ContractRegister {
38    /// Always zero: `x0`
39    Zero = 0,
40    /// Return address: `x1`
41    Ra = 1,
42    /// Stack pointer: `x2`
43    Sp = 2,
44    // /// Global pointer: `x3`
45    // Gp = 3,
46    // /// Thread pointer: `x4`
47    // Tp = 4,
48    /// Temporary/alternate return address: `x5`
49    T0 = 5,
50    /// Temporary: `x6`
51    T1 = 6,
52    /// Temporary: `x7`
53    T2 = 7,
54    /// Saved register/frame pointer: `x8`
55    S0 = 8,
56    /// Saved register: `x9`
57    S1 = 9,
58    /// Function argument/return value: `x10`
59    A0 = 10,
60    /// Function argument/return value: `x11`
61    A1 = 11,
62    /// Function argument: `x12`
63    A2 = 12,
64    /// Function argument: `x13`
65    A3 = 13,
66    /// Function argument: `x14`
67    A4 = 14,
68    /// Function argument: `x15`
69    A5 = 15,
70    /// Function argument: `x16`
71    A6 = 16,
72    /// Function argument: `x17`
73    A7 = 17,
74    /// Saved register: `x18`
75    S2 = 18,
76    /// Saved register: `x19`
77    S3 = 19,
78    /// Saved register: `x20`
79    S4 = 20,
80    /// Saved register: `x21`
81    S5 = 21,
82    /// Saved register: `x22`
83    S6 = 22,
84    /// Saved register: `x23`
85    S7 = 23,
86    /// Saved register: `x24`
87    S8 = 24,
88    /// Saved register: `x25`
89    S9 = 25,
90    /// Saved register: `x26`
91    S10 = 26,
92    /// Saved register: `x27`
93    S11 = 27,
94    /// Temporary: `x28`
95    T3 = 28,
96    /// Temporary: `x29`
97    T4 = 29,
98    /// Temporary: `x30`
99    T5 = 30,
100    /// Temporary: `x31`
101    T6 = 31,
102}
103
104impl const Default for ContractRegister {
105    #[inline(always)]
106    fn default() -> Self {
107        Self::Zero
108    }
109}
110
111impl fmt::Display for ContractRegister {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        match self {
114            Self::Zero => write!(f, "zero"),
115            Self::Ra => write!(f, "ra"),
116            Self::Sp => write!(f, "sp"),
117            Self::T0 => write!(f, "t0"),
118            Self::T1 => write!(f, "t1"),
119            Self::T2 => write!(f, "t2"),
120            Self::S0 => write!(f, "s0"),
121            Self::S1 => write!(f, "s1"),
122            Self::A0 => write!(f, "a0"),
123            Self::A1 => write!(f, "a1"),
124            Self::A2 => write!(f, "a2"),
125            Self::A3 => write!(f, "a3"),
126            Self::A4 => write!(f, "a4"),
127            Self::A5 => write!(f, "a5"),
128            Self::A6 => write!(f, "a6"),
129            Self::A7 => write!(f, "a7"),
130            Self::S2 => write!(f, "s2"),
131            Self::S3 => write!(f, "s3"),
132            Self::S4 => write!(f, "s4"),
133            Self::S5 => write!(f, "s5"),
134            Self::S6 => write!(f, "s6"),
135            Self::S7 => write!(f, "s7"),
136            Self::S8 => write!(f, "s8"),
137            Self::S9 => write!(f, "s9"),
138            Self::S10 => write!(f, "s10"),
139            Self::S11 => write!(f, "s11"),
140            Self::T3 => write!(f, "t3"),
141            Self::T4 => write!(f, "t4"),
142            Self::T5 => write!(f, "t5"),
143            Self::T6 => write!(f, "t6"),
144        }
145    }
146}
147
148impl fmt::Debug for ContractRegister {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        fmt::Display::fmt(self, f)
151    }
152}
153
154impl const PartialEq for ContractRegister {
155    #[inline(always)]
156    fn eq(&self, other: &Self) -> bool {
157        // This is quite ugly, but the default `derive` isn't `const` there doesn't seem to be a
158        // much better way with `Phantom` variant
159        matches!(
160            (self, other),
161            (Self::Zero, Self::Zero)
162                | (Self::Ra, Self::Ra)
163                | (Self::Sp, Self::Sp)
164                | (Self::T0, Self::T0)
165                | (Self::T1, Self::T1)
166                | (Self::T2, Self::T2)
167                | (Self::S0, Self::S0)
168                | (Self::S1, Self::S1)
169                | (Self::A0, Self::A0)
170                | (Self::A1, Self::A1)
171                | (Self::A2, Self::A2)
172                | (Self::A3, Self::A3)
173                | (Self::A4, Self::A4)
174                | (Self::A5, Self::A5)
175                | (Self::A6, Self::A6)
176                | (Self::A7, Self::A7)
177                | (Self::S2, Self::S2)
178                | (Self::S3, Self::S3)
179                | (Self::S4, Self::S4)
180                | (Self::S5, Self::S5)
181                | (Self::S6, Self::S6)
182                | (Self::S7, Self::S7)
183                | (Self::S8, Self::S8)
184                | (Self::S9, Self::S9)
185                | (Self::S10, Self::S10)
186                | (Self::S11, Self::S11)
187                | (Self::T3, Self::T3)
188                | (Self::T4, Self::T4)
189                | (Self::T5, Self::T5)
190                | (Self::T6, Self::T6)
191        )
192    }
193}
194
195impl const Eq for ContractRegister {}
196
197impl const Register for ContractRegister {
198    const ZERO: Self = Self::Zero;
199    const SP: Self = Self::Sp;
200    const RA: Self = Self::Ra;
201    const A0: Self = Self::A0;
202    const A1: Self = Self::A1;
203    type Type = u64;
204
205    #[inline(always)]
206    fn from_bits(bits: u8) -> Option<Self> {
207        match bits {
208            0 => Some(Self::Zero),
209            1 => Some(Self::Ra),
210            2 => Some(Self::Sp),
211            5 => Some(Self::T0),
212            6 => Some(Self::T1),
213            7 => Some(Self::T2),
214            8 => Some(Self::S0),
215            9 => Some(Self::S1),
216            10 => Some(Self::A0),
217            11 => Some(Self::A1),
218            12 => Some(Self::A2),
219            13 => Some(Self::A3),
220            14 => Some(Self::A4),
221            15 => Some(Self::A5),
222            16 => Some(Self::A6),
223            17 => Some(Self::A7),
224            18 => Some(Self::S2),
225            19 => Some(Self::S3),
226            20 => Some(Self::S4),
227            21 => Some(Self::S5),
228            22 => Some(Self::S6),
229            23 => Some(Self::S7),
230            24 => Some(Self::S8),
231            25 => Some(Self::S9),
232            26 => Some(Self::S10),
233            27 => Some(Self::S11),
234            28 => Some(Self::T3),
235            29 => Some(Self::T4),
236            30 => Some(Self::T5),
237            31 => Some(Self::T6),
238            _ => None,
239        }
240    }
241}
242
243/// SAFETY: `Self::from_bits()` returns `Some()` for `1`, `8`, `9` and `18..=27`
244unsafe impl const ZcmpRegister for ContractRegister {
245    const RVE: bool = false;
246}
247
248/// An instruction type used by contracts
249#[instruction(
250    ignore = [Fence, FenceTso, Ecall],
251    inherit = [
252        Rv64ZcaInstruction,
253        Rv64ZcbInstruction,
254        Rv64ZcmpInstruction,
255        Rv64Instruction,
256        Rv64MInstruction,
257        Rv64BInstruction,
258        Rv64ZbcInstruction,
259        Rv64ZknInstruction,
260        ZicondInstruction,
261        Rv64ZknhInstruction,
262    ],
263)]
264#[derive(Debug, Clone, Copy, PartialEq, Eq)]
265pub enum ContractInstruction<Reg = ContractRegister> {}
266
267#[instruction]
268impl<Reg> const Instruction for ContractInstruction<Reg>
269where
270    Reg: [const] Register<Type = u64>,
271{
272    type Reg = Reg;
273
274    #[inline(always)]
275    fn try_decode(instruction: u32) -> Option<Self> {
276        None
277    }
278
279    #[inline(always)]
280    fn alignment() -> u8 {
281        align_of::<u32>() as u8
282    }
283
284    #[inline(always)]
285    fn size(&self) -> u8 {
286        size_of::<u32>() as u8
287    }
288}
289
290#[instruction]
291impl<Reg> fmt::Display for ContractInstruction<Reg>
292where
293    Reg: Register,
294{
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        match self {}
297    }
298}
299
300#[instruction_execution]
301impl<Reg> ExecutableInstructionOperands for ContractInstruction<Reg> {}
302
303#[instruction_execution]
304impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
305    for ContractInstruction<Reg>
306{
307}
308
309#[instruction_execution]
310impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
311    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
312    for ContractInstruction<Reg>
313where
314    Reg: Register,
315{
316    #[inline(always)]
317    fn execute(
318        self,
319        Rs1Rs2OperandValues {
320            rs1_value,
321            rs2_value,
322        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
323        regs: &mut Regs,
324        _ext_state: &mut ExtState,
325        memory: &mut Memory,
326        program_counter: &mut PC,
327        system_instruction_handler: &mut InstructionHandler,
328    ) -> Result<
329        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
330        ExecutionError<Reg::Type, CustomError>,
331    > {
332        Ok(ControlFlow::Continue(Default::default()))
333    }
334}
335
336impl<Reg> ContractInstruction<Reg> {
337    /// Check if the instruction is a jump instruction of any kind (affects program counter)
338    #[inline]
339    pub fn is_jump(&self) -> bool {
340        matches!(
341            self,
342            Self::CJ { .. }
343                | Self::CBeqz { .. }
344                | Self::CBnez { .. }
345                | Self::CJr { .. }
346                | Self::CJalr { .. }
347                | Self::CmPopretz { .. }
348                | Self::CmPopret { .. }
349                | Self::Jalr { .. }
350                | Self::Beq { .. }
351                | Self::Bne { .. }
352                | Self::Blt { .. }
353                | Self::Bge { .. }
354                | Self::Bltu { .. }
355                | Self::Bgeu { .. }
356                | Self::Jal { .. }
357        )
358    }
359}