Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hint IO in the SDK #631

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
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
141 changes: 141 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
exclude = ["examples"]
members = [
"ceno_emul",
"examples-builder",
"ceno_host",
"ceno_rt",
"ceno_zkvm",
"examples-builder",
"mpcs",
"multilinear_extensions",
"poseidon",
"sumcheck",
"transcript",
"ceno_zkvm",
"poseidon",
]
resolver = "2"

Expand All @@ -23,6 +24,7 @@ repository = "https://github.com/scroll-tech/ceno"
version = "0.1.0"

[workspace.dependencies]
anyhow = { version = "1.0", default-features = false }
ark-std = "0.4"
cfg-if = "1.0"
criterion = { version = "0.5", features = ["html_reports"] }
Expand Down
2 changes: 1 addition & 1 deletion ceno_emul/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repository.workspace = true
version.workspace = true

[dependencies]
anyhow = { version = "1.0", default-features = false }
anyhow.workspace = true
elf = "0.7"
itertools.workspace = true
num-derive.workspace = true
Expand Down
13 changes: 13 additions & 0 deletions ceno_emul/src/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use std::{
fmt,
iter::Step,
ops::{self, Range},
};

Expand Down Expand Up @@ -106,6 +107,18 @@ impl WordAddr {
}
}

impl Step for WordAddr {
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
u32::steps_between(&start.0, &end.0)
}
fn forward_checked(start: Self, count: usize) -> Option<Self> {
u32::forward_checked(start.0, count).map(Self)
}
fn backward_checked(start: Self, count: usize) -> Option<Self> {
u32::backward_checked(start.0, count).map(Self)
}
}

impl fmt::Debug for ByteAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0x{:08x}", self.0)
Expand Down
32 changes: 32 additions & 0 deletions ceno_emul/src/host_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::iter::from_fn;

use crate::{ByteAddr, EmuContext, VMState, WordAddr};

const WORD_SIZE: usize = 4;
const INFO_OUT_ADDR: WordAddr = ByteAddr(0xC000_0000).waddr();

pub fn read_all_messages(state: &VMState) -> Vec<String> {
let mut offset: WordAddr = WordAddr::from(0);
from_fn(move || match read_message(state, offset) {
out if out.is_empty() => None,
out => {
offset += out.len().div_ceil(WORD_SIZE) as u32 + 1;
Some(out)
}
})
.collect()
}

fn read_message(state: &VMState, offset: WordAddr) -> String {
let out_addr = INFO_OUT_ADDR + offset;
let byte_len = state.peek_memory(out_addr) as usize;

String::from_utf8_lossy(
&(out_addr + 1_usize..)
.map(|memory| state.peek_memory(memory))
.flat_map(u32::to_le_bytes)
.take(byte_len)
.collect::<Vec<_>>(),
)
.to_string()
}
3 changes: 3 additions & 0 deletions ceno_emul/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![deny(clippy::cargo)]
#![feature(step_trait)]
mod addr;
pub use addr::*;

Expand All @@ -19,3 +20,5 @@ pub use elf::Program;

mod rv32im_encode;
pub use rv32im_encode::encode_rv32;

pub mod host_utils;
42 changes: 7 additions & 35 deletions ceno_emul/tests/test_elf.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use anyhow::Result;
use ceno_emul::{ByteAddr, CENO_PLATFORM, EmuContext, InsnKind, Platform, StepRecord, VMState};
use ceno_emul::{
CENO_PLATFORM, EmuContext, InsnKind, Platform, StepRecord, VMState,
host_utils::read_all_messages,
};

#[test]
fn test_ceno_rt_mini() -> Result<()> {
Expand Down Expand Up @@ -65,10 +68,10 @@ fn test_ceno_rt_io() -> Result<()> {

let all_messages = read_all_messages(&state);
for msg in &all_messages {
print!("{}", String::from_utf8_lossy(msg));
print!("{msg}");
}
assert_eq!(&all_messages[0], "📜📜📜 Hello, World!\n".as_bytes());
assert_eq!(&all_messages[1], "🌏🌍🌎\n".as_bytes());
assert_eq!(&all_messages[0], "📜📜📜 Hello, World!\n");
assert_eq!(&all_messages[1], "🌏🌍🌎\n");
Ok(())
}

Expand All @@ -77,34 +80,3 @@ fn run(state: &mut VMState) -> Result<Vec<StepRecord>> {
eprintln!("Emulator ran for {} steps.", steps.len());
Ok(steps)
}

const WORD_SIZE: usize = 4;
const INFO_OUT_ADDR: u32 = 0xC000_0000;

fn read_all_messages(state: &VMState) -> Vec<Vec<u8>> {
let mut all_messages = Vec::new();
let mut word_offset = 0;
loop {
let out = read_message(state, word_offset);
if out.is_empty() {
break;
}
word_offset += out.len().div_ceil(WORD_SIZE) as u32 + 1;
all_messages.push(out);
}
all_messages
}

fn read_message(state: &VMState, word_offset: u32) -> Vec<u8> {
let out_addr = ByteAddr(INFO_OUT_ADDR).waddr() + word_offset;
let byte_len = state.peek_memory(out_addr);
let word_len_up = byte_len.div_ceil(4);

let mut info_out = Vec::with_capacity(WORD_SIZE * word_len_up as usize);
for i in 1..1 + word_len_up {
let value = state.peek_memory(out_addr + i);
info_out.extend_from_slice(&value.to_le_bytes());
}
info_out.truncate(byte_len as usize);
info_out
}
19 changes: 19 additions & 0 deletions ceno_host/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
categories.workspace = true
description = "Support for the host port of a Ceno application"
edition.workspace = true
keywords.workspace = true
license.workspace = true
name = "ceno_host"
readme.workspace = true
repository.workspace = true
version.workspace = true

[dependencies]
anyhow.workspace = true
ceno_emul = { path = "../ceno_emul" }
itertools.workspace = true
rkyv = { version = "0.8.9", default-features = false, features = ["alloc", "bytecheck"] }

[dev-dependencies]
rand.workspace = true
Loading