use alloc::{collections::BTreeMap, vec};
use miden_air::trace::chiplets::KERNEL_ROM_TRACE_WIDTH;
use miden_core::field::PrimeCharacteristicRing;
use super::{ChipletTraceFragment, Felt, Kernel, Word as Digest, ZERO};
use crate::errors::OperationError;
#[cfg(test)]
mod tests;
type ProcHashBytes = [u8; 32];
#[derive(Debug)]
pub struct KernelRom {
access_map: BTreeMap<ProcHashBytes, ProcAccessInfo>,
kernel: Kernel,
}
impl KernelRom {
pub fn new(kernel: Kernel) -> Self {
let mut access_map = BTreeMap::new();
for &proc_hash in kernel.proc_hashes() {
access_map.insert(proc_hash.into(), ProcAccessInfo::new(proc_hash));
}
Self { access_map, kernel }
}
pub fn trace_len(&self) -> usize {
self.access_map.len()
}
pub fn access_proc(&mut self, proc_root: Digest) -> Result<(), OperationError> {
let proc_hash_bytes: ProcHashBytes = proc_root.into();
let access_info = self
.access_map
.get_mut(&proc_hash_bytes)
.ok_or(OperationError::SyscallTargetNotInKernel { proc_root })?;
access_info.num_accesses += 1;
Ok(())
}
pub fn fill_trace(self, trace: &mut ChipletTraceFragment) {
debug_assert_eq!(
KERNEL_ROM_TRACE_WIDTH,
trace.width(),
"inconsistent trace fragment width"
);
let mut values = vec![ZERO; self.access_map.len() * KERNEL_ROM_TRACE_WIDTH];
let (rows, _) = values.as_chunks_mut::<KERNEL_ROM_TRACE_WIDTH>();
for (row, access_info) in rows.iter_mut().zip(self.access_map.values()) {
row[0] = Felt::from_u64(access_info.num_accesses as u64);
row[1] = access_info.proc_hash[0];
row[2] = access_info.proc_hash[1];
row[3] = access_info.proc_hash[2];
row[4] = access_info.proc_hash[3];
}
trace.copy_rows_from(&values);
}
pub const fn kernel(&self) -> &Kernel {
&self.kernel
}
}
#[derive(Debug)]
struct ProcAccessInfo {
proc_hash: Digest,
num_accesses: usize,
}
impl ProcAccessInfo {
pub fn new(proc_hash: Digest) -> Self {
Self { proc_hash, num_accesses: 0 }
}
}