Skip to content

Commit e885ec0

Browse files
feat: access adapters (#1614)
closes INT-3839 --------- Co-authored-by: Ayush Shukla <[email protected]>
1 parent ae9635c commit e885ec0

File tree

38 files changed

+453
-136
lines changed

38 files changed

+453
-136
lines changed

crates/vm/src/arch/execution.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use openvm_instructions::{
66
};
77
use openvm_stark_backend::{
88
interaction::{BusIndex, InteractionBuilder, PermutationCheckBus},
9-
p3_field::{Field, FieldAlgebra, PrimeField32},
9+
p3_field::{FieldAlgebra, PrimeField32},
1010
};
1111
use serde::{Deserialize, Serialize};
1212
use thiserror::Error;
@@ -86,10 +86,10 @@ pub struct VmStateMut<'a, MEM, CTX> {
8686
pub ctx: &'a mut CTX,
8787
}
8888

89-
impl<CTX> VmStateMut<'_, TracingMemory, CTX> {
89+
impl<F: PrimeField32, CTX> VmStateMut<'_, TracingMemory<F>, CTX> {
9090
// TODO: store as u32 directly
9191
#[inline(always)]
92-
pub fn ins_start<F: Field>(&self, from_state: &mut ExecutionState<F>) {
92+
pub fn ins_start(&self, from_state: &mut ExecutionState<F>) {
9393
from_state.pc = F::from_canonical_u32(*self.pc);
9494
from_state.timestamp = F::from_canonical_u32(self.memory.timestamp);
9595
}

crates/vm/src/arch/integration_api.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ pub struct AdapterAirContext<T, I: VmAdapterInterface<T>> {
224224
pub trait SingleTraceStep<F, CTX> {
225225
fn execute(
226226
&mut self,
227-
state: VmStateMut<TracingMemory, CTX>,
227+
state: VmStateMut<TracingMemory<F>, CTX>,
228228
instruction: &Instruction<F>,
229229
row_slice: &mut [F],
230230
) -> Result<()>;
@@ -391,18 +391,18 @@ pub trait AdapterTraceStep<F, CTX> {
391391
where
392392
Self: 'a;
393393

394-
fn start(pc: u32, memory: &TracingMemory, adapter_row: &mut [F]);
394+
fn start(pc: u32, memory: &TracingMemory<F>, adapter_row: &mut [F]);
395395

396396
fn read(
397397
&self,
398-
memory: &mut TracingMemory,
398+
memory: &mut TracingMemory<F>,
399399
instruction: &Instruction<F>,
400400
adapter_row: &mut [F],
401401
) -> Self::ReadData;
402402

403403
fn write(
404404
&self,
405-
memory: &mut TracingMemory,
405+
memory: &mut TracingMemory<F>,
406406
instruction: &Instruction<F>,
407407
adapter_row: &mut [F],
408408
data: &Self::WriteData,

crates/vm/src/system/memory/adapter/mod.rs

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{borrow::BorrowMut, cmp::max, sync::Arc};
1+
use std::{borrow::BorrowMut, cmp::max, io::Cursor, sync::Arc};
22

33
pub use air::*;
44
pub use columns::*;
@@ -145,6 +145,39 @@ impl<F> AccessAdapterInventory<F> {
145145
None
146146
}
147147
}
148+
149+
pub(crate) fn execute_split(
150+
&mut self,
151+
address: MemoryAddress<u32, u32>,
152+
values: &[F],
153+
timestamp: u32,
154+
row_slice: &mut [F],
155+
) where
156+
F: PrimeField32,
157+
{
158+
let index = get_chip_index(values.len());
159+
self.chips[index].execute_split(address, values, timestamp, row_slice);
160+
}
161+
162+
pub(crate) fn execute_merge(
163+
&mut self,
164+
address: MemoryAddress<u32, u32>,
165+
values: &[F],
166+
left_timestamp: u32,
167+
right_timestamp: u32,
168+
row_slice: &mut [F],
169+
) where
170+
F: PrimeField32,
171+
{
172+
let index = get_chip_index(values.len());
173+
self.chips[index].execute_merge(
174+
address,
175+
values,
176+
left_timestamp,
177+
right_timestamp,
178+
row_slice,
179+
);
180+
}
148181
}
149182

150183
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -173,6 +206,25 @@ pub trait GenericAccessAdapterChipTrait<F> {
173206
fn generate_trace(self) -> RowMajorMatrix<F>
174207
where
175208
F: PrimeField32;
209+
210+
fn execute_split(
211+
&mut self,
212+
address: MemoryAddress<u32, u32>,
213+
values: &[F],
214+
timestamp: u32,
215+
row_slice: &mut [F],
216+
) where
217+
F: PrimeField32;
218+
219+
fn execute_merge(
220+
&mut self,
221+
address: MemoryAddress<u32, u32>,
222+
values: &[F],
223+
left_timestamp: u32,
224+
right_timestamp: u32,
225+
row_slice: &mut [F],
226+
) where
227+
F: PrimeField32;
176228
}
177229

178230
#[derive(Chip, ChipUsageGetter)]
@@ -216,6 +268,7 @@ impl<F> GenericAccessAdapterChip<F> {
216268
}
217269
}
218270
}
271+
219272
pub struct AccessAdapterChip<F, const N: usize> {
220273
air: AccessAdapterAir<N>,
221274
range_checker: SharedVariableRangeCheckerChip,
@@ -294,6 +347,72 @@ impl<F, const N: usize> GenericAccessAdapterChipTrait<F> for AccessAdapterChip<F
294347
});
295348
RowMajorMatrix::new(values, width)
296349
}
350+
351+
fn execute_split(
352+
&mut self,
353+
address: MemoryAddress<u32, u32>,
354+
values: &[F],
355+
timestamp: u32,
356+
row_slice: &mut [F],
357+
) where
358+
F: PrimeField32,
359+
{
360+
let row: &mut AccessAdapterCols<F, N> = row_slice.borrow_mut();
361+
row.is_valid = F::ONE;
362+
row.is_split = F::ONE;
363+
row.address = MemoryAddress::new(
364+
F::from_canonical_u32(address.address_space),
365+
F::from_canonical_u32(address.pointer),
366+
);
367+
let timestamp = F::from_canonical_u32(timestamp);
368+
row.left_timestamp = timestamp;
369+
row.right_timestamp = timestamp;
370+
row.is_right_larger = F::ZERO;
371+
debug_assert_eq!(
372+
values.len(),
373+
N,
374+
"Input values slice length must match the access adapter type"
375+
);
376+
377+
// SAFETY: `values` slice is asserted to have length N. `row.values` is an array of length
378+
// N. Pointers are valid and regions do not overlap because exactly one of them is a
379+
// part of the trace.
380+
unsafe {
381+
std::ptr::copy_nonoverlapping(values.as_ptr(), row.values.as_mut_ptr(), N);
382+
}
383+
}
384+
385+
fn execute_merge(
386+
&mut self,
387+
address: MemoryAddress<u32, u32>,
388+
values: &[F],
389+
left_timestamp: u32,
390+
right_timestamp: u32,
391+
row_slice: &mut [F],
392+
) where
393+
F: PrimeField32,
394+
{
395+
let row: &mut AccessAdapterCols<F, N> = row_slice.borrow_mut();
396+
row.is_valid = F::ONE;
397+
row.is_split = F::ZERO;
398+
row.address = MemoryAddress::new(
399+
F::from_canonical_u32(address.address_space),
400+
F::from_canonical_u32(address.pointer),
401+
);
402+
row.left_timestamp = F::from_canonical_u32(left_timestamp);
403+
row.right_timestamp = F::from_canonical_u32(right_timestamp);
404+
debug_assert_eq!(
405+
values.len(),
406+
N,
407+
"Input values slice length must match the access adapter type"
408+
);
409+
// SAFETY: `values` slice is asserted to have length N. `row.values` is an array of length
410+
// N. Pointers are valid and regions do not overlap because exactly one of them is a
411+
// part of the trace.
412+
unsafe {
413+
std::ptr::copy_nonoverlapping(values.as_ptr(), row.values.as_mut_ptr(), N);
414+
}
415+
}
297416
}
298417

