1use std::borrow::Borrow;
2
3use openvm_circuit::{
4 arch::{
5 AdapterAirContext, AdapterTraceExecutor, AdapterTraceFiller, BasicAdapterInterface,
6 ExecutionBridge, MinimalInstruction, VmAdapterAir,
7 },
8 system::memory::{offline_checker::MemoryBridge, online::TracingMemory, MemoryAuxColsFactory},
9};
10use openvm_circuit_primitives::bitwise_op_lookup::{
11 BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip,
12};
13use openvm_instructions::{
14 instruction::Instruction,
15 riscv::{RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS},
16};
17use openvm_stark_backend::{
18 interaction::InteractionBuilder,
19 p3_air::BaseAir,
20 p3_field::{Field, PrimeField32},
21};
22
23use crate::{
24 Rv32VecHeapAdapterAir, Rv32VecHeapAdapterCols, Rv32VecHeapAdapterExecutor,
25 Rv32VecHeapAdapterFiller, Rv32VecHeapAdapterRecord,
26};
27
28#[derive(Clone, Copy, Debug, derive_new::new)]
35pub struct Rv32HeapAdapterAir<
36 const NUM_READS: usize,
37 const READ_SIZE: usize,
38 const WRITE_SIZE: usize,
39> {
40 pub(super) execution_bridge: ExecutionBridge,
41 pub(super) memory_bridge: MemoryBridge,
42 pub bus: BitwiseOperationLookupBus,
43 address_bits: usize,
45}
46
47impl<F: Field, const NUM_READS: usize, const READ_SIZE: usize, const WRITE_SIZE: usize> BaseAir<F>
48 for Rv32HeapAdapterAir<NUM_READS, READ_SIZE, WRITE_SIZE>
49{
50 fn width(&self) -> usize {
51 Rv32VecHeapAdapterCols::<F, NUM_READS, 1, 1, READ_SIZE, WRITE_SIZE>::width()
52 }
53}
54
55impl<
56 AB: InteractionBuilder,
57 const NUM_READS: usize,
58 const READ_SIZE: usize,
59 const WRITE_SIZE: usize,
60 > VmAdapterAir<AB> for Rv32HeapAdapterAir<NUM_READS, READ_SIZE, WRITE_SIZE>
61{
62 type Interface = BasicAdapterInterface<
63 AB::Expr,
64 MinimalInstruction<AB::Expr>,
65 NUM_READS,
66 1,
67 READ_SIZE,
68 WRITE_SIZE,
69 >;
70
71 fn eval(
72 &self,
73 builder: &mut AB,
74 local: &[AB::Var],
75 ctx: AdapterAirContext<AB::Expr, Self::Interface>,
76 ) {
77 let vec_heap_air: Rv32VecHeapAdapterAir<NUM_READS, 1, 1, READ_SIZE, WRITE_SIZE> =
78 Rv32VecHeapAdapterAir::new(
79 self.execution_bridge,
80 self.memory_bridge,
81 self.bus,
82 self.address_bits,
83 );
84 vec_heap_air.eval(builder, local, ctx.into());
85 }
86
87 fn get_from_pc(&self, local: &[AB::Var]) -> AB::Var {
88 let cols: &Rv32VecHeapAdapterCols<_, NUM_READS, 1, 1, READ_SIZE, WRITE_SIZE> =
89 local.borrow();
90 cols.from_state.pc
91 }
92}
93
94#[derive(Clone, Copy)]
95pub struct Rv32HeapAdapterExecutor<
96 const NUM_READS: usize,
97 const READ_SIZE: usize,
98 const WRITE_SIZE: usize,
99>(Rv32VecHeapAdapterExecutor<NUM_READS, 1, 1, READ_SIZE, WRITE_SIZE>);
100
101impl<const NUM_READS: usize, const READ_SIZE: usize, const WRITE_SIZE: usize>
102 Rv32HeapAdapterExecutor<NUM_READS, READ_SIZE, WRITE_SIZE>
103{
104 pub fn new(pointer_max_bits: usize) -> Self {
105 assert!(NUM_READS <= 2);
106 assert!(
107 RV32_CELL_BITS * RV32_REGISTER_NUM_LIMBS - pointer_max_bits < RV32_CELL_BITS,
108 "pointer_max_bits={pointer_max_bits} needs to be large enough for high limb range check"
109 );
110 Rv32HeapAdapterExecutor(Rv32VecHeapAdapterExecutor::new(pointer_max_bits))
111 }
112}
113
114pub struct Rv32HeapAdapterFiller<
115 const NUM_READS: usize,
116 const READ_SIZE: usize,
117 const WRITE_SIZE: usize,
118>(Rv32VecHeapAdapterFiller<NUM_READS, 1, 1, READ_SIZE, WRITE_SIZE>);
119
120impl<const NUM_READS: usize, const READ_SIZE: usize, const WRITE_SIZE: usize>
121 Rv32HeapAdapterFiller<NUM_READS, READ_SIZE, WRITE_SIZE>
122{
123 pub fn new(
124 pointer_max_bits: usize,
125 bitwise_lookup_chip: SharedBitwiseOperationLookupChip<RV32_CELL_BITS>,
126 ) -> Self {
127 assert!(NUM_READS <= 2);
128 assert!(
129 RV32_CELL_BITS * RV32_REGISTER_NUM_LIMBS - pointer_max_bits < RV32_CELL_BITS,
130 "pointer_max_bits={pointer_max_bits} needs to be large enough for high limb range check"
131 );
132 Rv32HeapAdapterFiller(Rv32VecHeapAdapterFiller::new(
133 pointer_max_bits,
134 bitwise_lookup_chip,
135 ))
136 }
137}
138
139impl<F: PrimeField32, const NUM_READS: usize, const READ_SIZE: usize, const WRITE_SIZE: usize>
140 AdapterTraceExecutor<F> for Rv32HeapAdapterExecutor<NUM_READS, READ_SIZE, WRITE_SIZE>
141where
142 F: PrimeField32,
143{
144 const WIDTH: usize =
145 Rv32VecHeapAdapterCols::<F, NUM_READS, 1, 1, READ_SIZE, WRITE_SIZE>::width();
146 type ReadData = [[u8; READ_SIZE]; NUM_READS];
147 type WriteData = [[u8; WRITE_SIZE]; 1];
148 type RecordMut<'a> = &'a mut Rv32VecHeapAdapterRecord<NUM_READS, 1, 1, READ_SIZE, WRITE_SIZE>;
149
150 fn start(pc: u32, memory: &TracingMemory, record: &mut Self::RecordMut<'_>) {
151 record.from_pc = pc;
152 record.from_timestamp = memory.timestamp;
153 }
154
155 fn read(
156 &self,
157 memory: &mut TracingMemory,
158 instruction: &Instruction<F>,
159 record: &mut Self::RecordMut<'_>,
160 ) -> Self::ReadData {
161 let read_data = AdapterTraceExecutor::<F>::read(&self.0, memory, instruction, record);
162 read_data.map(|r| r[0])
163 }
164
165 fn write(
166 &self,
167 memory: &mut TracingMemory,
168 instruction: &Instruction<F>,
169 data: Self::WriteData,
170 record: &mut Self::RecordMut<'_>,
171 ) {
172 AdapterTraceExecutor::<F>::write(&self.0, memory, instruction, data, record);
173 }
174}
175
176impl<F: PrimeField32, const NUM_READS: usize, const READ_SIZE: usize, const WRITE_SIZE: usize>
177 AdapterTraceFiller<F> for Rv32HeapAdapterFiller<NUM_READS, READ_SIZE, WRITE_SIZE>
178{
179 const WIDTH: usize =
180 Rv32VecHeapAdapterCols::<F, NUM_READS, 1, 1, READ_SIZE, WRITE_SIZE>::width();
181
182 fn fill_trace_row(&self, mem_helper: &MemoryAuxColsFactory<F>, adapter_row: &mut [F]) {
183 AdapterTraceFiller::<F>::fill_trace_row(&self.0, mem_helper, adapter_row);
184 }
185}