Skip to content

Commit

Permalink
Implement public output zisk instruction and usage (#131)
Browse files Browse the repository at this point in the history
* Implement public output zisk instruction and usage

* set_output interface

* Fix address offset

* Fixes from integration with Hello World template to process public output

* Fix cargo clippy errors

* Fix riscof tests by enabling by default the emu option LOG_OUTPUT

* Comment out opc_pubout() trace in order to pass riskof tests

---------

Co-authored-by: Jordi Baylina <jordi@baylina.cat>
  • Loading branch information
fractasy and jbaylina authored Oct 25, 2024
1 parent 2bb889d commit 56dc7b3
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 30 deletions.
25 changes: 25 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,31 @@
],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'ziskemu hello_world'",
"cargo": {
"args": [
"build",
"--bin=ziskemu"
],
"filter": {
"name": "ziskemu",
"kind": "bin"
}
},
"args": [
"-e",
"/Users/jbaylina/git/zisk/hello_world/target/riscv64ima-polygon-ziskos-elf/debug/sha_hasher",
"-i",
"/Users/jbaylina/git/zisk/hello_world/build/input.bin",
"-c",
"-m",
"-x",
],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
Expand Down
1 change: 1 addition & 0 deletions core/src/zisk_inst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub enum ZiskOperationType {
Binary,
BinaryE,
Keccak,
PubOut,
}

pub const ZISK_OPERATION_TYPE_VARIANTS: usize = 6;
Expand Down
15 changes: 15 additions & 0 deletions core/src/zisk_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub enum OpType {
Binary,
BinaryE,
Keccak,
PubOut,
}

impl From<OpType> for ZiskOperationType {
Expand All @@ -32,6 +33,7 @@ impl From<OpType> for ZiskOperationType {
OpType::Binary => ZiskOperationType::Binary,
OpType::BinaryE => ZiskOperationType::BinaryE,
OpType::Keccak => ZiskOperationType::Keccak,
OpType::PubOut => ZiskOperationType::PubOut,
}
}
}
Expand All @@ -46,6 +48,7 @@ impl Display for OpType {
Self::Binary => write!(f, "b"),
Self::BinaryE => write!(f, "BinaryE"),
Self::Keccak => write!(f, "Keccak"),
Self::PubOut => write!(f, "PubOut"),
}
}
}
Expand Down Expand Up @@ -266,6 +269,7 @@ define_ops! {
(MaxuW, "maxu_w", Binary, 77, 0x1b, opc_maxu_w, op_maxu_w),
(MaxW, "max_w", Binary, 77, 0x1c, opc_max_w, op_max_w),
(Keccak, "keccak", Keccak, 77, 0xf1, opc_keccak, op_keccak),
(PubOut, "pubout", PubOut, 77, 0x30, opc_pubout, op_pubout), // TODO: New type
}

// Constant values used in operation functions
Expand Down Expand Up @@ -877,3 +881,14 @@ impl From<ZiskRequiredOperation> for ZiskOp {
ZiskOp::try_from_code(value.opcode).unwrap()
}
}