299418
impl<SC: StarkGenericConfig, const N: usize> Chip<SC> for AccessAdapterChip<Val<SC>, N>
@@ -328,3 +447,42 @@ impl<F, const N: usize> ChipUsageGetter for AccessAdapterChip<F, N> {
328447
fn air_name(n: usize) -> String {
329448
format!("AccessAdapter<{}>", n)
330449
}
450+
451+
#[inline(always)]
452+
pub fn get_chip_index(block_size: usize) -> usize {
453+
assert!(
454+
block_size.is_power_of_two() && block_size >= 2,
455+
"Invalid block size {} for split operation",
456+
block_size
457+
);
458+
let index = block_size.trailing_zeros() - 1;
459+
index as usize
460+
}
461+
462+
pub struct AdapterInventoryTraceCursor<F> {
463+
// [AG] TODO: replace with a pre-allocated space
464+
cursors: Vec<Cursor<Vec<F>>>,
465+
widths: Vec<usize>,
466+
}
467+
468+
impl<F: PrimeField32> AdapterInventoryTraceCursor<F> {
469+
pub fn new(as_cnt: usize) -> Self {
470+
let cursors = vec![Cursor::new(Vec::new()); as_cnt];
471+
let widths = vec![
472+
size_of::<AccessAdapterCols<u8, 2>>(),
473+
size_of::<AccessAdapterCols<u8, 4>>(),
474+
size_of::<AccessAdapterCols<u8, 8>>(),
475+
size_of::<AccessAdapterCols<u8, 16>>(),
476+
size_of::<AccessAdapterCols<u8, 32>>(),
477+
];
478+
Self { cursors, widths }
479+
}
480+
481+
pub fn get_row_slice(&mut self, block_size: usize) -> &mut [F] {
482+
let index = get_chip_index(block_size);
483+
let begin = self.cursors[index].position() as usize;
484+
let end = begin + self.widths[index];
485+
self.cursors[index].set_position(end as u64);
486+
&mut self.cursors[index].get_mut()[begin..end]
487+
}
488+
}

crates/vm/src/system/memory/controller/mod.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ pub struct MemoryController<F> {
101101
// Store separately to avoid smart pointer reference each time
102102
range_checker_bus: VariableRangeCheckerBus,
103103
// addr_space -> Memory data structure
104-
pub(crate) memory: TracingMemory,
104+
pub(crate) memory: TracingMemory<F>,
105105
/// A reference to the `OfflineMemory`. Will be populated after `finalize()`.
106106
pub offline_memory: Arc<Mutex<OfflineMemory<F>>>,
107107
pub access_adapters: AccessAdapterInventory<F>,
@@ -246,7 +246,7 @@ impl<F: PrimeField32> MemoryController<F> {
246246
range_checker.clone(),
247247
),
248248
},
249-
memory: TracingMemory::new(&mem_config),
249+
memory: TracingMemory::new(&mem_config, range_checker.clone(), memory_bus),
250250
offline_memory: Arc::new(Mutex::new(OfflineMemory::new(
251251
initial_memory,
252252
1,
@@ -297,8 +297,8 @@ impl<F: PrimeField32> MemoryController<F> {
297297
memory_bus,
298298
mem_config,
299299
interface_chip,
300-
memory: TracingMemory::new(&mem_config), /* it is expected that the memory will be
301-
* set later */
300+
memory: TracingMemory::new(&mem_config, range_checker.clone(), memory_bus), /* it is expected that the memory will be
301+
* set later */
302302
offline_memory: Arc::new(Mutex::new(OfflineMemory::new(
303303
AddressMap::from_mem_config(&mem_config),
304304
CHUNK,
@@ -355,7 +355,12 @@ impl<F: PrimeField32> MemoryController<F> {
355355
let mut offline_memory = self.offline_memory.lock().unwrap();
356356
offline_memory.set_initial_memory(memory.clone(), self.mem_config);
357357

358-
self.memory = TracingMemory::from_image(memory.clone(), self.mem_config.access_capacity);
358+
self.memory = TracingMemory::new(
359+
&self.mem_config,
360+
self.range_checker.clone(),
361+
self.memory_bus,
362+
)
363+
.with_image(memory.clone(), self.mem_config.access_capacity);
359364

360365
match &mut self.interface_chip {
361366
MemoryInterface::Volatile { .. } => {

0 commit comments

Comments
 (0)