openvm_native_circuit/adapters/
alu_native_adapter.rs1use std::{
2 borrow::{Borrow, BorrowMut},
3 mem::size_of,
4};
5
6use openvm_circuit::{
7 arch::{
8 get_record_from_slice, AdapterAirContext, AdapterTraceExecutor, AdapterTraceFiller,
9 BasicAdapterInterface, ExecutionBridge, ExecutionState, MinimalInstruction, VmAdapterAir,
10 },
11 system::{
12 memory::{
13 offline_checker::{
14 MemoryBridge, MemoryReadAuxRecord, MemoryReadOrImmediateAuxCols,
15 MemoryWriteAuxCols, MemoryWriteAuxRecord,
16 },
17 online::TracingMemory,
18 MemoryAddress, MemoryAuxColsFactory,
19 },
20 native_adapter::util::{tracing_read_or_imm_native, tracing_write_native},
21 },
22};
23use openvm_circuit_primitives::AlignedBytesBorrow;
24use openvm_circuit_primitives_derive::AlignedBorrow;
25use openvm_instructions::{instruction::Instruction, program::DEFAULT_PC_STEP};
26use openvm_native_compiler::conversion::AS;
27use openvm_stark_backend::{
28 interaction::InteractionBuilder,
29 p3_air::BaseAir,
30 p3_field::{Field, FieldAlgebra, PrimeField32},
31};
32
33#[repr(C)]
34#[derive(AlignedBorrow)]
35pub struct AluNativeAdapterCols<T> {
36 pub from_state: ExecutionState<T>,
37 pub a_pointer: T,
38 pub b_pointer: T,
39 pub c_pointer: T,
40 pub e_as: T,
41 pub f_as: T,
42 pub reads_aux: [MemoryReadOrImmediateAuxCols<T>; 2],
43 pub write_aux: MemoryWriteAuxCols<T, 1>,
44}
45
46#[derive(Clone, Copy, Debug, derive_new::new)]
47pub struct AluNativeAdapterAir {
48 pub(super) execution_bridge: ExecutionBridge,
49 pub(super) memory_bridge: MemoryBridge,
50}
51
52impl<F: Field> BaseAir<F> for AluNativeAdapterAir {
53 fn width(&self) -> usize {
54 AluNativeAdapterCols::<F>::width()
55 }
56}
57
58impl<AB: InteractionBuilder> VmAdapterAir<AB> for AluNativeAdapterAir {
59 type Interface = BasicAdapterInterface<AB::Expr, MinimalInstruction<AB::Expr>, 2, 1, 1, 1>;
60
61 fn eval(
62 &self,
63 builder: &mut AB,
64 local: &[AB::Var],
65 ctx: AdapterAirContext<AB::Expr, Self::Interface>,
66 ) {
67 let cols: &AluNativeAdapterCols<_> = local.borrow();
68 let timestamp = cols.from_state.timestamp;
69 let mut timestamp_delta = 0usize;
70 let mut timestamp_pp = || {
71 timestamp_delta += 1;
72 timestamp + AB::F::from_canonical_usize(timestamp_delta - 1)
73 };
74
75 let native_as = AB::Expr::from_canonical_u32(AS::Native as u32);
76
77 self.memory_bridge
80 .read_or_immediate(
81 MemoryAddress::new(cols.e_as, cols.b_pointer),
82 ctx.reads[0][0].clone(),
83 timestamp_pp(),
84 &cols.reads_aux[0],
85 )
86 .eval(builder, ctx.instruction.is_valid.clone());
87
88 self.memory_bridge
89 .read_or_immediate(
90 MemoryAddress::new(cols.f_as, cols.c_pointer),
91 ctx.reads[1][0].clone(),
92 timestamp_pp(),
93 &cols.reads_aux[1],
94 )
95 .eval(builder, ctx.instruction.is_valid.clone());
96
97 self.memory_bridge
98 .write(
99 MemoryAddress::new(native_as.clone(), cols.a_pointer),
100 ctx.writes[0].clone(),
101 timestamp_pp(),
102 &cols.write_aux,
103 )
104 .eval(builder, ctx.instruction.is_valid.clone());
105
106 self.execution_bridge
107 .execute_and_increment_or_set_pc(
108 ctx.instruction.opcode,
109 [
110 cols.a_pointer.into(),
111 cols.b_pointer.into(),
112 cols.c_pointer.into(),
113 native_as.clone(),
114 cols.e_as.into(),
115 cols.f_as.into(),
116 ],
117 cols.from_state,
118 AB::F::from_canonical_usize(timestamp_delta),
119 (DEFAULT_PC_STEP, ctx.to_pc),
120 )
121 .eval(builder, ctx.instruction.is_valid);
122 }
123
124 fn get_from_pc(&self, local: &[AB::Var]) -> AB::Var {
125 let cols: &AluNativeAdapterCols<_> = local.borrow();
126 cols.from_state.pc
127 }
128}
129
130#[repr(C)]
131#[derive(AlignedBytesBorrow, Debug)]
132pub struct AluNativeAdapterRecord<F> {
133 pub from_pc: u32,
134 pub from_timestamp: u32,
135
136 pub a_ptr: F,
137 pub b: F,
138 pub c: F,
139
140 pub reads_aux: [MemoryReadAuxRecord; 2],
142 pub write_aux: MemoryWriteAuxRecord<F, 1>,
143}
144
145#[derive(derive_new::new, Clone, Copy)]
146pub struct AluNativeAdapterExecutor;
147
148#[derive(derive_new::new)]
149pub struct AluNativeAdapterFiller;
150
151impl<F: PrimeField32> AdapterTraceExecutor<F> for AluNativeAdapterExecutor {
152 const WIDTH: usize = size_of::<AluNativeAdapterCols<u8>>();
153 type ReadData = [F; 2];
154 type WriteData = [F; 1];
155 type RecordMut<'a> = &'a mut AluNativeAdapterRecord<F>;
156
157 #[inline(always)]
158 fn start(pc: u32, memory: &TracingMemory, record: &mut Self::RecordMut<'_>) {
159 record.from_pc = pc;
160 record.from_timestamp = memory.timestamp;
161 }
162
163 #[inline(always)]
164 fn read(
165 &self,
166 memory: &mut TracingMemory,
167 instruction: &Instruction<F>,
168 record: &mut Self::RecordMut<'_>,
169 ) -> Self::ReadData {
170 let &Instruction { b, c, e, f, .. } = instruction;
171
172 record.b = b;
173 let rs1 = tracing_read_or_imm_native(memory, e, b, &mut record.reads_aux[0].prev_timestamp);
174 record.c = c;
175 let rs2 = tracing_read_or_imm_native(memory, f, c, &mut record.reads_aux[1].prev_timestamp);
176 [rs1, rs2]
177 }
178
179 #[inline(always)]
180 fn write(
181 &self,
182 memory: &mut TracingMemory,
183 instruction: &Instruction<F>,
184 data: Self::WriteData,
185 record: &mut Self::RecordMut<'_>,
186 ) {
187 let &Instruction { a, .. } = instruction;
188
189 record.a_ptr = a;
190 tracing_write_native(
191 memory,
192 a.as_canonical_u32(),
193 data,
194 &mut record.write_aux.prev_timestamp,
195 &mut record.write_aux.prev_data,
196 );
197 }
198}
199
200impl<F: PrimeField32> AdapterTraceFiller<F> for AluNativeAdapterFiller {
201 const WIDTH: usize = size_of::<AluNativeAdapterCols<u8>>();
202
203 #[inline(always)]
204 fn fill_trace_row(&self, mem_helper: &MemoryAuxColsFactory<F>, mut adapter_row: &mut [F]) {
205 let record: &AluNativeAdapterRecord<F> =
209 unsafe { get_record_from_slice(&mut adapter_row, ()) };
210 let adapter_row: &mut AluNativeAdapterCols<F> = adapter_row.borrow_mut();
211
212 adapter_row
214 .write_aux
215 .set_prev_data(record.write_aux.prev_data);
216 mem_helper.fill(
217 record.write_aux.prev_timestamp,
218 record.from_timestamp + 2,
219 adapter_row.write_aux.as_mut(),
220 );
221
222 let native_as = F::from_canonical_u32(AS::Native as u32);
223 for ((i, read_record), read_cols) in record
224 .reads_aux
225 .iter()
226 .enumerate()
227 .zip(adapter_row.reads_aux.iter_mut())
228 .rev()
229 {
230 let as_col = if i == 0 {
231 &mut adapter_row.e_as
232 } else {
233 &mut adapter_row.f_as
234 };
235 if read_record.prev_timestamp == u32::MAX {
237 read_cols.is_zero_aux = F::ZERO;
238 read_cols.is_immediate = F::ONE;
239 mem_helper.fill(0, record.from_timestamp + i as u32, read_cols.as_mut());
240 *as_col = F::ZERO;
241 } else {
242 read_cols.is_zero_aux = native_as.inverse();
243 read_cols.is_immediate = F::ZERO;
244 mem_helper.fill(
245 read_record.prev_timestamp,
246 record.from_timestamp + i as u32,
247 read_cols.as_mut(),
248 );
249 *as_col = native_as;
250 }
251 }
252
253 adapter_row.c_pointer = record.c;
254 adapter_row.b_pointer = record.b;
255 adapter_row.a_pointer = record.a_ptr;
256
257 adapter_row.from_state.timestamp = F::from_canonical_u32(record.from_timestamp);
258 adapter_row.from_state.pc = F::from_canonical_u32(record.from_pc);
259 }
260}