From f6cd790fcb4f2ff4d353c3f3131bbae45637c880 Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Mon, 8 Dec 2025 07:31:21 +0000 Subject: [PATCH] ABI info --- Makefile | 1 + README.md | 31 ++++++++++++++++++++++++++++++- common/uvm32_target.h | 1 - common/uvm32_target_custom.h | 0 uvm32/uvm32.c | 6 ++---- 5 files changed, 33 insertions(+), 6 deletions(-) delete mode 100644 common/uvm32_target_custom.h diff --git a/Makefile b/Makefile index 1a8c807..a279e85 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ all: + cat uvm32/uvm32.h uvm32/uvm32.c uvm32/mini-rv32ima.h common/*.h > uvm32-single-file.c (cd host && make) (cd host-mini && make) (cd host-parallel && make) diff --git a/README.md b/README.md index 16a1b48..9f7fb94 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,11 @@ Although based on a fully fledged CPU emulator, uvm32 is intended for executing host/host precompiled/mandel.bin host/host precompiled/zigtris.bin +Build sample apps (sets up docker for cross compiler) + + cd apps + make + Build one of the sample apps (requires docker for C, or Zig, or Rust) cd apps/helloworld && make @@ -78,7 +83,7 @@ If the bytecode attempts to execute more instructions than the the passed value ## Internals -uvm32 emulates a RISC-V 32bit CPU using [mini-rv32ima](https://github.com/cnlohr/mini-rv32ima). All IO from vm bytecode to the host is performed using `ecall` syscalls. Each "function" provided by the host requires a unique syscall value. A syscall passes a single `uint32_t` from bytecode to the host and may receive a returned `uint32_t`. The host may treat the value as a pointer and modify memory. +uvm32 emulates a RISC-V 32bit CPU using [mini-rv32ima](https://github.com/cnlohr/mini-rv32ima). All IO from vm bytecode to the host is performed using `ecall` syscalls. Each syscall provided by the host requires a unique syscall value. A syscall passes a single `uint32_t` from bytecode to the host and may receive a returned `uint32_t`. The host may treat the value as a pointer and modify memory. uvm32 is always in one of 4 states, paused, running, ended or error. @@ -95,6 +100,30 @@ stateDiagram At boot, the whole memory is zeroed. The user program is placed at the start, the CPU registers are stored at the end. The stack pointer is set to the start of the CPU registers and grows downwards. +## syscall ABI + +All communication between bytecode and the vm host is performed via syscalls. + +To make a syscall, register `a7` is set with the syscall number (an `IOREQ_x`) and `a0` is set with the syscall parameter. The response is returned in `a1`. + +[target.h](common/uvm32_target.h#L12) + +```c +static uint32_t syscall(uint32_t id, uint32_t param) { + register uint32_t a0 asm("a0") = (uint32_t)(param); + register uint32_t a1 asm("a1"); + register uint32_t a7 asm("a7") = (uint32_t)(id); + + asm volatile ( + "ecall" + : "=r"(a1) // output + : "r"(a0), "r"(a7) // input + : "memory" + ); + return a1; +} +``` + ## ioreqs There are two system ioreqs used by uvm32, `halt()` and `yield()`. diff --git a/common/uvm32_target.h b/common/uvm32_target.h index b4afdb3..3754183 100644 --- a/common/uvm32_target.h +++ b/common/uvm32_target.h @@ -34,7 +34,6 @@ static uint32_t syscall(uint32_t id, uint32_t param) { #define yield() syscall_cast(IOREQ_YIELD, 0) #include "uvm32_common_custom.h" -#include "uvm32_target_custom.h" // provide main, with setup()/loop() flow void setup(void); diff --git a/common/uvm32_target_custom.h b/common/uvm32_target_custom.h deleted file mode 100644 index e69de29..0000000 diff --git a/uvm32/uvm32.c b/uvm32/uvm32.c index 10f75d3..86d4678 100644 --- a/uvm32/uvm32.c +++ b/uvm32/uvm32.c @@ -153,15 +153,13 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.ioreq.val.buf); break; case IOREQ_TYP_U32_RD: -// get_safeptr(vmst, value, 4, &b); - vmst->ioevt.data.ioreq.val.u32p = &vmst->core->regs[11]; // r1, //(uint32_t *)b.ptr; + // pass link to r1 for user function to update + vmst->ioevt.data.ioreq.val.u32p = &vmst->core->regs[11]; break; } vmst->ioevt.typ = UVM32_EVT_IOREQ; vmst->ioevt.data.ioreq.code = vmst->mappings[i].code; vmst->ioevt.data.ioreq.typ = vmst->mappings[i].typ; -//#warning FIXME, retval -// vmst->core->regs[11] = 456; // r1 setStatus(vmst, UVM32_STATUS_PAUSED); syscall_valid = true; break; // stop searching