openvm_circuit/system/memory/offline_checker/
bus.rs

1use std::iter;
2
3use openvm_stark_backend::{
4    interaction::{BusIndex, InteractionBuilder, PermutationCheckBus},
5    p3_field::FieldAlgebra,
6};
7
8use crate::system::memory::MemoryAddress;
9
10/// Represents a memory bus identified by a unique bus index (`usize`).
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub struct MemoryBus {
13    pub inner: PermutationCheckBus,
14}
15
16impl MemoryBus {
17    pub const fn new(index: BusIndex) -> Self {
18        Self {
19            inner: PermutationCheckBus::new(index),
20        }
21    }
22}
23
24impl MemoryBus {
25    #[inline(always)]
26    pub fn index(&self) -> BusIndex {
27        self.inner.index
28    }
29
30    /// Prepares a write operation through the memory bus.
31    pub fn send<T: Clone>(
32        &self,
33        address: MemoryAddress<impl Into<T>, impl Into<T>>,
34        data: Vec<impl Into<T>>,
35        timestamp: impl Into<T>,
36    ) -> MemoryBusInteraction<T> {
37        self.push(true, address, data, timestamp)
38    }
39
40    /// Prepares a read operation through the memory bus.
41    pub fn receive<T: Clone>(
42        &self,
43        address: MemoryAddress<impl Into<T>, impl Into<T>>,
44        data: Vec<impl Into<T>>,
45        timestamp: impl Into<T>,
46    ) -> MemoryBusInteraction<T> {
47        self.push(false, address, data, timestamp)
48    }
49
50    /// Prepares a memory operation (read or write) through the memory bus.
51    fn push<T: Clone>(
52        &self,
53        is_send: bool,
54        address: MemoryAddress<impl Into<T>, impl Into<T>>,
55        data: Vec<impl Into<T>>,
56        timestamp: impl Into<T>,
57    ) -> MemoryBusInteraction<T> {
58        MemoryBusInteraction {
59            bus: self.inner,
60            is_send,
61            address: MemoryAddress::new(address.address_space.into(), address.pointer.into()),
62            data: data.into_iter().map(|item| item.into()).collect(),
63            timestamp: timestamp.into(),
64        }
65    }
66}
67
68#[derive(Clone, Debug)]
69pub struct MemoryBusInteraction<T> {
70    pub bus: PermutationCheckBus,
71    pub is_send: bool,
72    pub address: MemoryAddress<T, T>,
73    pub data: Vec<T>,
74    pub timestamp: T,
75}
76
77impl<T: FieldAlgebra> MemoryBusInteraction<T> {
78    /// Finalizes and sends/receives the memory operation with the specified direction over the bus.
79    ///
80    /// A read corresponds to a receive, and a write corresponds to a send.
81    ///
82    /// The parameter `direction` can be -1, 0, or 1. A value of 1 means perform the same action
83    /// (send/receive), a value of -1 reverses the action, and a value of 0 means disabled.
84    ///
85    /// Caller must constrain `direction` to be in {-1, 0, 1}.
86    pub fn eval<AB>(self, builder: &mut AB, direction: impl Into<AB::Expr>)
87    where
88        AB: InteractionBuilder<Expr = T>,
89    {
90        let fields = iter::empty()
91            .chain(iter::once(self.address.address_space))
92            .chain(iter::once(self.address.pointer))
93            .chain(self.data)
94            .chain(iter::once(self.timestamp));
95
96        if self.is_send {
97            self.bus.interact(builder, fields, direction);
98        } else {
99            self.bus
100                .interact(builder, fields, AB::Expr::NEG_ONE * direction.into());
101        }
102    }
103}