Skip to content

Commit 4803ecd

Browse files
committed
fix: add memcpy to toolchain
1 parent c1ef659 commit 4803ecd

File tree

10 files changed

+503
-464
lines changed

10 files changed

+503
-464
lines changed

Cargo.lock

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ openvm-ecc-sw-macros = { path = "extensions/ecc/sw-macros", default-features = f
169169
openvm-pairing-circuit = { path = "extensions/pairing/circuit", default-features = false }
170170
openvm-pairing-transpiler = { path = "extensions/pairing/transpiler", default-features = false }
171171
openvm-pairing-guest = { path = "extensions/pairing/guest", default-features = false }
172+
openvm-memcpy-circuit = { path = "extensions/memcpy/circuit", default-features = false }
173+
openvm-memcpy-transpiler = { path = "extensions/memcpy/transpiler", default-features = false }
172174
openvm-verify-stark = { path = "guest-libs/verify_stark", default-features = false }
173175

174176
# Benchmarking

benchmarks/execute/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ openvm-pairing-guest.workspace = true
2424
openvm-pairing-transpiler.workspace = true
2525
openvm-keccak256-circuit.workspace = true
2626
openvm-keccak256-transpiler.workspace = true
27+
openvm-memcpy-circuit.workspace = true
28+
openvm-memcpy-transpiler.workspace = true
2729
openvm-rv32im-circuit.workspace = true
2830
openvm-rv32im-transpiler.workspace = true
2931
openvm-sha256-circuit.workspace = true

benchmarks/execute/benches/execute.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ use openvm_ecc_circuit::{EccCpuProverExt, WeierstrassExtension, WeierstrassExten
2828
use openvm_ecc_transpiler::EccTranspilerExtension;
2929
use openvm_keccak256_circuit::{Keccak256, Keccak256CpuProverExt, Keccak256Executor};
3030
use openvm_keccak256_transpiler::Keccak256TranspilerExtension;
31+
use openvm_memcpy_circuit::{Memcpy, MemcpyCpuProverExt, MemcpyExecutor};
32+
use openvm_memcpy_transpiler::MemcpyTranspilerExtension;
3133
use openvm_native_circuit::{NativeConfig, NativeCpuBuilder, NATIVE_MAX_TRACE_HEIGHTS};
3234
use openvm_pairing_circuit::{
3335
PairingCurve, PairingExtension, PairingExtensionExecutor, PairingProverExt,
@@ -94,6 +96,8 @@ pub struct ExecuteConfig {
9496
#[extension]
9597
pub keccak: Keccak256,
9698
#[extension]
99+
pub memcpy: Memcpy,
100+
#[extension]
97101
pub sha256: Sha256,
98102
#[extension]
99103
pub modular: ModularExtension,
@@ -115,6 +119,7 @@ impl Default for ExecuteConfig {
115119
io: Rv32Io,
116120
bigint: Int256::default(),
117121
keccak: Keccak256,
122+
memcpy: Memcpy,
118123
sha256: Sha256,
119124
modular: ModularExtension::new(vec![
120125
bn_config.modulus.clone(),
@@ -175,6 +180,7 @@ where
175180
&config.keccak,
176181
inventory,
177182
)?;
183+
VmProverExtension::<E, _, _>::extend_prover(&MemcpyCpuProverExt, &config.memcpy, inventory)?;
178184
VmProverExtension::<E, _, _>::extend_prover(&Sha2CpuProverExt, &config.sha256, inventory)?;
179185
VmProverExtension::<E, _, _>::extend_prover(
180186
&AlgebraCpuProverExt,
@@ -203,6 +209,7 @@ fn create_default_transpiler() -> Transpiler<BabyBear> {
203209
.with_extension(Rv32MTranspilerExtension)
204210
.with_extension(Int256TranspilerExtension)
205211
.with_extension(Keccak256TranspilerExtension)
212+
.with_extension(MemcpyTranspilerExtension)
206213
.with_extension(Sha256TranspilerExtension)
207214
.with_extension(ModularTranspilerExtension)
208215
.with_extension(Fp2TranspilerExtension)

crates/sdk/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ openvm-ecc-circuit = { workspace = true }
1818
openvm-ecc-transpiler = { workspace = true }
1919
openvm-keccak256-circuit = { workspace = true }
2020
openvm-keccak256-transpiler = { workspace = true }
21+
openvm-memcpy-circuit = { workspace = true }
22+
openvm-memcpy-transpiler = { workspace = true }
2123
openvm-sha256-circuit = { workspace = true }
2224
openvm-sha256-transpiler = { workspace = true }
2325
openvm-pairing-circuit = { workspace = true }

crates/sdk/src/config/global.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ use openvm_rv32im_circuit::{
3333
use openvm_rv32im_transpiler::{
3434
Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension,
3535
};
36+
use openvm_memcpy_circuit::{Memcpy, MemcpyCpuProverExt, MemcpyExecutor};
37+
use openvm_memcpy_transpiler::MemcpyTranspilerExtension;
3638
use openvm_sha256_circuit::{Sha256, Sha256Executor, Sha2CpuProverExt};
3739
use openvm_sha256_transpiler::Sha256TranspilerExtension;
3840
use openvm_stark_backend::{
@@ -63,6 +65,7 @@ pub struct SdkVmConfig {
6365
pub rv32i: Option<UnitStruct>,
6466
pub io: Option<UnitStruct>,
6567
pub keccak: Option<UnitStruct>,
68+
pub memcpy: Option<UnitStruct>,
6669
pub sha256: Option<UnitStruct>,
6770
pub native: Option<UnitStruct>,
6871
pub castf: Option<UnitStruct>,
@@ -100,6 +103,7 @@ impl SdkVmConfig {
100103
.rv32m(Default::default())
101104
.io(Default::default())
102105
.keccak(Default::default())
106+
.memcpy(Default::default())
103107
.sha256(Default::default())
104108
.bigint(Default::default())
105109
.modular(ModularExtension::new(vec![
@@ -181,6 +185,9 @@ impl TranspilerConfig<F> for SdkVmConfig {
181185
if self.keccak.is_some() {
182186
transpiler = transpiler.with_extension(Keccak256TranspilerExtension);
183187
}
188+
if self.memcpy.is_some() {
189+
transpiler = transpiler.with_extension(MemcpyTranspilerExtension);
190+
}
184191
if self.sha256.is_some() {
185192
transpiler = transpiler.with_extension(Sha256TranspilerExtension);
186193
}
@@ -251,6 +258,7 @@ impl SdkVmConfig {
251258
let rv32i = config.rv32i.map(|_| Rv32I);
252259
let io = config.io.map(|_| Rv32Io);
253260
let keccak = config.keccak.map(|_| Keccak256);
261+
let memcpy = config.memcpy.map(|_| Memcpy);
254262
let sha256 = config.sha256.map(|_| Sha256);
255263
let native = config.native.map(|_| Native);
256264
let castf = config.castf.map(|_| CastFExtension);
@@ -266,6 +274,7 @@ impl SdkVmConfig {
266274
rv32i,
267275
io,
268276
keccak,
277+
memcpy,
269278
sha256,
270279
native,
271280
castf,
@@ -297,6 +306,8 @@ pub struct SdkVmConfigInner {
297306
pub io: Option<Rv32Io>,
298307
#[extension(executor = "Keccak256Executor")]
299308
pub keccak: Option<Keccak256>,
309+
#[extension(executor = "MemcpyExecutor")]
310+
pub memcpy: Option<Memcpy>,
300311
#[extension(executor = "Sha256Executor")]
301312
pub sha256: Option<Sha256>,
302313
#[extension(executor = "NativeExecutor<F>")]
@@ -374,6 +385,9 @@ where
374385
if let Some(keccak) = &config.keccak {
375386
VmProverExtension::<E, _, _>::extend_prover(&Keccak256CpuProverExt, keccak, inventory)?;
376387
}
388+
if let Some(memcpy) = &config.memcpy {
389+
VmProverExtension::<E, _, _>::extend_prover(&MemcpyCpuProverExt, memcpy, inventory)?;
390+
}
377391
if let Some(sha256) = &config.sha256 {
378392
VmProverExtension::<E, _, _>::extend_prover(&Sha2CpuProverExt, sha256, inventory)?;
379393
}
@@ -485,6 +499,12 @@ impl From<Keccak256> for UnitStruct {
485499
}
486500
}
487501

502+
impl From<Memcpy> for UnitStruct {
503+
fn from(_: Memcpy) -> Self {
504+
UnitStruct {}
505+
}
506+
}
507+
488508
impl From<Sha256> for UnitStruct {
489509
fn from(_: Sha256) -> Self {
490510
UnitStruct {}
@@ -511,6 +531,7 @@ struct SdkVmConfigWithDefaultDeser {
511531
pub rv32i: Option<UnitStruct>,
512532
pub io: Option<UnitStruct>,
513533
pub keccak: Option<UnitStruct>,
534+
pub memcpy: Option<UnitStruct>,
514535
pub sha256: Option<UnitStruct>,
515536
pub native: Option<UnitStruct>,
516537
pub castf: Option<UnitStruct>,
@@ -530,6 +551,7 @@ impl From<SdkVmConfigWithDefaultDeser> for SdkVmConfig {
530551
rv32i: config.rv32i,
531552
io: config.io,
532553
keccak: config.keccak,
554+
memcpy: config.memcpy,
533555
sha256: config.sha256,
534556
native: config.native,
535557
castf: config.castf,

crates/toolchain/openvm/src/memcpy.s

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@
205205
.attribute 4, 16
206206
.attribute 5, "rv32im"
207207
.file "musl_memcpy.c"
208+
209+
# Define memcpy_loop macro for custom instruction (U-type)
210+
.macro memcpy_loop shift
211+
.word 0x72000000 | (\shift << 12) # opcode 0x72 + shift in immediate field (bits 12-31)
212+
.endm
208213
.globl memcpy
209214
.p2align 2
210215
.type memcpy,@function

extensions/memcpy/circuit/src/core.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ pub type MemcpyLoopChip<F> = VmChipWrapper<F, MemcpyLoopFiller>;
311311
#[derive(AlignedBytesBorrow, Clone)]
312312
#[repr(C)]
313313
struct MemcpyLoopPreCompute {
314-
a: u8,
314+
c: u8,
315315
}
316316

317317
impl<F, RA> PreflightExecutor<F, RA> for MemcpyLoopExecutor
@@ -328,9 +328,9 @@ where
328328
state: VmStateMut<F, TracingMemory, RA>,
329329
instruction: &Instruction<F>,
330330
) -> Result<(), ExecutionError> {
331-
let Instruction { opcode, a, .. } = instruction;
331+
let Instruction { opcode, c, .. } = instruction;
332332
debug_assert_eq!(*opcode, Rv32MemcpyOpcode::MEMCPY_LOOP.global_opcode());
333-
let shift = a.as_canonical_u32() as u8;
333+
let shift = c.as_canonical_u32() as u8;
334334
debug_assert!([0, 1, 2, 3].contains(&shift));
335335
let mut record = state.ctx.alloc(EmptyMultiRowLayout::default());
336336

@@ -600,7 +600,7 @@ unsafe fn execute_e12_impl<F: PrimeField32, CTX: E1ExecutionCtx>(
600600
pre_compute: &MemcpyLoopPreCompute,
601601
vm_state: &mut VmExecState<F, GuestMemory, CTX>,
602602
) {
603-
let shift = pre_compute.a;
603+
let shift = pre_compute.c;
604604
let (dest, source) = if shift == 0 {
605605
(
606606
vm_state.vm_read::<u8, 4>(RV32_REGISTER_AS, A3_REGISTER_PTR as u32),
@@ -700,12 +700,12 @@ impl MemcpyLoopExecutor {
700700
inst: &Instruction<F>,
701701
data: &mut MemcpyLoopPreCompute,
702702
) -> Result<(), StaticProgramError> {
703-
let Instruction { opcode, a, .. } = inst;
704-
let a_u32 = a.as_canonical_u32();
705-
if ![0, 1, 2, 3].contains(&a_u32) {
703+
let Instruction { opcode, c, .. } = inst;
704+
let c_u32 = c.as_canonical_u32();
705+
if ![0, 1, 2, 3].contains(&c_u32) {
706706
return Err(StaticProgramError::InvalidInstruction(pc));
707707
}
708-
*data = MemcpyLoopPreCompute { a: a_u32 as u8 };
708+
*data = MemcpyLoopPreCompute { c: c_u32 as u8 };
709709
assert_eq!(*opcode, Rv32MemcpyOpcode::MEMCPY_LOOP.global_opcode());
710710
Ok(())
711711
}

0 commit comments

Comments
 (0)