openvm_circuit/arch/testing/
test_adapter.rs
1use std::{
2 borrow::{Borrow, BorrowMut},
3 collections::VecDeque,
4 fmt::Debug,
5};
6
7use openvm_circuit_primitives_derive::AlignedBorrow;
8use openvm_instructions::instruction::Instruction;
9use openvm_stark_backend::{
10 interaction::InteractionBuilder,
11 p3_air::BaseAir,
12 p3_field::{Field, FieldAlgebra, PrimeField32},
13};
14use serde::{Deserialize, Serialize};
15
16use crate::{
17 arch::{
18 AdapterAirContext, AdapterRuntimeContext, DynAdapterInterface, DynArray, ExecutionBridge,
19 ExecutionState, MinimalInstruction, Result, VmAdapterAir, VmAdapterChip,
20 },
21 system::memory::{MemoryController, OfflineMemory},
22};
23
24pub struct TestAdapterChip<F> {
27 pub prank_reads: VecDeque<Vec<F>>,
29 pub prank_pc_inc: VecDeque<Option<u32>>,
32
33 pub air: TestAdapterAir,
34}
35
36impl<F> TestAdapterChip<F> {
37 pub fn new(
38 prank_reads: Vec<Vec<F>>,
39 prank_pc_inc: Vec<Option<u32>>,
40 execution_bridge: ExecutionBridge,
41 ) -> Self {
42 Self {
43 prank_reads: prank_reads.into(),
44 prank_pc_inc: prank_pc_inc.into(),
45 air: TestAdapterAir { execution_bridge },
46 }
47 }
48}
49
50#[derive(Clone, Serialize, Deserialize)]
51pub struct TestAdapterRecord<T> {
52 pub from_pc: u32,
53 pub operands: [T; 7],
54}
55
56impl<F: PrimeField32> VmAdapterChip<F> for TestAdapterChip<F> {
57 type ReadRecord = ();
58 type WriteRecord = TestAdapterRecord<F>;
59 type Air = TestAdapterAir;
60 type Interface = DynAdapterInterface<F>;
61
62 fn preprocess(
63 &mut self,
64 _memory: &mut MemoryController<F>,
65 _instruction: &Instruction<F>,
66 ) -> Result<(DynArray<F>, Self::ReadRecord)> {
67 Ok((
68 self.prank_reads
69 .pop_front()
70 .expect("Not enough prank reads provided")
71 .into(),
72 (),
73 ))
74 }
75
76 fn postprocess(
77 &mut self,
78 memory: &mut MemoryController<F>,
79 instruction: &Instruction<F>,
80 from_state: ExecutionState<u32>,
81 _output: AdapterRuntimeContext<F, Self::Interface>,
82 _read_record: &Self::ReadRecord,
83 ) -> Result<(ExecutionState<u32>, Self::WriteRecord)> {
84 let pc_inc = self
85 .prank_pc_inc
86 .pop_front()
87 .map(|x| x.unwrap_or(4))
88 .unwrap_or(4);
89 Ok((
90 ExecutionState {
91 pc: from_state.pc + pc_inc,
92 timestamp: memory.timestamp(),
93 },
94 TestAdapterRecord {
95 operands: [
96 instruction.a,
97 instruction.b,
98 instruction.c,
99 instruction.d,
100 instruction.e,
101 instruction.f,
102 instruction.g,
103 ],
104 from_pc: from_state.pc,
105 },
106 ))
107 }
108
109 fn generate_trace_row(
110 &self,
111 row_slice: &mut [F],
112 _read_record: Self::ReadRecord,
113 write_record: Self::WriteRecord,
114 _memory: &OfflineMemory<F>,
115 ) {
116 let cols: &mut TestAdapterCols<F> = row_slice.borrow_mut();
117 cols.from_pc = F::from_canonical_u32(write_record.from_pc);
118 cols.operands = write_record.operands;
119 }
122
123 fn air(&self) -> &Self::Air {
124 &self.air
125 }
126}
127
128#[derive(Clone, Copy, Debug)]
129pub struct TestAdapterAir {
130 pub execution_bridge: ExecutionBridge,
131}
132
133#[repr(C)]
134#[derive(AlignedBorrow)]
135pub struct TestAdapterCols<T> {
136 pub from_pc: T,
137 pub operands: [T; 7],
138}
139
140impl<F: Field> BaseAir<F> for TestAdapterAir {
141 fn width(&self) -> usize {
142 TestAdapterCols::<F>::width()
143 }
144}
145
146impl<AB: InteractionBuilder> VmAdapterAir<AB> for TestAdapterAir {
147 type Interface = DynAdapterInterface<AB::Expr>;
148
149 fn eval(
150 &self,
151 builder: &mut AB,
152 local: &[AB::Var],
153 ctx: AdapterAirContext<AB::Expr, Self::Interface>,
154 ) {
155 let processed_instruction: MinimalInstruction<AB::Expr> = ctx.instruction.into();
156 let cols: &TestAdapterCols<AB::Var> = local.borrow();
157 self.execution_bridge
158 .execute_and_increment_or_set_pc(
159 processed_instruction.opcode,
160 cols.operands.to_vec(),
161 ExecutionState {
162 pc: cols.from_pc.into(),
163 timestamp: AB::Expr::ONE,
164 },
165 AB::Expr::ZERO,
166 (4, ctx.to_pc),
167 )
168 .eval(builder, processed_instruction.is_valid);
169 }
170
171 fn get_from_pc(&self, local: &[AB::Var]) -> AB::Var {
172 let cols: &TestAdapterCols<AB::Var> = local.borrow();
173 cols.from_pc
174 }
175}