Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ profile.json.gz

# test fixtures
benchmarks/fixtures


crates/toolchain/tests/rv32im-test-vectors/tests/*
*.o
*.a
*.s
*.txt
riscv/*
78 changes: 77 additions & 1 deletion crates/vm/src/arch/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ pub const OPENVM_DEFAULT_INIT_FILE_NAME: &str = "openvm_init.rs";
const DEFAULT_U8_BLOCK_SIZE: usize = 4;
const DEFAULT_NATIVE_BLOCK_SIZE: usize = 1;

/// The constant block size used for memory accesses when access adapters are disabled.
/// All memory accesses for address spaces 1-3 must use this block size.
/// This is also the block size used by the Boundary AIR for memory bus interactions.
pub const CONST_BLOCK_SIZE: usize = 4;

/// Trait for generating a init.rs file that contains a call to moduli_init!,
/// complex_init!, sw_init! with the supported moduli and curves.
/// Should be implemented by all VM config structs.
Expand Down Expand Up @@ -183,6 +188,11 @@ pub struct MemoryConfig {
pub decomp: usize,
/// Maximum N AccessAdapter AIR to support.
pub max_access_adapter_n: usize,
/// Whether access adapters are enabled. When disabled, all memory accesses must be of the
/// standard block size (e.g., 4 for address spaces 1-3). This removes the need for access
/// adapter AIRs and simplifies the memory system.
#[new(value = "true")]
pub access_adapters_enabled: bool,
}

impl Default for MemoryConfig {
Expand All @@ -194,7 +204,15 @@ impl Default for MemoryConfig {
addr_spaces[RV32_MEMORY_AS as usize].num_cells = MAX_CELLS;
addr_spaces[PUBLIC_VALUES_AS as usize].num_cells = DEFAULT_MAX_NUM_PUBLIC_VALUES;
addr_spaces[NATIVE_AS as usize].num_cells = MAX_CELLS;
Self::new(3, addr_spaces, POINTER_MAX_BITS, 29, 17, 32)
Self {
addr_space_height: 3,
addr_spaces,
pointer_max_bits: POINTER_MAX_BITS,
timestamp_max_bits: 29,
decomp: 17,
max_access_adapter_n: 32,
access_adapters_enabled: true,
}
}
}

Expand Down Expand Up @@ -245,6 +263,36 @@ impl MemoryConfig {
.map(|addr_sp| log2_strict_usize(addr_sp.min_block_size) as u8)
.collect()
}

/// Returns true if the Native address space (AS 4) is used.
/// Native AS is considered "used" if it has any allocated cells.
pub fn is_native_as_used(&self) -> bool {
self.addr_spaces
.get(NATIVE_AS as usize)
.is_some_and(|config| config.num_cells > 0)
}

/// Disables access adapters. When disabled, all memory accesses for address spaces 1-3
/// must use the constant block size (4). Access adapters will only be used for
/// address space 4 (Native) if it is enabled.
pub fn without_access_adapters(mut self) -> Self {
self.access_adapters_enabled = false;
self
}

/// Enables access adapters. This is the default behavior.
pub fn with_access_adapters(mut self) -> Self {
self.access_adapters_enabled = true;
self
}

/// Automatically sets `access_adapters_enabled` based on whether Native AS is used.
/// If Native AS is not used, access adapters are disabled since all other address spaces
/// use a fixed block size of 4.
pub fn with_auto_access_adapters(mut self) -> Self {
self.access_adapters_enabled = self.is_native_as_used();
self
}
}

/// System-level configuration for the virtual machine. Contains all configuration parameters that
Expand Down Expand Up @@ -375,6 +423,7 @@ impl SystemConfig {
+ num_memory_airs(
self.continuation_enabled,
self.memory_config.max_access_adapter_n,
self.memory_config.access_adapters_enabled,
)
}

Expand All @@ -384,6 +433,33 @@ impl SystemConfig {
false => 1,
}
}

/// Disables access adapters. When disabled, all memory accesses for address spaces 1-3
/// must use the constant block size (4). This simplifies the memory system by removing
/// access adapter AIRs.
pub fn without_access_adapters(mut self) -> Self {
self.memory_config.access_adapters_enabled = false;
self
}

/// Enables access adapters. This is the default behavior.
pub fn with_access_adapters(mut self) -> Self {
self.memory_config.access_adapters_enabled = true;
self
}

/// Automatically sets `access_adapters_enabled` based on whether Native AS is used.
/// If Native AS is not used, access adapters are disabled since all other address spaces
/// use a fixed block size of 4.
pub fn with_auto_access_adapters(mut self) -> Self {
self.memory_config = self.memory_config.with_auto_access_adapters();
self
}

/// Returns true if access adapters are enabled.
pub fn access_adapters_enabled(&self) -> bool {
self.memory_config.access_adapters_enabled
}
}

impl Default for SystemConfig {
Expand Down
7 changes: 7 additions & 0 deletions crates/vm/src/arch/execution_mode/metered/memory_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ pub struct MemoryCtx<const PAGE_BITS: usize> {
pub boundary_idx: usize,
pub merkle_tree_index: Option<usize>,
pub adapter_offset: usize,
access_adapters_enabled: bool,
continuations_enabled: bool,
chunk: u32,
chunk_bits: u32,
Expand All @@ -128,6 +129,7 @@ impl<const PAGE_BITS: usize> MemoryCtx<PAGE_BITS> {
boundary_idx: config.memory_boundary_air_id(),
merkle_tree_index: config.memory_merkle_air_id(),
adapter_offset: config.access_adapter_air_id_offset(),
access_adapters_enabled: config.memory_config.access_adapters_enabled,
chunk,
chunk_bits,
memory_dimensions,
Expand Down Expand Up @@ -210,6 +212,11 @@ impl<const PAGE_BITS: usize> MemoryCtx<PAGE_BITS> {
size_bits: u32,
num: u32,
) {
// Skip if access adapters are disabled
if !self.access_adapters_enabled {
return;
}

debug_assert!((address_space as usize) < self.min_block_size_bits.len());

// SAFETY: address_space passed is usually a hardcoded constant or derived from an
Expand Down
7 changes: 7 additions & 0 deletions crates/vm/src/arch/execution_mode/metered_cost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ pub const DEFAULT_MAX_COST: u64 = DEFAULT_MAX_SEGMENTS * DEFAULT_SEGMENT_MAX_CEL
pub struct AccessAdapterCtx {
min_block_size_bits: Vec<u8>,
idx_offset: usize,
enabled: bool,
}

impl AccessAdapterCtx {
pub fn new(config: &SystemConfig) -> Self {
Self {
min_block_size_bits: config.memory_config.min_block_size_bits(),
idx_offset: config.access_adapter_air_id_offset(),
enabled: config.memory_config.access_adapters_enabled,
}
}

Expand All @@ -36,6 +38,11 @@ impl AccessAdapterCtx {
size_bits: u32,
widths: &[usize],
) {
// Skip if access adapters are disabled
if !self.enabled {
return;
}

debug_assert!((address_space as usize) < self.min_block_size_bits.len());

// SAFETY: address_space passed is usually a hardcoded constant or derived from an
Expand Down
35 changes: 20 additions & 15 deletions crates/vm/src/system/memory/adapter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,26 @@ impl<F: Clone + Send + Sync> AccessAdapterInventory<F> {
memory_bus: MemoryBus,
memory_config: MemoryConfig,
) -> Self {
let rc = range_checker;
let mb = memory_bus;
let tmb = memory_config.timestamp_max_bits;
let maan = memory_config.max_access_adapter_n;
assert!(matches!(maan, 2 | 4 | 8 | 16 | 32));
let chips: Vec<_> = [
Self::create_access_adapter_chip::<2>(rc.clone(), mb, tmb, maan),
Self::create_access_adapter_chip::<4>(rc.clone(), mb, tmb, maan),
Self::create_access_adapter_chip::<8>(rc.clone(), mb, tmb, maan),
Self::create_access_adapter_chip::<16>(rc.clone(), mb, tmb, maan),
Self::create_access_adapter_chip::<32>(rc.clone(), mb, tmb, maan),
]
.into_iter()
.flatten()
.collect();
// Only create adapter chips if access adapters are enabled
let chips: Vec<_> = if memory_config.access_adapters_enabled {
let rc = range_checker;
let mb = memory_bus;
let tmb = memory_config.timestamp_max_bits;
let maan = memory_config.max_access_adapter_n;
assert!(matches!(maan, 2 | 4 | 8 | 16 | 32));
[
Self::create_access_adapter_chip::<2>(rc.clone(), mb, tmb, maan),
Self::create_access_adapter_chip::<4>(rc.clone(), mb, tmb, maan),
Self::create_access_adapter_chip::<8>(rc.clone(), mb, tmb, maan),
Self::create_access_adapter_chip::<16>(rc.clone(), mb, tmb, maan),
Self::create_access_adapter_chip::<32>(rc.clone(), mb, tmb, maan),
]
.into_iter()
.flatten()
.collect()
} else {
Vec::new()
};
Self {
memory_config,
chips,
Expand Down
47 changes: 30 additions & 17 deletions crates/vm/src/system/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,20 +118,24 @@ impl<SC: StarkGenericConfig> MemoryAirInventory<SC> {
);
MemoryInterfaceAirs::Volatile { boundary }
};
// Memory access adapters
let lt_air = IsLtSubAir::new(range_bus, mem_config.timestamp_max_bits);
let maan = mem_config.max_access_adapter_n;
assert!(matches!(maan, 2 | 4 | 8 | 16 | 32));
let access_adapters: Vec<AirRef<SC>> = [
Arc::new(AccessAdapterAir::<2> { memory_bus, lt_air }) as AirRef<SC>,
Arc::new(AccessAdapterAir::<4> { memory_bus, lt_air }) as AirRef<SC>,
Arc::new(AccessAdapterAir::<8> { memory_bus, lt_air }) as AirRef<SC>,
Arc::new(AccessAdapterAir::<16> { memory_bus, lt_air }) as AirRef<SC>,
Arc::new(AccessAdapterAir::<32> { memory_bus, lt_air }) as AirRef<SC>,
]
.into_iter()
.take(log2_strict_usize(maan))
.collect();
// Memory access adapters - only create if enabled
let access_adapters: Vec<AirRef<SC>> = if mem_config.access_adapters_enabled {
let lt_air = IsLtSubAir::new(range_bus, mem_config.timestamp_max_bits);
let maan = mem_config.max_access_adapter_n;
assert!(matches!(maan, 2 | 4 | 8 | 16 | 32));
[
Arc::new(AccessAdapterAir::<2> { memory_bus, lt_air }) as AirRef<SC>,
Arc::new(AccessAdapterAir::<4> { memory_bus, lt_air }) as AirRef<SC>,
Arc::new(AccessAdapterAir::<8> { memory_bus, lt_air }) as AirRef<SC>,
Arc::new(AccessAdapterAir::<16> { memory_bus, lt_air }) as AirRef<SC>,
Arc::new(AccessAdapterAir::<32> { memory_bus, lt_air }) as AirRef<SC>,
]
.into_iter()
.take(log2_strict_usize(maan))
.collect()
} else {
Vec::new()
};

Self {
bridge,
Expand Down Expand Up @@ -159,7 +163,16 @@ impl<SC: StarkGenericConfig> MemoryAirInventory<SC> {

/// This is O(1) and returns the length of
/// [`MemoryAirInventory::into_airs`].
pub fn num_memory_airs(is_persistent: bool, max_access_adapter_n: usize) -> usize {
// boundary + { merkle if is_persistent } + access_adapters
1 + usize::from(is_persistent) + log2_strict_usize(max_access_adapter_n)
pub fn num_memory_airs(
is_persistent: bool,
max_access_adapter_n: usize,
access_adapters_enabled: bool,
) -> usize {
// boundary + { merkle if is_persistent } + access_adapters (if enabled)
let num_adapters = if access_adapters_enabled {
log2_strict_usize(max_access_adapter_n)
} else {
0
};
1 + usize::from(is_persistent) + num_adapters
}
33 changes: 22 additions & 11 deletions crates/vm/src/system/memory/persistent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use tracing::instrument;

use super::{merkle::SerialReceiver, online::INITIAL_TIMESTAMP, TimestampedValues};
use crate::{
arch::{hasher::Hasher, ADDR_SPACE_OFFSET},
arch::{hasher::Hasher, ADDR_SPACE_OFFSET, CONST_BLOCK_SIZE},
system::memory::{
dimensions::MemoryDimensions, offline_checker::MemoryBus, MemoryAddress, MemoryImage,
TimestampedEquipartition,
Expand Down Expand Up @@ -109,16 +109,27 @@ impl<const CHUNK: usize, AB: InteractionBuilder> Air<AB> for PersistentBoundaryA
local.expand_direction * local.expand_direction,
);

self.memory_bus
.send(
MemoryAddress::new(
local.address_space,
local.leaf_label * AB::F::from_canonical_usize(CHUNK),
),
local.values.to_vec(),
local.timestamp,
)
.eval(builder, local.expand_direction);
// Send memory bus interactions in CONST_BLOCK_SIZE chunks.
// This sends CHUNK/CONST_BLOCK_SIZE messages, each with CONST_BLOCK_SIZE values.
// For CHUNK=8 and CONST_BLOCK_SIZE=4, this sends 2 messages of 4 values each.
let base_pointer: AB::Expr = local.leaf_label.into() * AB::F::from_canonical_usize(CHUNK);
for block_idx in 0..(CHUNK / CONST_BLOCK_SIZE) {
let block_start = block_idx * CONST_BLOCK_SIZE;
let block_values: Vec<AB::Expr> = local.values[block_start..block_start + CONST_BLOCK_SIZE]
.iter()
.map(|&v| v.into())
.collect();
self.memory_bus
.send(
MemoryAddress::new(
local.address_space,
base_pointer.clone() + AB::F::from_canonical_usize(block_start),
),
block_values,
local.timestamp,
)
.eval(builder, local.expand_direction);
}
}
}

Expand Down
Loading
Loading