miden_processor/trace/chiplets/ace/
trace.rs1use alloc::vec::Vec;
2use core::ops::Range;
3
4use miden_air::trace::{
5 RowIndex,
6 chiplets::ace::{
7 CLK_IDX, CTX_IDX, EVAL_OP_IDX, ID_0_IDX, ID_1_IDX, ID_2_IDX, M_0_IDX, M_1_IDX, PTR_IDX,
8 READ_NUM_EVAL_IDX, SELECTOR_BLOCK_IDX, SELECTOR_START_IDX, V_0_0_IDX, V_0_1_IDX, V_1_0_IDX,
9 V_1_1_IDX, V_2_0_IDX, V_2_1_IDX,
10 },
11};
12use miden_core::{
13 Felt, Word,
14 field::{BasedVectorSpace, QuadFelt},
15};
16
17use super::{
18 MAX_NUM_ACE_WIRES,
19 instruction::{Op, decode_instruction},
20};
21use crate::{ContextId, errors::AceError};
22
23#[derive(Debug, Clone)]
28pub struct CircuitEvaluation {
29 ctx: ContextId,
30 clk: RowIndex,
31
32 wire_bus: WireBus,
33
34 col_ptr: Vec<Felt>,
35 col_op: Vec<Felt>,
36
37 col_wire_out: WireColumn,
38 col_wire_left: WireColumn,
39 col_wire_right: WireColumn,
40
41 num_read_rows: u32,
42 num_eval_rows: u32,
43}
44
45impl CircuitEvaluation {
46 pub fn new(ctx: ContextId, clk: RowIndex, num_read_rows: u32, num_eval_rows: u32) -> Self {
53 let num_wires = 2 * (num_read_rows as u64) + (num_eval_rows as u64);
54 assert!(num_wires <= MAX_NUM_ACE_WIRES as u64, "too many wires");
55
56 let num_rows = num_read_rows + num_eval_rows;
57
58 Self {
59 ctx,
60 clk,
61 wire_bus: WireBus::new(num_wires as u32),
62 col_ptr: Vec::with_capacity(num_rows as usize),
63 col_op: Vec::with_capacity(num_eval_rows as usize),
64 col_wire_out: WireColumn::new(num_rows as usize),
65 col_wire_left: WireColumn::new(num_rows as usize),
66 col_wire_right: WireColumn::new(num_eval_rows as usize),
67 num_read_rows,
68 num_eval_rows,
69 }
70 }
71
72 pub fn num_rows(&self) -> usize {
73 (self.num_read_rows + self.num_eval_rows) as usize
74 }
75
76 pub fn clk(&self) -> u32 {
77 self.clk.into()
78 }
79
80 pub fn ctx(&self) -> u32 {
81 self.ctx.into()
82 }
83
84 pub fn num_read_rows(&self) -> u32 {
85 self.num_read_rows
86 }
87
88 pub fn num_eval_rows(&self) -> u32 {
89 self.num_eval_rows
90 }
91
92 pub fn do_read(&mut self, ptr: Felt, word: Word) {
95 let v_0 = QuadFelt::from_basis_coefficients_fn(|i: usize| [word[0], word[1]][i]);
97 let id_0 = self.wire_bus.insert(v_0);
98 self.col_wire_out.push(id_0, v_0);
99
100 let v_1 = QuadFelt::from_basis_coefficients_fn(|i: usize| [word[2], word[3]][i]);
102 let id_1 = self.wire_bus.insert(v_1);
103 self.col_wire_left.push(id_1, v_1);
104
105 self.col_ptr.push(ptr);
107 }
108
109 pub fn do_eval(&mut self, ptr: Felt, instruction: Felt) -> Result<(), AceError> {
112 let (id_l, id_r, op) = decode_instruction(instruction)
114 .ok_or(AceError("failed to decode instruction".into()))?;
115
116 let v_l = self
118 .wire_bus
119 .read_value(id_l)
120 .ok_or(AceError("failed to read from the wiring bus".into()))?;
121 let id_l = Felt::from_u32(id_l);
122 self.col_wire_left.push(id_l, v_l);
123
124 let v_r = self
126 .wire_bus
127 .read_value(id_r)
128 .ok_or(AceError("failed to read from the wiring bus".into()))?;
129 let id_r = Felt::from_u32(id_r);
130 self.col_wire_right.push(id_r, v_r);
131
132 let v_out = match op {
134 Op::Sub => v_l - v_r,
135 Op::Mul => v_l * v_r,
136 Op::Add => v_l + v_r,
137 };
138 let id_out = self.wire_bus.insert(v_out);
139 self.col_wire_out.push(id_out, v_out);
140
141 let op_sub = -Felt::ONE;
143 let op_mul = Felt::ZERO;
144 let op_add = Felt::ONE;
145 let op = match op {
146 Op::Sub => op_sub,
147 Op::Mul => op_mul,
148 Op::Add => op_add,
149 };
150 self.col_op.push(op);
151
152 self.col_ptr.push(ptr);
154
155 Ok(())
156 }
157
158 pub fn fill(&self, offset: usize, columns: &mut [Vec<Felt>]) {
159 let num_read_rows = self.num_read_rows as usize;
160 let num_eval_rows = self.num_eval_rows as usize;
161 let num_rows = num_read_rows + num_eval_rows;
162 let read_range = Range {
163 start: offset,
164 end: offset + num_read_rows,
165 };
166 let eval_range = Range {
167 start: read_range.end,
168 end: read_range.end + num_eval_rows,
169 };
170
171 columns[SELECTOR_START_IDX][offset] = Felt::ONE;
173 columns[SELECTOR_START_IDX][(offset + 1)..].fill(Felt::ZERO);
174
175 let f_read = Felt::ZERO;
177 let f_eval = Felt::ONE;
178 columns[SELECTOR_BLOCK_IDX][read_range.clone()].fill(f_read);
179 columns[SELECTOR_BLOCK_IDX][eval_range.clone()].fill(f_eval);
180
181 let ctx_felt = self.ctx.into();
183 columns[CTX_IDX][offset..offset + num_rows].fill(ctx_felt);
184
185 columns[PTR_IDX][offset..offset + num_rows].copy_from_slice(&self.col_ptr);
187
188 let clk_felt = self.clk.into();
190 columns[CLK_IDX][offset..offset + num_rows].fill(clk_felt);
191
192 let eval_section_first_idx = Felt::from_u32(self.num_eval_rows - 1);
194 columns[READ_NUM_EVAL_IDX][read_range.clone()].fill(eval_section_first_idx);
195
196 columns[EVAL_OP_IDX][eval_range.clone()].copy_from_slice(&self.col_op);
198
199 columns[ID_0_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_out.id);
201 columns[V_0_0_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_out.v_0);
202 columns[V_0_1_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_out.v_1);
203
204 columns[ID_1_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_left.id);
206 columns[V_1_0_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_left.v_0);
207 columns[V_1_1_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_left.v_1);
208
209 columns[ID_2_IDX][eval_range.clone()].copy_from_slice(&self.col_wire_right.id);
211 columns[V_2_0_IDX][eval_range.clone()].copy_from_slice(&self.col_wire_right.v_0);
212 columns[V_2_1_IDX][eval_range.clone()].copy_from_slice(&self.col_wire_right.v_1);
213
214 let mut multiplicities_iter = self.wire_bus.wires.iter().map(|(_v, m)| Felt::from_u32(*m));
216 for row_index in read_range {
218 let m_0 = multiplicities_iter
219 .next()
220 .expect("the m0 multiplicities were not constructed properly");
221 let m_1 = multiplicities_iter
222 .next()
223 .expect("the m1 multiplicities were not constructed properly");
224 columns[M_0_IDX][row_index] = m_0;
225 columns[M_1_IDX][row_index] = m_1;
226 }
227 for row_index in eval_range {
229 let m_0 = multiplicities_iter
230 .next()
231 .expect("the m0 multiplicities were not constructed properly");
232 columns[M_0_IDX][row_index] = m_0;
233 }
234
235 debug_assert!(multiplicities_iter.next().is_none());
236 }
237
238 pub fn output_value(&self) -> Option<QuadFelt> {
240 if !self.wire_bus.is_finalized() {
241 return None;
242 }
243 self.wire_bus.wires.last().map(|(v, _m)| *v)
244 }
245}
246
247#[derive(Debug, Clone)]
250struct WireColumn {
251 id: Vec<Felt>,
252 v_0: Vec<Felt>,
253 v_1: Vec<Felt>,
254}
255
256impl WireColumn {
257 fn new(num_rows: usize) -> Self {
258 Self {
259 id: Vec::with_capacity(num_rows),
260 v_0: Vec::with_capacity(num_rows),
261 v_1: Vec::with_capacity(num_rows),
262 }
263 }
264
265 fn push(&mut self, id: Felt, v: QuadFelt) {
267 self.id.push(id);
268 let v: &[Felt] = v.as_basis_coefficients_slice();
269 self.v_0.push(v[0]);
270 self.v_1.push(v[1]);
271 }
272}
273
274#[derive(Debug, Clone)]
283struct WireBus {
284 id_next: Felt,
286 wires: Vec<(QuadFelt, u32)>,
289 num_wires: u32,
291}
292
293impl WireBus {
294 fn new(num_wires: u32) -> Self {
295 Self {
296 wires: Vec::with_capacity(num_wires as usize),
297 num_wires,
298 id_next: Felt::from_u32(num_wires - 1),
299 }
300 }
301
302 fn insert(&mut self, value: QuadFelt) -> Felt {
304 debug_assert!(!self.is_finalized());
305 self.wires.push((value, 0));
306 let id = self.id_next;
307 self.id_next -= Felt::ONE;
308 id
309 }
310
311 fn read_value(&mut self, id: u32) -> Option<QuadFelt> {
314 let (v, m) = self
316 .num_wires
317 .checked_sub(id + 1)
318 .and_then(|id| self.wires.get_mut(id as usize))?;
319 *m += 1;
320 Some(*v)
321 }
322
323 fn is_finalized(&self) -> bool {
325 self.wires.len() == self.num_wires as usize
326 }
327}