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, PrimeCharacteristicRing, QuadFelt},
15};
16
17use super::{
18 MAX_NUM_ACE_WIRES,
19 instruction::{Op, decode_instruction},
20};
21use crate::{ContextId, errors::AceError};
22
23pub const NUM_ACE_LOGUP_FRACTIONS_READ: usize = 2;
25pub const NUM_ACE_LOGUP_FRACTIONS_EVAL: usize = 3;
27
28#[derive(Debug, Clone)]
33pub struct CircuitEvaluation {
34 ctx: ContextId,
35 clk: RowIndex,
36
37 wire_bus: WireBus,
38
39 col_ptr: Vec<Felt>,
40 col_op: Vec<Felt>,
41
42 col_wire_out: WireColumn,
43 col_wire_left: WireColumn,
44 col_wire_right: WireColumn,
45
46 num_read_rows: u32,
47 num_eval_rows: u32,
48}
49
50impl CircuitEvaluation {
51 pub fn new(ctx: ContextId, clk: RowIndex, num_read_rows: u32, num_eval_rows: u32) -> Self {
58 let num_wires = 2 * (num_read_rows as u64) + (num_eval_rows as u64);
59 assert!(num_wires <= MAX_NUM_ACE_WIRES as u64, "too many wires");
60
61 let num_rows = num_read_rows + num_eval_rows;
62
63 Self {
64 ctx,
65 clk,
66 wire_bus: WireBus::new(num_wires as u32),
67 col_ptr: Vec::with_capacity(num_rows as usize),
68 col_op: Vec::with_capacity(num_eval_rows as usize),
69 col_wire_out: WireColumn::new(num_rows as usize),
70 col_wire_left: WireColumn::new(num_rows as usize),
71 col_wire_right: WireColumn::new(num_eval_rows as usize),
72 num_read_rows,
73 num_eval_rows,
74 }
75 }
76
77 pub fn num_rows(&self) -> usize {
78 (self.num_read_rows + self.num_eval_rows) as usize
79 }
80
81 pub fn clk(&self) -> u32 {
82 self.clk.into()
83 }
84
85 pub fn ctx(&self) -> u32 {
86 self.ctx.into()
87 }
88
89 pub fn num_read_rows(&self) -> u32 {
90 self.num_read_rows
91 }
92
93 pub fn num_eval_rows(&self) -> u32 {
94 self.num_eval_rows
95 }
96
97 pub fn do_read(&mut self, ptr: Felt, word: Word) {
100 let v_0 = QuadFelt::from_basis_coefficients_fn(|i: usize| [word[0], word[1]][i]);
102 let id_0 = self.wire_bus.insert(v_0);
103 self.col_wire_out.push(id_0, v_0);
104
105 let v_1 = QuadFelt::from_basis_coefficients_fn(|i: usize| [word[2], word[3]][i]);
107 let id_1 = self.wire_bus.insert(v_1);
108 self.col_wire_left.push(id_1, v_1);
109
110 self.col_ptr.push(ptr);
112 }
113
114 pub fn do_eval(&mut self, ptr: Felt, instruction: Felt) -> Result<(), AceError> {
117 let (id_l, id_r, op) =
119 decode_instruction(instruction).ok_or(AceError::FailedDecodeInstruction)?;
120
121 let v_l = self.wire_bus.read_value(id_l).ok_or(AceError::FailedWireBusRead)?;
123 let id_l = Felt::from_u32(id_l);
124 self.col_wire_left.push(id_l, v_l);
125
126 let v_r = self.wire_bus.read_value(id_r).ok_or(AceError::FailedWireBusRead)?;
128 let id_r = Felt::from_u32(id_r);
129 self.col_wire_right.push(id_r, v_r);
130
131 let v_out = match op {
133 Op::Sub => v_l - v_r,
134 Op::Mul => v_l * v_r,
135 Op::Add => v_l + v_r,
136 };
137 let id_out = self.wire_bus.insert(v_out);
138 self.col_wire_out.push(id_out, v_out);
139
140 let op_sub = -Felt::ONE;
142 let op_mul = Felt::ZERO;
143 let op_add = Felt::ONE;
144 let op = match op {
145 Op::Sub => op_sub,
146 Op::Mul => op_mul,
147 Op::Add => op_add,
148 };
149 self.col_op.push(op);
150
151 self.col_ptr.push(ptr);
153
154 Ok(())
155 }
156
157 pub fn fill(&self, offset: usize, columns: &mut [Vec<Felt>]) {
158 let num_read_rows = self.num_read_rows as usize;
159 let num_eval_rows = self.num_eval_rows as usize;
160 let num_rows = num_read_rows + num_eval_rows;
161 let read_range = Range {
162 start: offset,
163 end: offset + num_read_rows,
164 };
165 let eval_range = Range {
166 start: read_range.end,
167 end: read_range.end + num_eval_rows,
168 };
169
170 columns[SELECTOR_START_IDX][offset] = Felt::ONE;
172 columns[SELECTOR_START_IDX][(offset + 1)..].fill(Felt::ZERO);
173
174 let f_read = Felt::ZERO;
176 let f_eval = Felt::ONE;
177 columns[SELECTOR_BLOCK_IDX][read_range.clone()].fill(f_read);
178 columns[SELECTOR_BLOCK_IDX][eval_range.clone()].fill(f_eval);
179
180 let ctx_felt = self.ctx.into();
182 columns[CTX_IDX][offset..offset + num_rows].fill(ctx_felt);
183
184 columns[PTR_IDX][offset..offset + num_rows].copy_from_slice(&self.col_ptr);
186
187 let clk_felt = self.clk.into();
189 columns[CLK_IDX][offset..offset + num_rows].fill(clk_felt);
190
191 let eval_section_first_idx = Felt::from_u32(self.num_eval_rows - 1);
193 columns[READ_NUM_EVAL_IDX][read_range.clone()].fill(eval_section_first_idx);
194
195 columns[EVAL_OP_IDX][eval_range.clone()].copy_from_slice(&self.col_op);
197
198 columns[ID_0_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_out.id);
200 columns[V_0_0_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_out.v_0);
201 columns[V_0_1_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_out.v_1);
202
203 columns[ID_1_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_left.id);
205 columns[V_1_0_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_left.v_0);
206 columns[V_1_1_IDX][offset..offset + num_rows].copy_from_slice(&self.col_wire_left.v_1);
207
208 columns[ID_2_IDX][eval_range.clone()].copy_from_slice(&self.col_wire_right.id);
210 columns[V_2_0_IDX][eval_range.clone()].copy_from_slice(&self.col_wire_right.v_0);
211 columns[V_2_1_IDX][eval_range.clone()].copy_from_slice(&self.col_wire_right.v_1);
212
213 let mut multiplicities_iter = self.wire_bus.wires.iter().map(|(_v, m)| Felt::from_u32(*m));
215 for row_index in read_range {
217 let m_0 = multiplicities_iter
218 .next()
219 .expect("the m0 multiplicities were not constructed properly");
220 let m_1 = multiplicities_iter
221 .next()
222 .expect("the m1 multiplicities were not constructed properly");
223 columns[M_0_IDX][row_index] = m_0;
224 columns[M_1_IDX][row_index] = m_1;
225 }
226 for row_index in eval_range {
228 let m_0 = multiplicities_iter
229 .next()
230 .expect("the m0 multiplicities were not constructed properly");
231 columns[M_0_IDX][row_index] = m_0;
232 }
233
234 debug_assert!(multiplicities_iter.next().is_none());
235 }
236
237 pub fn output_value(&self) -> Option<QuadFelt> {
239 if !self.wire_bus.is_finalized() {
240 return None;
241 }
242 self.wire_bus.wires.last().map(|(v, _m)| *v)
243 }
244}
245
246#[derive(Debug, Clone)]
249struct WireColumn {
250 id: Vec<Felt>,
251 v_0: Vec<Felt>,
252 v_1: Vec<Felt>,
253}
254
255impl WireColumn {
256 fn new(num_rows: usize) -> Self {
257 Self {
258 id: Vec::with_capacity(num_rows),
259 v_0: Vec::with_capacity(num_rows),
260 v_1: Vec::with_capacity(num_rows),
261 }
262 }
263
264 fn push(&mut self, id: Felt, v: QuadFelt) {
266 self.id.push(id);
267 let v: &[Felt] = v.as_basis_coefficients_slice();
268 self.v_0.push(v[0]);
269 self.v_1.push(v[1]);
270 }
271}
272
273#[derive(Debug, Clone)]
282struct WireBus {
283 id_next: Felt,
285 wires: Vec<(QuadFelt, u32)>,
288 num_wires: u32,
290}
291
292impl WireBus {
293 fn new(num_wires: u32) -> Self {
294 Self {
295 wires: Vec::with_capacity(num_wires as usize),
296 num_wires,
297 id_next: Felt::from_u32(num_wires - 1),
298 }
299 }
300
301 fn insert(&mut self, value: QuadFelt) -> Felt {
303 debug_assert!(!self.is_finalized());
304 self.wires.push((value, 0));
305 let id = self.id_next;
306 self.id_next -= Felt::ONE;
307 id
308 }
309
310 fn read_value(&mut self, id: u32) -> Option<QuadFelt> {
313 let (v, m) = self
315 .num_wires
316 .checked_sub(id + 1)
317 .and_then(|id| self.wires.get_mut(id as usize))?;
318 *m += 1;
319 Some(*v)
320 }
321
322 fn is_finalized(&self) -> bool {
324 self.wires.len() == self.num_wires as usize
325 }
326}