/// Copies register b into c as a public output data record, where a contains the data index
#[inline(always)]
pub const fn op_pubout(a: u64, b: u64) -> (u64, bool) {
(b, false)
}
#[inline(always)]
pub fn opc_pubout(ctx: &mut InstContext) {
(ctx.c, ctx.flag) = op_pubout(ctx.a, ctx.b);
//println!("public ${} = {:#010x}", ctx.a, ctx.b);
}
127 changes: 120 additions & 7 deletions core/src/zv2zisk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1357,7 +1357,7 @@ pub fn add_zisk_init_data(rom: &mut ZiskRom, addr: u64, data: &[u8]) {
/// Add the entry/exit jump program section
pub fn add_entry_exit_jmp(rom: &mut ZiskRom, addr: u64) {
//print!("add_entry_exit_jmp() rom.next_init_inst_addr={}\n", rom.next_init_inst_addr);
let trap_handler: u64 = rom.next_init_inst_addr + 0x18;
let trap_handler: u64 = rom.next_init_inst_addr + 0x14;

// :0000
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
Expand Down Expand Up @@ -1420,7 +1420,120 @@ pub fn add_entry_exit_jmp(rom: &mut ZiskRom, addr: u64) {
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0014
/* Read output length located at first 64 bits of output data,
then read output data in chunks of 64 bits:
loadw: c(reg1) = b(mem=OUTPUT_ADDR), a=0 // TODO: check that Nx4 < OUTPUT_SIZE
copyb: c(reg2)=b=0, a=0
copyb: c(reg3)=b=OUTPUT_ADDR+4, a=0
eq: if reg2==reg1 jump to end
pubout: c=b.mem(reg3), a = reg2
add: reg3 = reg3 + 4 // Increment memory address
add: reg2 = reg2 + 1, jump -12 // Increment index, goto eq
end
*/

// :0014 -> copyb: reg1 = c = b = mem(OUTPUT_ADDR,4), a=0
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("imm", OUTPUT_ADDR, false);
zib.src_b("ind", 0, false);
zib.ind_width(4);
zib.op("copyb").unwrap();
zib.store("reg", 1, false, false);
zib.j(0, 4);
zib.verbose("Set reg1 to output data length read at OUTPUT_ADDR");
zib.build();
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0018 -> copyb: copyb: c(reg2)=b=0, a=0
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("imm", 0, false);
zib.src_b("imm", 0, false);
zib.op("copyb").unwrap();
zib.store("reg", 2, false, false);
zib.j(0, 4);
zib.verbose("Set reg2 to 0");
zib.build();
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :001c -> copyb: c(reg3)=b=OUTPUT_ADDR, a=0
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("imm", 0, false);
zib.src_b("imm", OUTPUT_ADDR + 4, false);
zib.op("copyb").unwrap();
zib.store("reg", 3, false, false);
zib.j(0, 4);
zib.verbose("Set reg3 to OUTPUT_ADDR + 4");
zib.build();
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0020 -> eq: if reg2==reg1 jump to end
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("reg", 1, false);
zib.src_b("reg", 2, false);
zib.op("eq").unwrap();
zib.store("none", 0, false, false);
zib.j(20, 4);
zib.verbose("If reg1==reg2 jumpt to end");
zib.build();
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0024 -> copyb: c = b = mem(reg3, 4)
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("reg", 3, false);
zib.src_b("ind", 0, false);
zib.ind_width(4);
zib.op("copyb").unwrap();
zib.store("none", 0, false, false);
zib.j(0, 4);
zib.verbose("Set c to mem(output_data[index]), a=index");
zib.build();
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0028 -> pubout: c = last_c = mem(reg3, 4), a = reg2 = index
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("reg", 2, false);
zib.src_b("lastc", 0, false);
zib.op("pubout").unwrap();
zib.store("none", 0, false, false);
zib.j(0, 4);
zib.verbose("Public output, set c to output_data[index], a=index");
zib.build();
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :002c -> add: reg3 = reg3 + 4
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("reg", 3, false);
zib.src_b("imm", 4, false);
zib.op("add").unwrap();
zib.store("reg", 3, false, false);
zib.j(0, 4);
zib.verbose("Set reg3 to reg3 + 4");
zib.build();
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0030 -> add: reg2 = reg2 + 1, jump -16
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("reg", 2, false);
zib.src_b("imm", 1, false);
zib.op("add").unwrap();
zib.store("reg", 2, false, false);
zib.j(4, -16);
zib.verbose("Set reg2 to reg2 + 1");
zib.build();
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0034
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("imm", 0, false);
zib.src_b("imm", 0, false);
Expand All @@ -1432,7 +1545,7 @@ pub fn add_entry_exit_jmp(rom: &mut ZiskRom, addr: u64) {
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0018 trap_handle
// :0038 trap_handle
// If register a7==CAUSE_EXIT, end the program
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("reg", 17, false);
Expand All @@ -1444,7 +1557,7 @@ pub fn add_entry_exit_jmp(rom: &mut ZiskRom, addr: u64) {
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :001c
// :003c
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("imm", 0, false);
zib.src_b("imm", 0, false);
Expand All @@ -1456,7 +1569,7 @@ pub fn add_entry_exit_jmp(rom: &mut ZiskRom, addr: u64) {
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0020 trap_handle
// :0040 trap_handle
// If register a7==CAUSE_KECCAK, call the keccak opcode and return
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("reg", 17, false);
Expand All @@ -1468,7 +1581,7 @@ pub fn add_entry_exit_jmp(rom: &mut ZiskRom, addr: u64) {
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0024
// :0044
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("reg", 11, false);
zib.src_b("imm", 0, false);
Expand All @@ -1479,7 +1592,7 @@ pub fn add_entry_exit_jmp(rom: &mut ZiskRom, addr: u64) {
rom.insts.insert(rom.next_init_inst_addr, zib);
rom.next_init_inst_addr += 4;

// :0028
// :0048
let mut zib = ZiskInstBuilder::new(rom.next_init_inst_addr);
zib.src_a("imm", 0, false);
zib.src_b("reg", 1, false);
Expand Down
3 changes: 2 additions & 1 deletion emulator/src/emu_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ pub struct EmuOptions {
/// Sets the log step mode
#[clap(short, long, value_name = "LOG_STEP", default_value = "false")]
pub log_step: bool,
/// Log the output to console
/// Log the output to console. This option is set by default to true as a requirement to pass
/// the riscof GHA tests
#[clap(short = 'c', long, value_name = "LOG_OUTPUT", default_value = "true")]
pub log_output: bool,
/// Trace every this number of steps
Expand Down
45 changes: 23 additions & 22 deletions ziskos/entrypoint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,44 +44,45 @@ pub fn read_input() -> Vec<u8> {
}

#[cfg(target_os = "ziskos")]
pub fn write_output(write_ptr: &[u8], nbytes: usize) {
pub fn set_output(id: usize, value: u32) {
use std::arch::asm;
let addr_n: *mut u32;
let addr_v: *mut u32;
let arch_id_zisk: usize;
let mut addr: *mut u8 = 0x1000_0000 as *mut u8;

unsafe {
asm!(
"csrr {0}, marchid",
out(reg) arch_id_zisk,
)
};

assert!(id < 64, "Maximum number of public outputs: 64");

if arch_id_zisk == ARCH_ID_ZISK as usize {
addr = 0xa000_0200 as *mut u8;
addr_n = OUTPUT_ADDR as *mut u32;
addr_v = (OUTPUT_ADDR + 4 + 4 * (id as u64)) as *mut u32;
} else {
addr_n = 0x1000_0000 as *mut u32;
addr_v = (0x1000_0000 + 4 + 4 * (id as u64)) as *mut u32;
}

for i in 0..nbytes {
unsafe {
core::ptr::write_volatile(addr, write_ptr[i]);
}
let n;

unsafe {
n = core::ptr::read(addr_n) as usize;
}
}

#[cfg(not(target_os = "ziskos"))]
pub fn write_output(write_ptr: &[u8], _nbytes: usize) {
// Convert write_ptr to string
let write_str = match std::str::from_utf8(write_ptr) {
Ok(v) => v,
Err(e) => {
println!("Error converting write_ptr to string: {}", e);
return;
}
};
if id + 1 > n {
unsafe { core::ptr::write_volatile(addr_n, (id + 1) as u32) };
}

// Create the output string
let output = write_str.to_string();
unsafe { core::ptr::write_volatile(addr_v, value) };
}

// Print the output string
print!("{}", output);
#[cfg(not(target_os = "ziskos"))]
pub fn set_output(id: usize, value: u32) {
println!("public {}: {:#010x}", id, value);
}

#[cfg(target_os = "ziskos")]
Expand Down

0 comments on commit 56dc7b3

Please sign in to comment.