openvm_rv32im_transpiler/
rrs.rs

1use std::marker::PhantomData;
2
3use openvm_instructions::{instruction::Instruction, riscv::RV32_REGISTER_NUM_LIMBS, *};
4use openvm_stark_backend::p3_field::PrimeField32;
5use openvm_transpiler::util::{
6    from_b_type, from_i_type, from_i_type_shamt, from_j_type, from_load, from_r_type, from_s_type,
7    from_u_type, nop,
8};
9use rrs_lib::{
10    instruction_formats::{BType, IType, ITypeShamt, JType, RType, SType, UType},
11    InstructionProcessor,
12};
13
14use crate::{
15    BaseAluOpcode, BranchEqualOpcode, BranchLessThanOpcode, DivRemOpcode, LessThanOpcode,
16    MulHOpcode, MulOpcode, Rv32AuipcOpcode, Rv32JalLuiOpcode, Rv32JalrOpcode, Rv32LoadStoreOpcode,
17    ShiftOpcode,
18};
19
20/// A transpiler that converts the 32-bit encoded instructions into instructions.
21pub(crate) struct InstructionTranspiler<F>(pub PhantomData<F>);
22
23impl<F: PrimeField32> InstructionProcessor for InstructionTranspiler<F> {
24    type InstructionResult = Instruction<F>;
25
26    fn process_add(&mut self, dec_insn: RType) -> Self::InstructionResult {
27        from_r_type(
28            BaseAluOpcode::ADD.global_opcode().as_usize(),
29            1,
30            &dec_insn,
31            false,
32        )
33    }
34
35    fn process_addi(&mut self, dec_insn: IType) -> Self::InstructionResult {
36        from_i_type(BaseAluOpcode::ADD.global_opcode().as_usize(), &dec_insn)
37    }
38
39    fn process_sub(&mut self, dec_insn: RType) -> Self::InstructionResult {
40        from_r_type(
41            BaseAluOpcode::SUB.global_opcode().as_usize(),
42            1,
43            &dec_insn,
44            false,
45        )
46    }
47
48    fn process_xor(&mut self, dec_insn: RType) -> Self::InstructionResult {
49        from_r_type(
50            BaseAluOpcode::XOR.global_opcode().as_usize(),
51            1,
52            &dec_insn,
53            false,
54        )
55    }
56
57    fn process_xori(&mut self, dec_insn: IType) -> Self::InstructionResult {
58        from_i_type(BaseAluOpcode::XOR.global_opcode().as_usize(), &dec_insn)
59    }
60
61    fn process_or(&mut self, dec_insn: RType) -> Self::InstructionResult {
62        from_r_type(
63            BaseAluOpcode::OR.global_opcode().as_usize(),
64            1,
65            &dec_insn,
66            false,
67        )
68    }
69
70    fn process_ori(&mut self, dec_insn: IType) -> Self::InstructionResult {
71        from_i_type(BaseAluOpcode::OR.global_opcode().as_usize(), &dec_insn)
72    }
73
74    fn process_and(&mut self, dec_insn: RType) -> Self::InstructionResult {
75        from_r_type(
76            BaseAluOpcode::AND.global_opcode().as_usize(),
77            1,
78            &dec_insn,
79            false,
80        )
81    }
82
83    fn process_andi(&mut self, dec_insn: IType) -> Self::InstructionResult {
84        from_i_type(BaseAluOpcode::AND.global_opcode().as_usize(), &dec_insn)
85    }
86
87    fn process_sll(&mut self, dec_insn: RType) -> Self::InstructionResult {
88        from_r_type(
89            ShiftOpcode::SLL.global_opcode().as_usize(),
90            1,
91            &dec_insn,
92            false,
93        )
94    }
95
96    fn process_slli(&mut self, dec_insn: ITypeShamt) -> Self::InstructionResult {
97        from_i_type_shamt(ShiftOpcode::SLL.global_opcode().as_usize(), &dec_insn)
98    }
99
100    fn process_srl(&mut self, dec_insn: RType) -> Self::InstructionResult {
101        from_r_type(
102            ShiftOpcode::SRL.global_opcode().as_usize(),
103            1,
104            &dec_insn,
105            false,
106        )
107    }
108
109    fn process_srli(&mut self, dec_insn: ITypeShamt) -> Self::InstructionResult {
110        from_i_type_shamt(ShiftOpcode::SRL.global_opcode().as_usize(), &dec_insn)
111    }
112
113    fn process_sra(&mut self, dec_insn: RType) -> Self::InstructionResult {
114        from_r_type(
115            ShiftOpcode::SRA.global_opcode().as_usize(),
116            1,
117            &dec_insn,
118            false,
119        )
120    }
121
122    fn process_srai(&mut self, dec_insn: ITypeShamt) -> Self::InstructionResult {
123        from_i_type_shamt(ShiftOpcode::SRA.global_opcode().as_usize(), &dec_insn)
124    }
125
126    fn process_slt(&mut self, dec_insn: RType) -> Self::InstructionResult {
127        from_r_type(
128            LessThanOpcode::SLT.global_opcode().as_usize(),
129            1,
130            &dec_insn,
131            false,
132        )
133    }
134
135    fn process_slti(&mut self, dec_insn: IType) -> Self::InstructionResult {
136        from_i_type(LessThanOpcode::SLT.global_opcode().as_usize(), &dec_insn)
137    }
138
139    fn process_sltu(&mut self, dec_insn: RType) -> Self::InstructionResult {
140        from_r_type(
141            LessThanOpcode::SLTU.global_opcode().as_usize(),
142            1,
143            &dec_insn,
144            false,
145        )
146    }
147
148    fn process_sltui(&mut self, dec_insn: IType) -> Self::InstructionResult {
149        from_i_type(LessThanOpcode::SLTU.global_opcode().as_usize(), &dec_insn)
150    }
151
152    fn process_lb(&mut self, dec_insn: IType) -> Self::InstructionResult {
153        from_load(
154            Rv32LoadStoreOpcode::LOADB.global_opcode().as_usize(),
155            &dec_insn,
156        )
157    }
158
159    fn process_lh(&mut self, dec_insn: IType) -> Self::InstructionResult {
160        from_load(
161            Rv32LoadStoreOpcode::LOADH.global_opcode().as_usize(),
162            &dec_insn,
163        )
164    }
165
166    fn process_lw(&mut self, dec_insn: IType) -> Self::InstructionResult {
167        from_load(
168            Rv32LoadStoreOpcode::LOADW.global_opcode().as_usize(),
169            &dec_insn,
170        )
171    }
172
173    fn process_lbu(&mut self, dec_insn: IType) -> Self::InstructionResult {
174        from_load(
175            Rv32LoadStoreOpcode::LOADBU.global_opcode().as_usize(),
176            &dec_insn,
177        )
178    }
179
180    fn process_lhu(&mut self, dec_insn: IType) -> Self::InstructionResult {
181        from_load(
182            Rv32LoadStoreOpcode::LOADHU.global_opcode().as_usize(),
183            &dec_insn,
184        )
185    }
186
187    fn process_sb(&mut self, dec_insn: SType) -> Self::InstructionResult {
188        from_s_type(
189            Rv32LoadStoreOpcode::STOREB.global_opcode().as_usize(),
190            &dec_insn,
191        )
192    }
193
194    fn process_sh(&mut self, dec_insn: SType) -> Self::InstructionResult {
195        from_s_type(
196            Rv32LoadStoreOpcode::STOREH.global_opcode().as_usize(),
197            &dec_insn,
198        )
199    }
200
201    fn process_sw(&mut self, dec_insn: SType) -> Self::InstructionResult {
202        from_s_type(
203            Rv32LoadStoreOpcode::STOREW.global_opcode().as_usize(),
204            &dec_insn,
205        )
206    }
207
208    fn process_beq(&mut self, dec_insn: BType) -> Self::InstructionResult {
209        from_b_type(BranchEqualOpcode::BEQ.global_opcode().as_usize(), &dec_insn)
210    }
211
212    fn process_bne(&mut self, dec_insn: BType) -> Self::InstructionResult {
213        from_b_type(BranchEqualOpcode::BNE.global_opcode().as_usize(), &dec_insn)
214    }
215
216    fn process_blt(&mut self, dec_insn: BType) -> Self::InstructionResult {
217        from_b_type(
218            BranchLessThanOpcode::BLT.global_opcode().as_usize(),
219            &dec_insn,
220        )
221    }
222
223    fn process_bge(&mut self, dec_insn: BType) -> Self::InstructionResult {
224        from_b_type(
225            BranchLessThanOpcode::BGE.global_opcode().as_usize(),
226            &dec_insn,
227        )
228    }
229
230    fn process_bltu(&mut self, dec_insn: BType) -> Self::InstructionResult {
231        from_b_type(
232            BranchLessThanOpcode::BLTU.global_opcode().as_usize(),
233            &dec_insn,
234        )
235    }
236
237    fn process_bgeu(&mut self, dec_insn: BType) -> Self::InstructionResult {
238        from_b_type(
239            BranchLessThanOpcode::BGEU.global_opcode().as_usize(),
240            &dec_insn,
241        )
242    }
243
244    fn process_jal(&mut self, dec_insn: JType) -> Self::InstructionResult {
245        from_j_type(Rv32JalLuiOpcode::JAL.global_opcode().as_usize(), &dec_insn)
246    }
247
248    fn process_jalr(&mut self, dec_insn: IType) -> Self::InstructionResult {
249        Instruction::new(
250            Rv32JalrOpcode::JALR.global_opcode(),
251            F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rd),
252            F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs1),
253            F::from_canonical_u32((dec_insn.imm as u32) & 0xffff),
254            F::ONE,
255            F::ZERO,
256            F::from_bool(dec_insn.rd != 0),
257            F::from_bool(dec_insn.imm < 0),
258        )
259    }
260
261    fn process_lui(&mut self, dec_insn: UType) -> Self::InstructionResult {
262        if dec_insn.rd == 0 {
263            return nop();
264        }
265        // we need to set f to 1 because this is handled by the same chip as jal
266        let mut result = from_u_type(Rv32JalLuiOpcode::LUI.global_opcode().as_usize(), &dec_insn);
267        result.f = F::ONE;
268        result
269    }
270
271    fn process_auipc(&mut self, dec_insn: UType) -> Self::InstructionResult {
272        if dec_insn.rd == 0 {
273            return nop();
274        }
275        Instruction::new(
276            Rv32AuipcOpcode::AUIPC.global_opcode(),
277            F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rd),
278            F::ZERO,
279            F::from_canonical_u32(((dec_insn.imm as u32) & 0xfffff000) >> 8),
280            F::ONE, // rd is a register
281            F::ZERO,
282            F::ZERO,
283            F::ZERO,
284        )
285    }
286
287    fn process_mul(&mut self, dec_insn: RType) -> Self::InstructionResult {
288        from_r_type(
289            MulOpcode::MUL.global_opcode().as_usize(),
290            0,
291            &dec_insn,
292            false,
293        )
294    }
295
296    fn process_mulh(&mut self, dec_insn: RType) -> Self::InstructionResult {
297        from_r_type(
298            MulHOpcode::MULH.global_opcode().as_usize(),
299            0,
300            &dec_insn,
301            false,
302        )
303    }
304
305    fn process_mulhu(&mut self, dec_insn: RType) -> Self::InstructionResult {
306        from_r_type(
307            MulHOpcode::MULHU.global_opcode().as_usize(),
308            0,
309            &dec_insn,
310            false,
311        )
312    }
313
314    fn process_mulhsu(&mut self, dec_insn: RType) -> Self::InstructionResult {
315        from_r_type(
316            MulHOpcode::MULHSU.global_opcode().as_usize(),
317            0,
318            &dec_insn,
319            false,
320        )
321    }
322
323    fn process_div(&mut self, dec_insn: RType) -> Self::InstructionResult {
324        from_r_type(
325            DivRemOpcode::DIV.global_opcode().as_usize(),
326            0,
327            &dec_insn,
328            false,
329        )
330    }
331
332    fn process_divu(&mut self, dec_insn: RType) -> Self::InstructionResult {
333        from_r_type(
334            DivRemOpcode::DIVU.global_opcode().as_usize(),
335            0,
336            &dec_insn,
337            false,
338        )
339    }
340
341    fn process_rem(&mut self, dec_insn: RType) -> Self::InstructionResult {
342        from_r_type(
343            DivRemOpcode::REM.global_opcode().as_usize(),
344            0,
345            &dec_insn,
346            false,
347        )
348    }
349
350    fn process_remu(&mut self, dec_insn: RType) -> Self::InstructionResult {
351        from_r_type(
352            DivRemOpcode::REMU.global_opcode().as_usize(),
353            0,
354            &dec_insn,
355            false,
356        )
357    }
358
359    fn process_fence(&mut self, dec_insn: IType) -> Self::InstructionResult {
360        tracing::debug!("Transpiling fence ({:?}) to nop", dec_insn);
361        nop()
362    }
363}