openvm_circuit/system/memory/
mod.rs1use std::sync::Arc;
2
3use openvm_circuit_primitives::{is_less_than::IsLtSubAir, var_range::VariableRangeCheckerBus};
4use openvm_circuit_primitives_derive::AlignedBorrow;
5use openvm_stark_backend::{
6 config::{StarkGenericConfig, Val},
7 interaction::PermutationCheckBus,
8 p3_field::Field,
9 p3_util::{log2_ceil_usize, log2_strict_usize},
10 AirRef,
11};
12
13pub mod adapter;
14mod controller;
15pub mod merkle;
16pub mod offline_checker;
17pub mod online;
18pub mod persistent;
19#[cfg(test)]
20mod tests;
21pub mod volatile;
22
23pub use controller::*;
24pub use online::{Address, AddressMap, INITIAL_TIMESTAMP};
25
26use crate::{
27 arch::{MemoryConfig, ADDR_SPACE_OFFSET},
28 system::memory::{
29 adapter::AccessAdapterAir, dimensions::MemoryDimensions, interface::MemoryInterfaceAirs,
30 merkle::MemoryMerkleAir, offline_checker::MemoryBridge, persistent::PersistentBoundaryAir,
31 volatile::VolatileBoundaryAir,
32 },
33};
34
35pub const POINTER_MAX_BITS: usize = 29;
38
39#[derive(PartialEq, Copy, Clone, Debug, Eq)]
40pub enum OpType {
41 Read = 0,
42 Write = 1,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq, AlignedBorrow)]
48#[repr(C)]
49pub struct MemoryAddress<S, T> {
50 pub address_space: S,
51 pub pointer: T,
52}
53
54impl<S, T> MemoryAddress<S, T> {
55 pub fn new(address_space: S, pointer: T) -> Self {
56 Self {
57 address_space,
58 pointer,
59 }
60 }
61
62 pub fn from<T1, T2>(a: MemoryAddress<T1, T2>) -> Self
63 where
64 T1: Into<S>,
65 T2: Into<T>,
66 {
67 Self {
68 address_space: a.address_space.into(),
69 pointer: a.pointer.into(),
70 }
71 }
72}
73
74#[derive(Clone)]
75pub struct MemoryAirInventory<SC: StarkGenericConfig> {
76 pub bridge: MemoryBridge,
77 pub interface: MemoryInterfaceAirs,
78 pub access_adapters: Vec<AirRef<SC>>,
79}
80
81impl<SC: StarkGenericConfig> MemoryAirInventory<SC> {
82 pub fn new(
83 bridge: MemoryBridge,
84 mem_config: &MemoryConfig,
85 range_bus: VariableRangeCheckerBus,
86 merkle_compression_buses: Option<(PermutationCheckBus, PermutationCheckBus)>,
87 ) -> Self {
88 let memory_bus = bridge.memory_bus();
89 let interface = if let Some((merkle_bus, compression_bus)) = merkle_compression_buses {
90 let memory_dims = MemoryDimensions {
92 addr_space_height: mem_config.addr_space_height,
93 address_height: mem_config.pointer_max_bits - log2_strict_usize(CHUNK),
94 };
95 let boundary = PersistentBoundaryAir::<CHUNK> {
96 memory_dims,
97 memory_bus,
98 merkle_bus,
99 compression_bus,
100 };
101 let merkle = MemoryMerkleAir::<CHUNK> {
102 memory_dimensions: memory_dims,
103 merkle_bus,
104 compression_bus,
105 };
106 MemoryInterfaceAirs::Persistent { boundary, merkle }
107 } else {
108 let addr_space_height = mem_config.addr_space_height;
110 assert!(addr_space_height < Val::<SC>::bits() - 2);
111 let addr_space_max_bits =
112 log2_ceil_usize((ADDR_SPACE_OFFSET + 2u32.pow(addr_space_height as u32)) as usize);
113 let boundary = VolatileBoundaryAir::new(
114 memory_bus,
115 addr_space_max_bits,
116 mem_config.pointer_max_bits,
117 range_bus,
118 );
119 MemoryInterfaceAirs::Volatile { boundary }
120 };
121 let lt_air = IsLtSubAir::new(range_bus, mem_config.timestamp_max_bits);
123 let maan = mem_config.max_access_adapter_n;
124 assert!(matches!(maan, 2 | 4 | 8 | 16 | 32));
125 let access_adapters: Vec<AirRef<SC>> = [
126 Arc::new(AccessAdapterAir::<2> { memory_bus, lt_air }) as AirRef<SC>,
127 Arc::new(AccessAdapterAir::<4> { memory_bus, lt_air }) as AirRef<SC>,
128 Arc::new(AccessAdapterAir::<8> { memory_bus, lt_air }) as AirRef<SC>,
129 Arc::new(AccessAdapterAir::<16> { memory_bus, lt_air }) as AirRef<SC>,
130 Arc::new(AccessAdapterAir::<32> { memory_bus, lt_air }) as AirRef<SC>,
131 ]
132 .into_iter()
133 .take(log2_strict_usize(maan))
134 .collect();
135
136 Self {
137 bridge,
138 interface,
139 access_adapters,
140 }
141 }
142
143 pub fn into_airs(self) -> Vec<AirRef<SC>> {
145 let mut airs: Vec<AirRef<SC>> = Vec::new();
146 match self.interface {
147 MemoryInterfaceAirs::Volatile { boundary } => {
148 airs.push(Arc::new(boundary));
149 }
150 MemoryInterfaceAirs::Persistent { boundary, merkle } => {
151 airs.push(Arc::new(boundary));
152 airs.push(Arc::new(merkle));
153 }
154 }
155 airs.extend(self.access_adapters);
156 airs
157 }
158}
159
160pub fn num_memory_airs(is_persistent: bool, max_access_adapter_n: usize) -> usize {
163 1 + usize::from(is_persistent) + log2_strict_usize(max_access_adapter_n)
165}