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 = [Ecall],
251    inherit = [
252        Rv64ZcaInstruction,
253        Rv64ZcbInstruction,
254        Rv64ZcmpInstruction,
255        Rv64Instruction,
256        Rv64MInstruction,
257        Rv64BInstruction,
258        Rv64ZbcInstruction,
259        Rv64ZknInstruction,
260        ZicondInstruction,
261    ],
262)]
263#[derive(Debug, Clone, Copy, PartialEq, Eq)]
264pub enum ContractInstruction<Reg = ContractRegister> {}
265
266#[instruction]
267impl<Reg> const Instruction for ContractInstruction<Reg>
268where
269    Reg: [const] Register<Type = u64>,
270{
271    type Reg = Reg;
272
273    #[inline(always)]
274    fn try_decode(instruction: u32) -> Option<Self> {
275        None
276    }
277
278    #[inline(always)]
279    fn alignment() -> u8 {
280        align_of::<u32>() as u8
281    }
282
283    #[inline(always)]
284    fn size(&self) -> u8 {
285        size_of::<u32>() as u8
286    }
287}
288
289#[instruction]
290impl<Reg> fmt::Display for ContractInstruction<Reg>
291where
292    Reg: Register,
293{
294    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295        match self {}
296    }
297}
298
299#[instruction_execution]
300impl<Reg> ExecutableInstructionOperands for ContractInstruction<Reg> {}
301
302#[instruction_execution]
303impl<Reg, ExtState, CustomError> ExecutableInstructionCsr<ExtState, CustomError>
304    for ContractInstruction<Reg>
305{
306}
307
308#[instruction_execution]
309impl<Reg, Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
310    ExecutableInstruction<Regs, ExtState, Memory, PC, InstructionHandler, CustomError>
311    for ContractInstruction<Reg>
312where
313    Reg: Register,
314{
315    #[inline(always)]
316    fn execute(
317        self,
318        Rs1Rs2OperandValues {
319            rs1_value,
320            rs2_value,
321        }: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
322        regs: &mut Regs,
323        _ext_state: &mut ExtState,
324        memory: &mut Memory,
325        program_counter: &mut PC,
326        system_instruction_handler: &mut InstructionHandler,
327    ) -> Result<
328        ControlFlow<(), (Self::Reg, <Self::Reg as Register>::Type)>,
329        ExecutionError<Reg::Type, CustomError>,
330    > {
331        Ok(ControlFlow::Continue(Default::default()))
332    }
333}
334
335impl<Reg> ContractInstruction<Reg> {
336    /// Check if the instruction is a jump instruction of any kind (affects program counter)
337    #[inline]
338    pub fn is_jump(&self) -> bool {
339        matches!(
340            self,
341            Self::CJ { .. }
342                | Self::CBeqz { .. }
343                | Self::CBnez { .. }
344                | Self::CJr { .. }
345                | Self::CJalr { .. }
346                | Self::CmPopretz { .. }
347                | Self::CmPopret { .. }
348                | Self::Jalr { .. }
349                | Self::Beq { .. }
350                | Self::Bne { .. }
351                | Self::Blt { .. }
352                | Self::Bge { .. }
353                | Self::Bltu { .. }
354                | Self::Bgeu { .. }
355                | Self::Jal { .. }
356        )
357    }
358}