use alloc::{collections::BTreeMap, vec::Vec};
use miden_air::trace::chiplets::memory::{
Selectors, MEMORY_COPY_READ, MEMORY_INIT_READ, MEMORY_WRITE,
};
use super::{Felt, Word, INIT_MEM_VALUE};
#[derive(Default)]
pub struct MemorySegmentTrace(BTreeMap<u32, Vec<MemorySegmentAccess>>);
impl MemorySegmentTrace {
pub fn get_value(&self, addr: u32) -> Option<Word> {
match self.0.get(&addr) {
Some(addr_trace) => addr_trace.last().map(|access| access.value()),
None => None,
}
}
pub fn get_state_at(&self, clk: u32) -> Vec<(u64, Word)> {
let mut result: Vec<(u64, Word)> = Vec::new();
if clk == 0 {
return result;
}
let search_clk = (clk - 1) as u64;
for (&addr, addr_trace) in self.0.iter() {
match addr_trace.binary_search_by(|access| access.clk().as_int().cmp(&search_clk)) {
Ok(i) => result.push((addr.into(), addr_trace[i].value())),
Err(i) => {
if i > 0 {
result.push((addr.into(), addr_trace[i - 1].value()));
}
}
}
}
result
}
pub fn read(&mut self, addr: u32, clk: Felt) -> Word {
self.0
.entry(addr)
.and_modify(|addr_trace| {
let last_value = addr_trace.last().expect("empty address trace").value();
let access = MemorySegmentAccess::new(clk, MemoryOperation::CopyRead, last_value);
addr_trace.push(access);
})
.or_insert_with(|| {
let access =
MemorySegmentAccess::new(clk, MemoryOperation::InitRead, INIT_MEM_VALUE);
vec![access]
})
.last()
.expect("empty address trace")
.value()
}
pub fn write(&mut self, addr: u32, clk: Felt, value: Word) {
let access = MemorySegmentAccess::new(clk, MemoryOperation::Write, value);
self.0
.entry(addr)
.and_modify(|addr_trace| addr_trace.push(access))
.or_insert_with(|| vec![access]);
}
pub(super) fn inner(&self) -> &BTreeMap<u32, Vec<MemorySegmentAccess>> {
&self.0
}
pub(super) fn into_inner(self) -> BTreeMap<u32, Vec<MemorySegmentAccess>> {
self.0
}
#[cfg(test)]
pub fn size(&self) -> usize {
self.0.len()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MemoryOperation {
InitRead,
CopyRead,
Write,
}
#[derive(Copy, Debug, Clone)]
pub struct MemorySegmentAccess {
clk: Felt,
op: MemoryOperation,
value: Word,
}
impl MemorySegmentAccess {
fn new(clk: Felt, op: MemoryOperation, value: Word) -> Self {
Self { clk, op, value }
}
pub(super) fn clk(&self) -> Felt {
self.clk
}
pub(super) fn op_selectors(&self) -> Selectors {
match self.op {
MemoryOperation::InitRead => MEMORY_INIT_READ,
MemoryOperation::CopyRead => MEMORY_COPY_READ,
MemoryOperation::Write => MEMORY_WRITE,
}
}
pub(super) fn value(&self) -> Word {
self.value
}
}