openvm_rv32im_transpiler/
lib.rs1use std::marker::PhantomData;
2
3use openvm_instructions::{
4 instruction::Instruction, riscv::RV32_REGISTER_NUM_LIMBS, LocalOpcode, PhantomDiscriminant,
5 SystemOpcode,
6};
7use openvm_rv32im_guest::{
8 PhantomImm, CSRRW_FUNCT3, CSR_OPCODE, HINT_BUFFER_IMM, HINT_FUNCT3, HINT_STOREW_IMM,
9 NATIVE_STOREW_FUNCT3, NATIVE_STOREW_FUNCT7, PHANTOM_FUNCT3, REVEAL_FUNCT3, RV32M_FUNCT7,
10 RV32_ALU_OPCODE, SYSTEM_OPCODE, TERMINATE_FUNCT3,
11};
12use openvm_stark_backend::p3_field::PrimeField32;
13use openvm_transpiler::{
14 util::{nop, unimp},
15 TranspilerExtension, TranspilerOutput,
16};
17use rrs::InstructionTranspiler;
18use rrs_lib::{
19 instruction_formats::{IType, RType},
20 process_instruction,
21};
22
23mod instructions;
24pub mod rrs;
25pub use instructions::*;
26
27#[derive(Default)]
28pub struct Rv32ITranspilerExtension;
29
30#[derive(Default)]
31pub struct Rv32MTranspilerExtension;
32
33#[derive(Default)]
34pub struct Rv32IoTranspilerExtension;
35
36impl<F: PrimeField32> TranspilerExtension<F> for Rv32ITranspilerExtension {
37 fn process_custom(&self, instruction_stream: &[u32]) -> Option<TranspilerOutput<F>> {
38 let mut transpiler = InstructionTranspiler::<F>(PhantomData);
39 if instruction_stream.is_empty() {
40 return None;
41 }
42 let instruction_u32 = instruction_stream[0];
43
44 let opcode = (instruction_u32 & 0x7f) as u8;
45 let funct3 = ((instruction_u32 >> 12) & 0b111) as u8; let instruction = match (opcode, funct3) {
48 (CSR_OPCODE, _) => {
49 let dec_insn = IType::new(instruction_u32);
50 if dec_insn.funct3 as u8 == CSRRW_FUNCT3 {
51 if dec_insn.rs1 == 0 && dec_insn.rd == 0 {
53 return Some(TranspilerOutput::one_to_one(nop()));
56 }
57 }
58 eprintln!(
59 "Transpiling system / CSR instruction: {:b} (opcode = {:07b}, funct3 = {:03b}) to unimp",
60 instruction_u32, opcode, funct3
61 );
62 return Some(TranspilerOutput::one_to_one(unimp()));
63 }
64 (SYSTEM_OPCODE, TERMINATE_FUNCT3) => {
65 let dec_insn = IType::new(instruction_u32);
66 Some(Instruction {
67 opcode: SystemOpcode::TERMINATE.global_opcode(),
68 c: F::from_canonical_u8(
69 dec_insn.imm.try_into().expect("exit code must be byte"),
70 ),
71 ..Default::default()
72 })
73 }
74 (SYSTEM_OPCODE, PHANTOM_FUNCT3) => {
75 let dec_insn = IType::new(instruction_u32);
76 PhantomImm::from_repr(dec_insn.imm as u16).map(|phantom| match phantom {
77 PhantomImm::HintInput => Instruction::phantom(
78 PhantomDiscriminant(Rv32Phantom::HintInput as u16),
79 F::ZERO,
80 F::ZERO,
81 0,
82 ),
83 PhantomImm::HintRandom => Instruction::phantom(
84 PhantomDiscriminant(Rv32Phantom::HintRandom as u16),
85 F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rd),
86 F::ZERO,
87 0,
88 ),
89 PhantomImm::PrintStr => Instruction::phantom(
90 PhantomDiscriminant(Rv32Phantom::PrintStr as u16),
91 F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rd),
92 F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs1),
93 0,
94 ),
95 PhantomImm::HintLoadByKey => Instruction::phantom(
96 PhantomDiscriminant(Rv32Phantom::HintLoadByKey as u16),
97 F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rd),
98 F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs1),
99 0,
100 ),
101 })
102 }
103 (RV32_ALU_OPCODE, _) => {
104 let dec_insn = RType::new(instruction_u32);
106 let funct7 = dec_insn.funct7 as u8;
107 match funct7 {
108 RV32M_FUNCT7 => None,
109 _ => process_instruction(&mut transpiler, instruction_u32),
110 }
111 }
112 _ => process_instruction(&mut transpiler, instruction_u32),
113 };
114
115 instruction.map(TranspilerOutput::one_to_one)
116 }
117}
118
119impl<F: PrimeField32> TranspilerExtension<F> for Rv32MTranspilerExtension {
120 fn process_custom(&self, instruction_stream: &[u32]) -> Option<TranspilerOutput<F>> {
121 if instruction_stream.is_empty() {
122 return None;
123 }
124 let instruction_u32 = instruction_stream[0];
125
126 let opcode = (instruction_u32 & 0x7f) as u8;
127 if opcode != RV32_ALU_OPCODE {
128 return None;
129 }
130
131 let dec_insn = RType::new(instruction_u32);
132 let funct7 = dec_insn.funct7 as u8;
133 if funct7 != RV32M_FUNCT7 {
134 return None;
135 }
136
137 let instruction = process_instruction(
138 &mut InstructionTranspiler::<F>(PhantomData),
139 instruction_u32,
140 );
141
142 instruction.map(TranspilerOutput::one_to_one)
143 }
144}
145
146impl<F: PrimeField32> TranspilerExtension<F> for Rv32IoTranspilerExtension {
147 fn process_custom(&self, instruction_stream: &[u32]) -> Option<TranspilerOutput<F>> {
148 if instruction_stream.is_empty() {
149 return None;
150 }
151 let instruction_u32 = instruction_stream[0];
152
153 let opcode = (instruction_u32 & 0x7f) as u8;
154 let funct3 = ((instruction_u32 >> 12) & 0b111) as u8; if opcode != SYSTEM_OPCODE {
157 return None;
158 }
159
160 let instruction = match funct3 {
161 HINT_FUNCT3 => {
162 let dec_insn = IType::new(instruction_u32);
163 let imm_u16 = (dec_insn.imm as u32) & 0xffff;
164 match imm_u16 {
165 HINT_STOREW_IMM => Some(Instruction::from_isize(
166 Rv32HintStoreOpcode::HINT_STOREW.global_opcode(),
167 0,
168 (RV32_REGISTER_NUM_LIMBS * dec_insn.rd) as isize,
169 0,
170 1,
171 2,
172 )),
173 HINT_BUFFER_IMM => Some(Instruction::from_isize(
174 Rv32HintStoreOpcode::HINT_BUFFER.global_opcode(),
175 (RV32_REGISTER_NUM_LIMBS * dec_insn.rs1) as isize,
176 (RV32_REGISTER_NUM_LIMBS * dec_insn.rd) as isize,
177 0,
178 1,
179 2,
180 )),
181 _ => None,
182 }
183 }
184 REVEAL_FUNCT3 => {
185 let dec_insn = IType::new(instruction_u32);
186 let imm_u16 = (dec_insn.imm as u32) & 0xffff;
187 Some(Instruction::large_from_isize(
189 Rv32LoadStoreOpcode::STOREW.global_opcode(),
190 (RV32_REGISTER_NUM_LIMBS * dec_insn.rs1) as isize,
191 (RV32_REGISTER_NUM_LIMBS * dec_insn.rd) as isize,
192 imm_u16 as isize,
193 1,
194 3,
195 1,
196 (dec_insn.imm < 0) as isize,
197 ))
198 }
199 NATIVE_STOREW_FUNCT3 => {
200 let dec_insn = RType::new(instruction_u32);
202 if dec_insn.funct7 != NATIVE_STOREW_FUNCT7 {
203 return None;
204 }
205 Some(Instruction::large_from_isize(
206 Rv32LoadStoreOpcode::STOREW.global_opcode(),
207 (RV32_REGISTER_NUM_LIMBS * dec_insn.rs1) as isize,
208 (RV32_REGISTER_NUM_LIMBS * dec_insn.rd) as isize,
209 0,
210 1,
211 4,
212 1,
213 0,
214 ))
215 }
216 _ => return None,
217 };
218
219 instruction.map(TranspilerOutput::one_to_one)
220 }
221}