Skip to content

Commit

Permalink
Dummy Circuit - Basic ECALL (#369)
Browse files Browse the repository at this point in the history
_Issue #359 and #567_

* The `DummyInstruction` implements all the communications of a step:
state, fetch, registers, memory. But it does not verify calculations:
any value can be written out.

* Placeholder circuits for missing implementations, including unknown
ecalls.

* More precise register op assignment, see #570.

---------

Co-authored-by: Aurélien Nicolas <[email protected]>
  • Loading branch information
naure and Aurélien Nicolas authored Nov 8, 2024
1 parent a060e15 commit 8e00028
Show file tree
Hide file tree
Showing 12 changed files with 468 additions and 21 deletions.
2 changes: 1 addition & 1 deletion ceno_emul/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod vm_state;
pub use vm_state::VMState;

mod rv32im;
pub use rv32im::{DecodedInstruction, EmuContext, InsnCodes, InsnFormat, InsnKind};
pub use rv32im::{DecodedInstruction, EmuContext, InsnCategory, InsnCodes, InsnFormat, InsnKind};

mod elf;
pub use elf::Program;
Expand Down
3 changes: 3 additions & 0 deletions ceno_emul/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ pub struct Platform {
pub rom_end: Addr,
pub ram_start: Addr,
pub ram_end: Addr,
/// If true, ecall instructions are no-op instead of trap. Testing only.
pub unsafe_ecall_nop: bool,
}

pub const CENO_PLATFORM: Platform = Platform {
rom_start: 0x2000_0000,
rom_end: 0x3000_0000 - 1,
ram_start: 0x8000_0000,
ram_end: 0xFFFF_FFFF,
unsafe_ecall_nop: false,
};

impl Platform {
Expand Down
4 changes: 2 additions & 2 deletions ceno_emul/src/rv32im.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ pub struct DecodedInstruction {
}

#[derive(Clone, Copy, Debug)]
enum InsnCategory {
pub enum InsnCategory {
Compute,
Branch,
Load,
Expand Down Expand Up @@ -196,7 +196,7 @@ impl InsnKind {
pub struct InsnCodes {
pub format: InsnFormat,
pub kind: InsnKind,
category: InsnCategory,
pub category: InsnCategory,
pub(crate) opcode: u32,
pub(crate) func3: u32,
pub(crate) func7: u32,
Expand Down
25 changes: 24 additions & 1 deletion ceno_emul/src/tracer.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::{collections::HashMap, fmt, mem};

use crate::{
CENO_PLATFORM, PC_STEP_SIZE,
CENO_PLATFORM, InsnKind, PC_STEP_SIZE,
addr::{ByteAddr, Cycle, RegIdx, Word, WordAddr},
encode_rv32,
rv32im::DecodedInstruction,
};

Expand Down Expand Up @@ -187,6 +188,28 @@ impl StepRecord {
)
}

/// Create a test record for an ECALL instruction that can do anything.
pub fn new_ecall_any(cycle: Cycle, pc: ByteAddr) -> StepRecord {
let value = 1234;
Self::new_insn(
cycle,
Change::new(pc, pc + PC_STEP_SIZE),
encode_rv32(InsnKind::EANY, 0, 0, 0, 0),
Some(value),
Some(value),
Some(Change::new(value, value)),
Some(WriteOp {
addr: CENO_PLATFORM.ram_start().into(),
value: Change {
before: value,
after: value,
},
previous_cycle: 0,
}),
0,
)
}

#[allow(clippy::too_many_arguments)]
fn new_insn(
cycle: Cycle,
Expand Down
15 changes: 12 additions & 3 deletions ceno_emul/src/vm_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashMap;

use super::rv32im::EmuContext;
use crate::{
Program,
PC_STEP_SIZE, Program,
addr::{ByteAddr, RegIdx, Word, WordAddr},
platform::Platform,
rv32im::{DecodedInstruction, Emulator, TrapCause},
Expand Down Expand Up @@ -117,12 +117,21 @@ impl EmuContext for VMState {
// Expect an ecall to terminate the program: function HALT with argument exit_code.
fn ecall(&mut self) -> Result<bool> {
let function = self.load_register(self.platform.reg_ecall())?;
let arg0 = self.load_register(self.platform.reg_arg0())?;
if function == self.platform.ecall_halt() {
let exit_code = self.load_register(self.platform.reg_arg0())?;
tracing::debug!("halt with exit_code={}", exit_code);
tracing::debug!("halt with exit_code={}", arg0);

self.halt();
Ok(true)
} else if self.platform.unsafe_ecall_nop {
// Treat unknown ecalls as all powerful instructions:
// Read two registers, write one register, write one memory word, and branch.
tracing::warn!("ecall ignored: syscall_id={}", function);
self.store_register(DecodedInstruction::RD_NULL as RegIdx, 0)?;
let addr = self.platform.ram_start().into();
self.store_memory(addr, self.peek_memory(addr))?;
self.set_pc(ByteAddr(self.pc) + PC_STEP_SIZE);
Ok(true)
} else {
self.trap(TrapCause::EcallError)
}
Expand Down
1 change: 1 addition & 0 deletions ceno_zkvm/src/instructions/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod branch;
pub mod config;
pub mod constants;
pub mod divu;
pub mod dummy;
pub mod ecall;
pub mod jump;
pub mod logic;
Expand Down
19 changes: 19 additions & 0 deletions ceno_zkvm/src/instructions/riscv/divu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use ff_ext::ExtensionField;
use super::{
RIVInstruction,
constants::{UINT_LIMBS, UInt},
dummy::DummyInstruction,
r_insn::RInstructionConfig,
};
use crate::{
Expand Down Expand Up @@ -33,12 +34,30 @@ pub struct ArithConfig<E: ExtensionField> {

pub struct ArithInstruction<E, I>(PhantomData<(E, I)>);

pub struct DivOp;
impl RIVInstruction for DivOp {
const INST_KIND: InsnKind = InsnKind::DIV;
}
pub type DivDummy<E> = DummyInstruction<E, DivOp>; // TODO: implement DivInstruction.

pub struct DivUOp;
impl RIVInstruction for DivUOp {
const INST_KIND: InsnKind = InsnKind::DIVU;
}
pub type DivUInstruction<E> = ArithInstruction<E, DivUOp>;

pub struct RemOp;
impl RIVInstruction for RemOp {
const INST_KIND: InsnKind = InsnKind::REM;
}
pub type RemDummy<E> = DummyInstruction<E, RemOp>; // TODO: implement RemInstruction.

pub struct RemuOp;
impl RIVInstruction for RemuOp {
const INST_KIND: InsnKind = InsnKind::REMU;
}
pub type RemuDummy<E> = DummyInstruction<E, RemuOp>; // TODO: implement RemuInstruction.

impl<E: ExtensionField, I: RIVInstruction> Instruction<E> for ArithInstruction<E, I> {
type InstructionConfig = ArithConfig<E>;

Expand Down
Loading

0 comments on commit 8e00028

Please sign in to comment.