1#[cfg(test)]
2use alloc::vec::Vec;
3
4use miden_air::trace::MIN_TRACE_LEN;
5
6use super::chiplets::Chiplets;
7use crate::{Felt, ONE};
8#[cfg(test)]
9use crate::{operation::Operation, utils::ToElements};
10
11#[derive(Debug)]
20pub struct RowMajorTraceWriter<'a, E> {
21 data: &'a mut [E],
22 payload: usize,
23 stride: usize,
24}
25
26impl<'a, E: Copy> RowMajorTraceWriter<'a, E> {
27 #[cfg(test)]
29 pub(super) fn new(data: &'a mut [E], width: usize) -> Self {
30 Self::with_stride(data, width, width)
31 }
32
33 pub fn with_stride(data: &'a mut [E], payload: usize, stride: usize) -> Self {
36 debug_assert!(stride >= payload, "stride must be >= payload");
37 debug_assert_eq!(data.len() % stride, 0, "buffer length must be a multiple of stride");
38 Self { data, payload, stride }
39 }
40
41 #[inline(always)]
43 pub fn write_row(&mut self, row: usize, values: &[E]) {
44 debug_assert_eq!(values.len(), self.payload);
45 let start = row * self.stride;
46 self.data[start..start + self.payload].copy_from_slice(values);
47 }
48}
49
50pub struct ChipletTraceFragment<'a> {
59 band: &'a mut [Felt],
61 stride: usize,
62 col_start: usize,
63 num_rows: usize,
64 num_cols: usize,
65 row_offset: usize,
67 prefix_one_cols: &'static [usize],
69 write_chip_clk: bool,
71}
72
73impl<'a> ChipletTraceFragment<'a> {
74 pub fn row_major(
76 band: &'a mut [Felt],
77 stride: usize,
78 col_start: usize,
79 num_cols: usize,
80 ) -> Self {
81 Self::new(band, stride, col_start, num_cols, 0, &[], false)
82 }
83
84 pub fn with_overheads(
87 band: &'a mut [Felt],
88 stride: usize,
89 col_start: usize,
90 num_cols: usize,
91 row_offset: usize,
92 prefix_one_cols: &'static [usize],
93 ) -> Self {
94 Self::new(
95 band,
96 stride,
97 col_start,
98 num_cols,
99 row_offset,
100 prefix_one_cols,
101 stride > col_start + num_cols,
102 )
103 }
104
105 fn new(
106 band: &'a mut [Felt],
107 stride: usize,
108 col_start: usize,
109 num_cols: usize,
110 row_offset: usize,
111 prefix_one_cols: &'static [usize],
112 write_chip_clk: bool,
113 ) -> Self {
114 debug_assert_eq!(band.len() % stride, 0, "band length must be a multiple of stride");
115 debug_assert!(col_start + num_cols <= stride, "column band overruns the row stride");
116 debug_assert!(
117 prefix_one_cols.iter().all(|&col| col < col_start),
118 "prefix_one_cols must lie before col_start",
119 );
120 let num_rows = band.len() / stride;
121 Self {
122 band,
123 stride,
124 col_start,
125 num_rows,
126 num_cols,
127 row_offset,
128 prefix_one_cols,
129 write_chip_clk,
130 }
131 }
132
133 pub fn width(&self) -> usize {
138 self.num_cols
139 }
140
141 pub fn len(&self) -> usize {
143 self.num_rows
144 }
145
146 pub fn copy_rows_from(&mut self, src: &[Felt]) {
152 debug_assert_eq!(src.len(), self.num_rows * self.num_cols, "source buffer size mismatch");
153 self.copy_rows_into(0, src);
154 }
155
156 pub fn copy_rows_into(&mut self, row_offset: usize, src: &[Felt]) {
159 debug_assert_eq!(src.len() % self.num_cols, 0, "source buffer size not row-aligned");
160 let chunk_rows = src.len() / self.num_cols;
161 debug_assert!(
162 row_offset + chunk_rows <= self.num_rows,
163 "chunk overruns fragment row range",
164 );
165 let clk_col = self.stride - 1;
166 for r in 0..chunk_rows {
167 let dst_row = row_offset + r;
168 let row_start = dst_row * self.stride;
169 let row = &mut self.band[row_start..row_start + self.stride];
170 for &col in self.prefix_one_cols {
171 row[col] = ONE;
172 }
173 let src_row = &src[r * self.num_cols..(r + 1) * self.num_cols];
174 row[self.col_start..self.col_start + self.num_cols].copy_from_slice(src_row);
175 if self.write_chip_clk {
176 row[clk_col] = Felt::from_u32((self.row_offset + dst_row + 1) as u32);
177 }
178 }
179 }
180}
181
182#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
192pub struct TraceLenSummary {
193 core_trace_len: usize,
194 range_trace_len: usize,
195 chiplets_trace_len: ChipletsLengths,
196 poseidon2_permutation_trace_len: usize,
197 padded_trace_len: Option<usize>,
200}
201
202impl TraceLenSummary {
203 pub fn new(
204 core_trace_len: usize,
205 range_trace_len: usize,
206 chiplets_trace_len: ChipletsLengths,
207 ) -> Self {
208 TraceLenSummary {
209 core_trace_len,
210 range_trace_len,
211 chiplets_trace_len,
212 poseidon2_permutation_trace_len: 0,
213 padded_trace_len: None,
214 }
215 }
216
217 pub fn new_with_padded(
219 core_trace_len: usize,
220 range_trace_len: usize,
221 chiplets_trace_len: ChipletsLengths,
222 poseidon2_permutation_trace_len: usize,
223 padded_trace_len: usize,
224 ) -> Self {
225 TraceLenSummary {
226 core_trace_len,
227 range_trace_len,
228 chiplets_trace_len,
229 poseidon2_permutation_trace_len,
230 padded_trace_len: Some(padded_trace_len),
231 }
232 }
233
234 pub fn core_trace_len(&self) -> usize {
236 self.core_trace_len
237 }
238
239 pub fn range_trace_len(&self) -> usize {
241 self.range_trace_len
242 }
243
244 pub fn chiplets_trace_len(&self) -> ChipletsLengths {
246 self.chiplets_trace_len
247 }
248
249 pub fn poseidon2_permutation_trace_len(&self) -> usize {
251 self.poseidon2_permutation_trace_len
252 }
253
254 pub fn trace_len(&self) -> usize {
256 self.range_trace_len
257 .max(self.core_trace_len)
258 .max(self.chiplets_trace_len.trace_len())
259 .max(self.poseidon2_permutation_trace_len)
260 }
261
262 pub fn padded_trace_len(&self) -> usize {
264 self.padded_trace_len
265 .unwrap_or_else(|| self.trace_len().next_power_of_two().max(MIN_TRACE_LEN))
266 }
267
268 pub fn padding_percentage(&self) -> usize {
270 (self.padded_trace_len() - self.trace_len()) * 100 / self.padded_trace_len()
271 }
272}
273
274#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
279pub struct ChipletsLengths {
280 hash_chiplet_len: usize,
281 bitwise_chiplet_len: usize,
282 memory_chiplet_len: usize,
283 ace_chiplet_len: usize,
284 kernel_rom_len: usize,
285}
286
287impl ChipletsLengths {
288 pub fn new(chiplets: &Chiplets) -> Self {
289 ChipletsLengths {
290 hash_chiplet_len: chiplets.bitwise_start().into(),
291 bitwise_chiplet_len: chiplets.memory_start() - chiplets.bitwise_start(),
292 memory_chiplet_len: chiplets.ace_start() - chiplets.memory_start(),
293 ace_chiplet_len: chiplets.kernel_rom_start() - chiplets.ace_start(),
294 kernel_rom_len: chiplets.padding_start() - chiplets.kernel_rom_start(),
295 }
296 }
297
298 pub fn from_parts(
299 hash_len: usize,
300 bitwise_len: usize,
301 memory_len: usize,
302 ace_len: usize,
303 kernel_len: usize,
304 ) -> Self {
305 ChipletsLengths {
306 hash_chiplet_len: hash_len,
307 bitwise_chiplet_len: bitwise_len,
308 memory_chiplet_len: memory_len,
309 ace_chiplet_len: ace_len,
310 kernel_rom_len: kernel_len,
311 }
312 }
313
314 pub fn hash_chiplet_len(&self) -> usize {
316 self.hash_chiplet_len
317 }
318
319 pub fn bitwise_chiplet_len(&self) -> usize {
321 self.bitwise_chiplet_len
322 }
323
324 pub fn memory_chiplet_len(&self) -> usize {
326 self.memory_chiplet_len
327 }
328
329 pub fn ace_chiplet_len(&self) -> usize {
331 self.ace_chiplet_len
332 }
333
334 pub fn kernel_rom_len(&self) -> usize {
336 self.kernel_rom_len
337 }
338
339 pub fn trace_len(&self) -> usize {
343 self.hash_chiplet_len()
344 + self.bitwise_chiplet_len()
345 + self.memory_chiplet_len()
346 + self.ace_chiplet_len()
347 + self.kernel_rom_len()
348 + 1
349 }
350}
351
352pub(crate) fn split_element_u32_into_u16(value: Felt) -> (Felt, Felt) {
358 let (hi, lo) = split_u32_into_u16(value.as_canonical_u64());
359 (Felt::new_unchecked(hi as u64), Felt::new_unchecked(lo as u64))
360}
361
362pub(crate) fn split_u32_into_u16(value: u64) -> (u16, u16) {
367 const U32MAX: u64 = u32::MAX as u64;
368 debug_assert!(value <= U32MAX, "not a 32-bit value");
369
370 let lo = value as u16;
371 let hi = (value >> 16) as u16;
372
373 (hi, lo)
374}
375
376#[cfg(test)]
383pub(super) fn build_span_with_respan_ops() -> (Vec<Operation>, Vec<Felt>) {
384 let iv = [1, 3, 5, 7, 9, 11, 13, 15, 17].to_elements();
385 let ops = alloc::vec![
386 Operation::Push(iv[0]),
387 Operation::Push(iv[1]),
388 Operation::Push(iv[2]),
389 Operation::Push(iv[3]),
390 Operation::Push(iv[4]),
391 Operation::Push(iv[5]),
392 Operation::Push(iv[6]),
393 Operation::Push(iv[7]),
395 Operation::Push(iv[8]),
396 Operation::Add,
397 Operation::Drop,
399 Operation::Drop,
400 Operation::Drop,
401 Operation::Drop,
402 Operation::Drop,
403 Operation::Drop,
404 Operation::Drop,
405 Operation::Drop,
406 ];
407 (ops, iv)
408}