openvm_rv32im_circuit/adapters/
mod.rs1use std::ops::Mul;
2
3use openvm_circuit::{
4 arch::{execution_mode::ExecutionCtxTrait, VmStateMut},
5 system::memory::{
6 merkle::public_values::PUBLIC_VALUES_AS,
7 online::{GuestMemory, TracingMemory},
8 },
9};
10use openvm_instructions::riscv::{RV32_MEMORY_AS, RV32_REGISTER_AS};
11use openvm_stark_backend::p3_field::{PrimeCharacteristicRing, PrimeField32};
12
13mod alu;
14mod branch;
15mod jalr;
16mod loadstore;
17mod mul;
18mod rdwrite;
19
20pub use alu::*;
21pub use branch::*;
22pub use jalr::*;
23pub use loadstore::*;
24pub use mul::*;
25pub use openvm_instructions::riscv::{RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS};
26pub use rdwrite::*;
27
28pub const INT256_NUM_LIMBS: usize = 32;
30
31pub const RV_IS_TYPE_IMM_BITS: usize = 12;
33
34pub const RV_B_TYPE_IMM_BITS: usize = 13;
36
37pub const RV_J_TYPE_IMM_BITS: usize = 21;
38
39pub fn compose<F: PrimeField32>(ptr_data: [F; RV32_REGISTER_NUM_LIMBS]) -> u32 {
42 let mut val = 0;
43 for (i, limb) in ptr_data.map(|x| x.as_canonical_u32()).iter().enumerate() {
44 val += limb << (i * 8);
45 }
46 val
47}
48
49pub fn decompose<F: PrimeField32>(value: u32) -> [F; RV32_REGISTER_NUM_LIMBS] {
51 std::array::from_fn(|i| {
52 F::from_u32((value >> (RV32_CELL_BITS * i)) & ((1 << RV32_CELL_BITS) - 1))
53 })
54}
55
56#[inline(always)]
57pub fn imm_to_bytes(imm: u32) -> [u8; RV32_REGISTER_NUM_LIMBS] {
58 debug_assert_eq!(imm >> 24, 0);
59 let mut imm_le = imm.to_le_bytes();
60 imm_le[3] = imm_le[2];
61 imm_le
62}
63
64#[inline(always)]
65pub fn memory_read<const N: usize>(memory: &GuestMemory, address_space: u32, ptr: u32) -> [u8; N] {
66 debug_assert!(
67 address_space == RV32_REGISTER_AS
68 || address_space == RV32_MEMORY_AS
69 || address_space == PUBLIC_VALUES_AS,
70 );
71
72 unsafe { memory.read::<u8, N>(address_space, ptr) }
76}
77
78#[inline(always)]
79pub fn memory_write<const N: usize>(
80 memory: &mut GuestMemory,
81 address_space: u32,
82 ptr: u32,
83 data: [u8; N],
84) {
85 debug_assert!(
86 address_space == RV32_REGISTER_AS
87 || address_space == RV32_MEMORY_AS
88 || address_space == PUBLIC_VALUES_AS
89 );
90
91 unsafe { memory.write::<u8, N>(address_space, ptr, data) }
95}
96
97#[inline(always)]
101pub fn timed_read<const N: usize>(
102 memory: &mut TracingMemory,
103 address_space: u32,
104 ptr: u32,
105) -> (u32, [u8; N]) {
106 debug_assert!(
107 address_space == RV32_REGISTER_AS
108 || address_space == RV32_MEMORY_AS
109 || address_space == PUBLIC_VALUES_AS
110 );
111
112 unsafe { memory.read::<u8, N>(address_space, ptr) }
116}
117
118#[inline(always)]
119pub fn timed_write<const N: usize>(
120 memory: &mut TracingMemory,
121 address_space: u32,
122 ptr: u32,
123 data: [u8; N],
124) -> (u32, [u8; N]) {
125 debug_assert!(
126 address_space == RV32_REGISTER_AS
127 || address_space == RV32_MEMORY_AS
128 || address_space == PUBLIC_VALUES_AS
129 );
130
131 unsafe { memory.write::<u8, N>(address_space, ptr, data) }
135}
136
137#[inline(always)]
140pub fn tracing_read<const N: usize>(
141 memory: &mut TracingMemory,
142 address_space: u32,
143 ptr: u32,
144 prev_timestamp: &mut u32,
145) -> [u8; N] {
146 let (t_prev, data) = timed_read(memory, address_space, ptr);
147 *prev_timestamp = t_prev;
148 data
149}
150
151#[inline(always)]
152pub fn tracing_read_imm(
153 memory: &mut TracingMemory,
154 imm: u32,
155 imm_mut: &mut u32,
156) -> [u8; RV32_REGISTER_NUM_LIMBS] {
157 *imm_mut = imm;
158 debug_assert_eq!(imm >> 24, 0); memory.increment_timestamp();
161
162 let mut imm_le = imm.to_le_bytes();
163 imm_le[3] = imm_le[2];
166 imm_le
167}
168
169#[inline(always)]
172pub fn tracing_write<const N: usize>(
173 memory: &mut TracingMemory,
174 address_space: u32,
175 ptr: u32,
176 data: [u8; N],
177 prev_timestamp: &mut u32,
178 prev_data: &mut [u8; N],
179) {
180 let (t_prev, data_prev) = timed_write(memory, address_space, ptr, data);
181 *prev_timestamp = t_prev;
182 *prev_data = data_prev;
183}
184
185#[inline(always)]
186pub fn memory_read_from_state<F, Ctx, const N: usize>(
187 state: &mut VmStateMut<F, GuestMemory, Ctx>,
188 address_space: u32,
189 ptr: u32,
190) -> [u8; N]
191where
192 Ctx: ExecutionCtxTrait,
193{
194 state.ctx.on_memory_operation(address_space, ptr, N as u32);
195
196 memory_read(state.memory, address_space, ptr)
197}
198
199#[inline(always)]
200pub fn memory_write_from_state<F, Ctx, const N: usize>(
201 state: &mut VmStateMut<F, GuestMemory, Ctx>,
202 address_space: u32,
203 ptr: u32,
204 data: [u8; N],
205) where
206 Ctx: ExecutionCtxTrait,
207{
208 state.ctx.on_memory_operation(address_space, ptr, N as u32);
209
210 memory_write(state.memory, address_space, ptr, data)
211}
212
213#[inline(always)]
214pub fn read_rv32_register_from_state<F, Ctx>(
215 state: &mut VmStateMut<F, GuestMemory, Ctx>,
216 ptr: u32,
217) -> u32
218where
219 Ctx: ExecutionCtxTrait,
220{
221 u32::from_le_bytes(memory_read_from_state(state, RV32_REGISTER_AS, ptr))
222}
223
224#[inline(always)]
225pub fn read_rv32_register(memory: &GuestMemory, ptr: u32) -> u32 {
226 u32::from_le_bytes(memory_read(memory, RV32_REGISTER_AS, ptr))
227}
228
229pub fn abstract_compose<T: PrimeCharacteristicRing, V: Mul<T, Output = T>>(
230 data: [V; RV32_REGISTER_NUM_LIMBS],
231) -> T {
232 data.into_iter()
233 .enumerate()
234 .fold(T::ZERO, |acc, (i, limb)| {
235 acc + limb * T::from_u32(1 << (i * RV32_CELL_BITS))
236 })
237}
238
239pub fn tmp_convert_to_u8s<F: PrimeField32, const N: usize>(data: [F; N]) -> [u8; N] {
241 data.map(|x| x.as_canonical_u32() as u8)
242}