use core::ops::ControlFlow;
use miden_air::trace::{
CLK_COL_IDX, CTX_COL_IDX, DECODER_TRACE_OFFSET, FN_HASH_OFFSET, STACK_TRACE_OFFSET,
SYS_TRACE_WIDTH,
decoder::{
ADDR_COL_IDX, GROUP_COUNT_COL_IDX, HASHER_STATE_OFFSET, IN_SPAN_COL_IDX,
NUM_OP_BATCH_FLAGS, NUM_OP_BITS, OP_BATCH_FLAGS_OFFSET, OP_BITS_EXTRA_COLS_OFFSET,
OP_BITS_OFFSET, OP_INDEX_COL_IDX,
},
stack::{B0_COL_IDX, B1_COL_IDX, H0_COL_IDX, STACK_TOP_OFFSET, STACK_TOP_RANGE},
};
use miden_core::{Felt, ONE, Operation, Word, ZERO};
use super::CoreTraceFragmentGenerator;
use crate::{fast::trace_state::NodeFlags, processor::StackInterface};
#[derive(Debug)]
pub struct OperationTraceConfig {
pub opcode: u8,
pub hasher_state: (Word, Word),
pub addr: Felt,
}
impl CoreTraceFragmentGenerator {
pub fn add_end_trace_row(&mut self, node_digest: Word) -> ControlFlow<()> {
let (ended_node_addr, flags) = self.update_decoder_state_on_node_end();
self.add_end_trace_row_impl(node_digest, flags, ended_node_addr)
}
pub fn add_end_trace_row_impl(
&mut self,
node_digest: Word,
flags: NodeFlags,
ended_node_addr: Felt,
) -> ControlFlow<()> {
let config = OperationTraceConfig {
opcode: Operation::End.op_code(),
hasher_state: (node_digest, flags.to_hasher_state_second_word()),
addr: ended_node_addr,
};
self.span_context = None;
self.add_control_flow_trace_row(config)
}
pub fn add_control_flow_trace_row(&mut self, config: OperationTraceConfig) -> ControlFlow<()> {
let row_idx = self.num_rows_built();
self.populate_system_trace_columns(row_idx);
self.populate_decoder_trace_columns(row_idx, &config);
self.populate_stack_trace_columns(row_idx);
self.increment_clk()
}
pub fn populate_system_trace_columns(&mut self, row_idx: usize) {
if let Some(system_rows) = self.system_rows {
for (i, &value) in system_rows.iter().enumerate() {
self.fragment.columns[i][row_idx] = value;
}
}
let mut new_system_rows = [ZERO; SYS_TRACE_WIDTH];
new_system_rows[CLK_COL_IDX] = Felt::from(self.context.state.system.clk + 1); new_system_rows[CTX_COL_IDX] = Felt::from(self.context.state.system.ctx); new_system_rows[FN_HASH_OFFSET] = self.context.state.system.fn_hash[0]; new_system_rows[FN_HASH_OFFSET + 1] = self.context.state.system.fn_hash[1]; new_system_rows[FN_HASH_OFFSET + 2] = self.context.state.system.fn_hash[2]; new_system_rows[FN_HASH_OFFSET + 3] = self.context.state.system.fn_hash[3];
self.system_rows = Some(new_system_rows);
}
fn populate_decoder_trace_columns(&mut self, row_idx: usize, config: &OperationTraceConfig) {
self.fragment.columns[DECODER_TRACE_OFFSET + ADDR_COL_IDX][row_idx] = config.addr;
let opcode = config.opcode;
for i in 0..NUM_OP_BITS {
let bit = Felt::from((opcode >> i) & 1);
self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + i][row_idx] = bit;
}
let (first_hash, second_hash) = config.hasher_state;
self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET][row_idx] = first_hash[0]; self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 1][row_idx] =
first_hash[1]; self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 2][row_idx] =
first_hash[2]; self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 3][row_idx] =
first_hash[3]; self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 4][row_idx] =
second_hash[0]; self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 5][row_idx] =
second_hash[1]; self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 6][row_idx] =
second_hash[2]; self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 7][row_idx] =
second_hash[3];
self.fragment.columns[DECODER_TRACE_OFFSET + OP_INDEX_COL_IDX][row_idx] = ZERO;
self.fragment.columns[DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX][row_idx] = ZERO;
self.fragment.columns[DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX][row_idx] = ZERO;
for i in 0..NUM_OP_BATCH_FLAGS {
self.fragment.columns[DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + i][row_idx] = ZERO;
}
let bit6 = self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + 6][row_idx];
let bit5 = self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + 5][row_idx];
let bit4 = self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + 4][row_idx];
self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET][row_idx] =
bit6 * (ONE - bit5) * bit4;
self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + 1][row_idx] =
bit6 * bit5;
}
pub fn populate_stack_trace_columns(&mut self, row_idx: usize) {
use miden_air::trace::STACK_TRACE_WIDTH;
if let Some(stack_rows) = self.stack_rows {
for (i, &value) in stack_rows.iter().enumerate() {
self.fragment.columns[STACK_TRACE_OFFSET + i][row_idx] = value;
}
}
let mut new_stack_rows = [ZERO; STACK_TRACE_WIDTH];
for i in STACK_TOP_RANGE {
new_stack_rows[STACK_TOP_OFFSET + i] = self.get(i);
}
new_stack_rows[B0_COL_IDX] = Felt::new(self.context.state.stack.stack_depth() as u64); new_stack_rows[B1_COL_IDX] = self.context.state.stack.overflow_addr(); new_stack_rows[H0_COL_IDX] = self.context.state.stack.overflow_helper();
self.stack_rows = Some(new_stack_rows);
}
}