From b173cd435ffecd4f10e5d894a3600e59d1d0d779 Mon Sep 17 00:00:00 2001 From: Samuel Judson Date: Tue, 23 Apr 2024 17:48:45 -0400 Subject: [PATCH] Change NVM Syscall Specification (#150) * Change NVM to use rd as part of syscalls for easier circuit constraint generation. * Clippy --- riscv/src/eval.rs | 2 +- riscv/src/nvm.rs | 8 ++++++++ vm/src/eval.rs | 5 +++-- vm/src/syscalls.rs | 18 +++++++++++------- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/riscv/src/eval.rs b/riscv/src/eval.rs index 6852d2700..8f7ccaf23 100644 --- a/riscv/src/eval.rs +++ b/riscv/src/eval.rs @@ -176,7 +176,7 @@ pub fn eval_inst(vm: &mut VM) -> Result<()> { } FENCE | EBREAK => {} ECALL => { - vm.syscalls.syscall(vm.regs.pc, vm.regs.x, &vm.mem)?; + vm.Z = vm.syscalls.syscall(vm.regs.pc, vm.regs.x, &vm.mem)?; } UNIMP => { PC = vm.inst.pc; diff --git a/riscv/src/nvm.rs b/riscv/src/nvm.rs index 0c106f3b7..260d19005 100644 --- a/riscv/src/nvm.rs +++ b/riscv/src/nvm.rs @@ -157,6 +157,14 @@ fn translate_inst(rv: RVInst) -> (u32, Inst) { } RV32::ECALL => { inst.opcode = SYS; + // Per the RISC-V spec, for an ecall `rd = 0` and the system determines + // how to return a value, e.g. by modifying register `x10` (aka `a0`). + // + // For the NVM, we formalize this by setting `rd = 10` and having each + // ecall modify `x10`, even if to just write zero. By doing so, we know + // that `rd` points to the modified register, and so we will always + // generate the R1CS circuit constraints correctly. + inst.rd = 10; } RV32::FENCE | RV32::EBREAK => { inst.opcode = NOP; diff --git a/vm/src/eval.rs b/vm/src/eval.rs index ed2dbc0db..5f4c1b351 100644 --- a/vm/src/eval.rs +++ b/vm/src/eval.rs @@ -99,8 +99,9 @@ pub fn eval_step(vm: &mut NexusVM) -> Result<()> { HALT => { PC = vm.pc; } - SYS => vm.syscalls.syscall(vm.pc, vm.regs, &vm.memory)?, - + SYS => { + vm.Z = vm.syscalls.syscall(vm.pc, vm.regs, &vm.memory)?; + } JAL => { vm.Z = add32(vm.pc, 8); let XI = add32(X, I); diff --git a/vm/src/syscalls.rs b/vm/src/syscalls.rs index 23a6fdbb4..9a7ec094b 100644 --- a/vm/src/syscalls.rs +++ b/vm/src/syscalls.rs @@ -37,26 +37,30 @@ impl Syscalls { self.input = slice.to_owned().into(); } - pub fn syscall(&mut self, pc: u32, mut regs: [u32; 32], memory: &impl Memory) -> Result<()> { + pub fn syscall(&mut self, pc: u32, regs: [u32; 32], memory: &impl Memory) -> Result { let num = regs[18]; // s2 = x18 syscall number - let a0 = regs[10]; // a0 = x10 - let a1 = regs[11]; // a1 = x11 + let inp1 = regs[10]; // a0 = x10 + let inp2 = regs[11]; // a1 = x11 + + let mut out = 0x0; + if num == 1 { // write_log let mut stdout = std::io::stdout(); - for addr in a0..a0 + a1 { + for addr in inp1..inp1 + inp2 { let b = memory.load(Width::BU, addr)?.0; stdout.write_all(&[b as u8])?; } let _ = stdout.flush(); } else if num == 2 { match self.input.pop_front() { - Some(b) => regs[10] = b as u32, - None => regs[10] = u32::MAX, + Some(b) => out = b as u32, + None => out = u32::MAX, } } else { return Err(UnknownSyscall(pc, num)); } - Ok(()) + + Ok(out) } }