use alloc::collections::BTreeMap;
use miden_air::trace::{RowIndex, chiplets::KERNEL_ROM_TRACE_WIDTH};
use miden_core::field::PrimeCharacteristicRing;
use super::{Felt, Kernel, TraceFragment, Word as Digest};
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 TraceFragment) {
debug_assert_eq!(
KERNEL_ROM_TRACE_WIDTH,
trace.width(),
"inconsistent trace fragment width"
);
let mut row = RowIndex::from(0);
for access_info in self.access_map.values() {
let multiplicity = Felt::from_u64(access_info.num_accesses as u64);
trace.set(row, 0, multiplicity);
trace.set(row, 1, access_info.proc_hash[0]);
trace.set(row, 2, access_info.proc_hash[1]);
trace.set(row, 3, access_info.proc_hash[2]);
trace.set(row, 4, access_info.proc_hash[3]);
row += 1_u32;
}
}
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 }
}
}