openvm_rv32im_circuit/adapters/
branch.rs1use std::borrow::{Borrow, BorrowMut};
2
3use openvm_circuit::{
4 arch::{
5 get_record_from_slice, AdapterAirContext, AdapterTraceExecutor, AdapterTraceFiller,
6 BasicAdapterInterface, ExecutionBridge, ExecutionState, ImmInstruction, VmAdapterAir,
7 },
8 system::memory::{
9 offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryReadAuxRecord},
10 online::TracingMemory,
11 MemoryAddress, MemoryAuxColsFactory,
12 },
13};
14use openvm_circuit_primitives::{
15 AlignedBytesBorrow, ColumnsAir, StructReflection, StructReflectionHelper,
16};
17use openvm_circuit_primitives_derive::AlignedBorrow;
18use openvm_instructions::{
19 instruction::Instruction, program::DEFAULT_PC_STEP, riscv::RV32_REGISTER_AS,
20};
21use openvm_stark_backend::{
22 interaction::InteractionBuilder,
23 p3_air::BaseAir,
24 p3_field::{Field, PrimeCharacteristicRing, PrimeField32},
25};
26
27use super::RV32_REGISTER_NUM_LIMBS;
28use crate::adapters::tracing_read;
29
30#[repr(C)]
31#[derive(AlignedBorrow, StructReflection)]
32pub struct Rv32BranchAdapterCols<T> {
33 pub from_state: ExecutionState<T>,
34 pub rs1_ptr: T,
35 pub rs2_ptr: T,
36 pub reads_aux: [MemoryReadAuxCols<T>; 2],
37}
38
39#[derive(Clone, Copy, Debug, derive_new::new, ColumnsAir)]
40#[columns_via(Rv32BranchAdapterCols<u8>)]
41pub struct Rv32BranchAdapterAir {
42 pub(super) execution_bridge: ExecutionBridge,
43 pub(super) memory_bridge: MemoryBridge,
44}
45
46impl<F: Field> BaseAir<F> for Rv32BranchAdapterAir {
47 fn width(&self) -> usize {
48 Rv32BranchAdapterCols::<F>::width()
49 }
50}
51
52impl<AB: InteractionBuilder> VmAdapterAir<AB> for Rv32BranchAdapterAir {
53 type Interface =
54 BasicAdapterInterface<AB::Expr, ImmInstruction<AB::Expr>, 2, 0, RV32_REGISTER_NUM_LIMBS, 0>;
55
56 fn eval(
57 &self,
58 builder: &mut AB,
59 local: &[AB::Var],
60 ctx: AdapterAirContext<AB::Expr, Self::Interface>,
61 ) {
62 let local: &Rv32BranchAdapterCols<_> = local.borrow();
63 let timestamp = local.from_state.timestamp;
64 let mut timestamp_delta: usize = 0;
65 let mut timestamp_pp = || {
66 timestamp_delta += 1;
67 timestamp + AB::F::from_usize(timestamp_delta - 1)
68 };
69
70 self.memory_bridge
71 .read(
72 MemoryAddress::new(AB::F::from_u32(RV32_REGISTER_AS), local.rs1_ptr),
73 ctx.reads[0].clone(),
74 timestamp_pp(),
75 &local.reads_aux[0],
76 )
77 .eval(builder, ctx.instruction.is_valid.clone());
78
79 self.memory_bridge
80 .read(
81 MemoryAddress::new(AB::F::from_u32(RV32_REGISTER_AS), local.rs2_ptr),
82 ctx.reads[1].clone(),
83 timestamp_pp(),
84 &local.reads_aux[1],
85 )
86 .eval(builder, ctx.instruction.is_valid.clone());
87
88 self.execution_bridge
89 .execute_and_increment_or_set_pc(
90 ctx.instruction.opcode,
91 [
92 local.rs1_ptr.into(),
93 local.rs2_ptr.into(),
94 ctx.instruction.immediate,
95 AB::Expr::from_u32(RV32_REGISTER_AS),
96 AB::Expr::from_u32(RV32_REGISTER_AS),
97 ],
98 local.from_state,
99 AB::F::from_usize(timestamp_delta),
100 (DEFAULT_PC_STEP, ctx.to_pc),
101 )
102 .eval(builder, ctx.instruction.is_valid);
103 }
104
105 fn get_from_pc(&self, local: &[AB::Var]) -> AB::Var {
106 let cols: &Rv32BranchAdapterCols<_> = local.borrow();
107 cols.from_state.pc
108 }
109}
110
111#[repr(C)]
112#[derive(AlignedBytesBorrow, Debug)]
113pub struct Rv32BranchAdapterRecord {
114 pub from_pc: u32,
115 pub from_timestamp: u32,
116 pub rs1_ptr: u32,
117 pub rs2_ptr: u32,
118 pub reads_aux: [MemoryReadAuxRecord; 2],
119}
120
121#[derive(Clone, Copy, derive_new::new)]
124pub struct Rv32BranchAdapterExecutor;
125
126#[derive(derive_new::new)]
127pub struct Rv32BranchAdapterFiller;
128
129impl<F> AdapterTraceExecutor<F> for Rv32BranchAdapterExecutor
130where
131 F: PrimeField32,
132{
133 const WIDTH: usize = size_of::<Rv32BranchAdapterCols<u8>>();
134 type ReadData = [[u8; RV32_REGISTER_NUM_LIMBS]; 2];
135 type WriteData = ();
136 type RecordMut<'a> = &'a mut Rv32BranchAdapterRecord;
137
138 #[inline(always)]
139 fn start(pc: u32, memory: &TracingMemory, record: &mut &mut Rv32BranchAdapterRecord) {
140 record.from_pc = pc;
141 record.from_timestamp = memory.timestamp;
142 }
143
144 #[inline(always)]
145 fn read(
146 &self,
147 memory: &mut TracingMemory,
148 instruction: &Instruction<F>,
149 record: &mut &mut Rv32BranchAdapterRecord,
150 ) -> Self::ReadData {
151 let &Instruction { a, b, d, e, .. } = instruction;
152
153 debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS);
154 debug_assert_eq!(e.as_canonical_u32(), RV32_REGISTER_AS);
155
156 record.rs1_ptr = a.as_canonical_u32();
157 let rs1 = tracing_read(
158 memory,
159 RV32_REGISTER_AS,
160 a.as_canonical_u32(),
161 &mut record.reads_aux[0].prev_timestamp,
162 );
163 record.rs2_ptr = b.as_canonical_u32();
164 let rs2 = tracing_read(
165 memory,
166 RV32_REGISTER_AS,
167 b.as_canonical_u32(),
168 &mut record.reads_aux[1].prev_timestamp,
169 );
170
171 [rs1, rs2]
172 }
173
174 #[inline(always)]
175 fn write(
176 &self,
177 _memory: &mut TracingMemory,
178 _instruction: &Instruction<F>,
179 _data: Self::WriteData,
180 _record: &mut Self::RecordMut<'_>,
181 ) {
182 }
184}
185
186impl<F: PrimeField32> AdapterTraceFiller<F> for Rv32BranchAdapterFiller {
187 const WIDTH: usize = size_of::<Rv32BranchAdapterCols<u8>>();
188
189 #[inline(always)]
190 fn fill_trace_row(&self, mem_helper: &MemoryAuxColsFactory<F>, mut adapter_row: &mut [F]) {
191 let record: &Rv32BranchAdapterRecord =
196 unsafe { get_record_from_slice(&mut adapter_row, ()) };
197 let adapter_row: &mut Rv32BranchAdapterCols<F> = adapter_row.borrow_mut();
198
199 let timestamp = record.from_timestamp;
201
202 mem_helper.fill(
203 record.reads_aux[1].prev_timestamp,
204 timestamp + 1,
205 adapter_row.reads_aux[1].as_mut(),
206 );
207
208 mem_helper.fill(
209 record.reads_aux[0].prev_timestamp,
210 timestamp,
211 adapter_row.reads_aux[0].as_mut(),
212 );
213
214 adapter_row.from_state.pc = F::from_u32(record.from_pc);
215 adapter_row.from_state.timestamp = F::from_u32(record.from_timestamp);
216 adapter_row.rs1_ptr = F::from_u32(record.rs1_ptr);
217 adapter_row.rs2_ptr = F::from_u32(record.rs2_ptr);
218 }
219}