-
Notifications
You must be signed in to change notification settings - Fork 30
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
[feat] Add the functionality for custom RISC-V intrinsics, support hints in RISC-V #726
Changes from 9 commits
59a7bd3
ac5ad94
c961df2
fed98b8
8fb16f0
57f2ab9
f6e132c
4582601
a3785d0
2b44823
3165d5f
895ace5
963dee7
a47f3c9
869aa21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// use crate::custom_insn_i; | ||
|
||
use alloc::{alloc::Layout, vec::Vec}; | ||
|
||
use axvm_platform::{custom_insn_i, intrinsics::CUSTOM_0}; | ||
|
||
/// Store the next 4 bytes from the hint stream to [[rd] + imm]_2. | ||
#[macro_export] | ||
macro_rules! hint_store_u32 { | ||
($x:ident, $imm:expr) => { | ||
custom_insn_i!(CUSTOM_0, 0b001, $x, "x0", $imm) | ||
}; | ||
} | ||
|
||
/// Read the next 4 bytes from the hint stream. | ||
#[allow(asm_sub_register)] | ||
pub fn read_u32() -> u32 { | ||
let ptr = unsafe { alloc::alloc::alloc(Layout::from_size_align(4, 4).unwrap()) }; | ||
let addr = ptr as u32; | ||
hint_store_u32!(addr, 0); | ||
let result: u32; | ||
unsafe { | ||
core::arch::asm!("lw {rd}, ({rs1})", rd = out(reg) result, rs1 = in(reg) addr); | ||
} | ||
result | ||
} | ||
|
||
/// Read the next `len` bytes from the hint stream into a vector. | ||
fn read_vec_by_len(len: usize) -> Vec<u8> { | ||
// Note: this expect message doesn't matter until our panic handler actually cares about it | ||
let layout = Layout::from_size_align((len + 3) / 4 * 4, 4).expect("vec is too large"); | ||
let ptr = unsafe { alloc::alloc::alloc(layout) }; | ||
let mut x: u32 = 0; | ||
// Note: if len % 4 != 0, this will discard some last bytes | ||
for i in 0..len { | ||
if i % 4 == 0 { | ||
// TODO: it probably makes sense not to juggle the data between registers and memory here. | ||
// On the other hand, maybe it's not a big deal. | ||
x = read_u32(); | ||
} | ||
unsafe { | ||
ptr.add(i).write_volatile((x & 255) as u8); | ||
} | ||
x >>= 8; | ||
} | ||
unsafe { Vec::from_raw_parts(ptr, len, len) } | ||
} | ||
|
||
/// Read `size: u32` and then `size` bytes from the hint stream into a vector. | ||
pub fn read_vec() -> Vec<u8> { | ||
read_vec_by_len(read_u32() as usize) | ||
} | ||
|
||
/// Reset the hint stream with the next hint. | ||
pub fn hint_input() { | ||
custom_insn_i!(CUSTOM_0, 0b011, "x0", "x0", 0); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,18 @@ | ||
//! Functions that call custom instructions that use axVM intrinsic instructions. | ||
|
||
mod hash; | ||
/// Library functions for user input/output. | ||
pub mod io; | ||
|
||
pub use hash::*; | ||
pub use io::*; | ||
|
||
/// Exit the program with exit code 0. | ||
pub fn exit() { | ||
jonathanpwang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
axvm_platform::rust_rt::terminate::<0>(); | ||
} | ||
|
||
/// Exit the program with exit code 1. | ||
pub fn panic() { | ||
axvm_platform::rust_rt::terminate::<1>(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,6 +79,7 @@ | |
#![deny(rustdoc::broken_intra_doc_links)] | ||
#![deny(missing_docs)] | ||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] | ||
#![feature(asm_const)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this a nightly feature? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the |
||
|
||
extern crate alloc; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[build] | ||
target = "riscv32im-risc0-zkvm-elf" | ||
|
||
[unstable] | ||
build-std = ["core", "alloc", "proc_macro", "panic_abort"] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[workspace] | ||
[package] | ||
version = "0.1.0" | ||
name = "axvm-hint-program" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
axvm = { path = "../../../axvm" } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#![no_main] | ||
#![no_std] | ||
|
||
axvm::entry!(main); | ||
|
||
pub fn main() { | ||
axvm::intrinsics::io::hint_input(); | ||
let vec = axvm::intrinsics::io::read_size_and_vec(); | ||
if vec.iter().sum::<u8>() == 0 { | ||
axvm::intrinsics::panic(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
pub const CUSTOM_0: u8 = 0x0b; | ||
pub const CUSTOM_1: u8 = 0x2b; | ||
|
||
#[macro_export] | ||
macro_rules! custom_insn_i { | ||
($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $imm:expr) => { | ||
unsafe { | ||
core::arch::asm!(concat!( | ||
".insn i {opcode}, {funct3}, ", | ||
$rd, | ||
", ", | ||
$rs1, | ||
", {imm}", | ||
), opcode = const $opcode, funct3 = const $funct3, imm = const $imm) | ||
} | ||
}; | ||
($opcode:expr, $funct3:expr, $x:ident, $rs1:literal, $imm:expr) => { | ||
jonathanpwang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
unsafe { | ||
core::arch::asm!(concat!( | ||
".insn i {opcode}, {funct3}, {rd}, ", | ||
$rs1, | ||
", {imm}", | ||
), opcode = const $opcode, funct3 = const $funct3, rd = in(reg) $x, imm = const $imm) | ||
} | ||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! custom_insn_r { | ||
($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $rs2:literal) => { | ||
unsafe { | ||
core::arch::asm!(concat!( | ||
".insn r {opcode}, {funct3}, ", | ||
$rd, | ||
", ", | ||
$rs1, | ||
", ", | ||
$rs2, | ||
), opcode = const $opcode, funct3 = const $funct3) | ||
} | ||
}; | ||
($opcode:expr, $funct3:expr, $x:ident, $rs1:literal, $rs2:literal) => { | ||
unsafe { | ||
core::arch::asm!(concat!( | ||
".insn r {opcode}, {funct3}, {rd}, ", | ||
$rs1, | ||
", ", | ||
$rs2, | ||
), opcode = const $opcode, funct3 = const $funct3, rd = out(reg) $x) | ||
} | ||
}; | ||
// TODO: implement more variants with like rs1 = in(reg) $y etc | ||
} |
Golovanov399 marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this magic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok it seems it's because we hint to memory and register is stack. please add some comments because you're too clever
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I was just doing what compiler suggested