diff --git a/README.md b/README.md index 62d5f9a..53d7f16 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Although based on a fully fledged CPU emulator, uvm32 is intended for executing ## Samples - * [host](host) vm host which loads a binary and runs to completion, handling multiple ioreq types + * [host](host) vm host which loads a binary and runs to completion, handling multiple syscall types * [host-mini](host-mini) minimal vm host (shown above), with baked in bytecode * [host-parallel](host-parallel) parallel vm host running multiple vm instances concurrently, with baked in bytecode * [host-arduino](host-arduino) vm host as Arduino sketch (tested on Arduino Uno ATmega328P, uses 9950 bytes of flash/1254 bytes RAM) @@ -70,7 +70,7 @@ Once loaded with bytecode, uvm32's state is advanced by calling `uvm32_run()`. uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) `uvm32_run()` will execute until the bytecode requests some IO activity from the host. -These IO activities are called "ioreqs" and are the only way for bytecode to communicate with the host. +These IO activities are called "syscalls" and are the only way for bytecode to communicate with the host. If the bytecode attempts to execute more instructions than the the passed value of `instr_meter` it is assumed to have crashed and an error is reported. (As with a watchdog on an embedded system, the `yield()` bytecode function tells the host that the code requires more time to complete and has not hung) @@ -80,7 +80,7 @@ If the bytecode attempts to execute more instructions than the the passed value * `UVM32_EVT_END` the program has ended * `UVM32_EVT_ERR` the program has encountered an error * `UVM32_EVT_YIELD` the program has called `yield()` signifying that it requires more instructions to be executed, but has not crashed/hung -* `UVM32_EVT_IOREQ` the program requests some IO via the host +* `UVM32_EVT_UVM32_SYSCALL` the program requests some IO via the host ## Internals @@ -92,7 +92,7 @@ uvm32 is always in one of 4 states, paused, running, ended or error. stateDiagram [*] --> UVM32_STATUS_PAUSED : uvm32_init() UVM32_STATUS_PAUSED-->UVM32_STATUS_RUNNING : uvm32_run() - UVM32_STATUS_RUNNING --> UVM32_STATUS_PAUSED : ioreq event + UVM32_STATUS_RUNNING --> UVM32_STATUS_PAUSED : syscall event UVM32_STATUS_RUNNING --> UVM32_STATUS_ENDED : halt() UVM32_STATUS_RUNNING --> UVM32_STATUS_ERROR ``` @@ -105,7 +105,7 @@ At boot, the whole memory is zeroed. The user program is placed at the start, th 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`. +To make a syscall, register `a7` is set with the syscall number (a `UVM32_SYSCALL_x`) and `a0` is set with the syscall parameter. The response is returned in `a1`. [target.h](common/uvm32_target.h#L12) @@ -125,14 +125,14 @@ static uint32_t syscall(uint32_t id, uint32_t param) { } ``` -## ioreqs +## syscalls -There are two system ioreqs used by uvm32, `halt()` and `yield()`. +There are two system syscalls used by uvm32, `halt()` and `yield()`. `halt()` tells the host that the program has ended normally. `yield()` tells the host that the program requires more instructions to be executed. -New ioreqs can be added to the host via `uvm32_init()`. -Each ioreq maps a syscall number to a value understood by the host (`F_PRINTD` below) and has an associated type which tells the host how to interpret the data passed to the syscall. +New syscalls can be added to the host via `uvm32_init()`. +Each syscall maps a syscall number to a value understood by the host (`F_PRINTD` below) and has an associated type which tells the host how to interpret the data passed to the syscall. Here is a full example of a working VM host from [apps/host-mini](apps/host-mini) @@ -146,7 +146,7 @@ Here is a full example of a working VM host from [apps/host-mini](apps/host-mini #include "../common/uvm32_common_custom.h" // Precompiled binary program to print integers -// This code expects to print via syscall 0x13C (IOREQ_PRINTD in common/uvm32_common_custom.h) +// This code expects to print via syscall 0x13C (UVM32_SYSCALL_PRINTD in common/uvm32_common_custom.h) uint8_t rom[] = { 0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x73, 0x50, 0x80, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x07, 0x00, 0x00, @@ -159,9 +159,9 @@ typedef enum { F_PRINTD, } f_code_t; -// Map VM ioreq IOREQ_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32 +// Map VM syscall UVM32_SYSCALL_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32 const uvm32_mapping_t env[] = { - { .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD }, + { .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD }, }; int main(int argc, char *argv[]) { @@ -179,11 +179,11 @@ int main(int argc, char *argv[]) { case UVM32_EVT_END: isrunning = false; break; - case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ - switch((f_code_t)evt.data.ioreq.code) { + case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL + switch((f_code_t)evt.data.syscall.code) { case F_PRINTD: - // Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in evt.data.ioreq.val.u32 - printf("%d\n", evt.data.ioreq.val.u32); + // Type of F_PRINTD is UVM32_SYSCALL_TYP_U32_WR, so expect value in evt.data.syscall.val.u32 + printf("%d\n", evt.data.syscall.val.u32); break; } break; diff --git a/apps/crt0.S b/apps/crt0.S index d73c0ea..01afb70 100644 --- a/apps/crt0.S +++ b/apps/crt0.S @@ -12,7 +12,7 @@ jal ra, main #include "non-rust-crt0-hack.S" #else // only rust will see this -li a7, {IOREQ_HALT} +li a7, {UVM32_SYSCALL_HALT} #endif ecall .section .data diff --git a/apps/hello-asm/hello-asm.S b/apps/hello-asm/hello-asm.S index a38c926..9f4faa8 100644 --- a/apps/hello-asm/hello-asm.S +++ b/apps/hello-asm/hello-asm.S @@ -4,9 +4,9 @@ .global _start _start: la a0, str -li a7, IOREQ_PRINTLN +li a7, UVM32_SYSCALL_PRINTLN ecall -li a7, IOREQ_HALT +li a7, UVM32_SYSCALL_HALT ecall str: .ascii "Hi\0" diff --git a/apps/non-rust-crt0-hack.S b/apps/non-rust-crt0-hack.S index 6616332..cb3e9ae 100644 --- a/apps/non-rust-crt0-hack.S +++ b/apps/non-rust-crt0-hack.S @@ -1 +1 @@ -li a7,IOREQ_HALT +li a7,UVM32_SYSCALL_HALT diff --git a/apps/rust-hello/src/main.rs b/apps/rust-hello/src/main.rs index 92eb70e..9718286 100644 --- a/apps/rust-hello/src/main.rs +++ b/apps/rust-hello/src/main.rs @@ -5,11 +5,11 @@ use core::arch::global_asm; use core::arch::asm; use core::panic::PanicInfo; -// fetch IOREQ definitions from C header +// fetch UVM32_SYSCALL definitions from C header include!(concat!(env!("OUT_DIR"), "/bindings.rs")); // startup code -global_asm!(include_str!("../../crt0.S"), IOREQ_HALT = const IOREQ_HALT); +global_asm!(include_str!("../../crt0.S"), UVM32_SYSCALL_HALT = const UVM32_SYSCALL_HALT); fn syscall(id: u32, n: u32) -> u32 { let mut value; @@ -25,11 +25,11 @@ fn syscall(id: u32, n: u32) -> u32 { fn println(message: &str) { let addr_value = message.as_ptr() as u32; - syscall(IOREQ_PRINTLN, addr_value); + syscall(UVM32_SYSCALL_PRINTLN, addr_value); } fn printd(n: u32) { - syscall(IOREQ_PRINTD, n); + syscall(UVM32_SYSCALL_PRINTD, n); } #[no_mangle] diff --git a/apps/zig-mandel/src/uvm.zig b/apps/zig-mandel/src/uvm.zig index 056da22..c3d2474 100644 --- a/apps/zig-mandel/src/uvm.zig +++ b/apps/zig-mandel/src/uvm.zig @@ -15,14 +15,14 @@ pub inline fn syscall(id: u32, param: u32) u32 { } pub inline fn println(val: [:0]const u8) void { - _ = syscall(uvm32.IOREQ_PRINTLN, @intFromPtr(val.ptr)); + _ = syscall(uvm32.UVM32_SYSCALL_PRINTLN, @intFromPtr(val.ptr)); } pub inline fn yield() void { - _ = syscall(uvm32.IOREQ_YIELD, 0); + _ = syscall(uvm32.UVM32_SYSCALL_YIELD, 0); } pub inline fn printc(c:u8) void { - _ = syscall(uvm32.IOREQ_PRINTC, c); + _ = syscall(uvm32.UVM32_SYSCALL_PRINTC, c); } diff --git a/apps/zigtris/src/uvm.zig b/apps/zigtris/src/uvm.zig index 5a66218..27ac526 100644 --- a/apps/zigtris/src/uvm.zig +++ b/apps/zigtris/src/uvm.zig @@ -15,7 +15,7 @@ pub inline fn syscall(id: u32, param: u32) u32 { } pub inline fn getch() ?u8 { - const key = syscall(uvm32.IOREQ_GETC, 0); + const key = syscall(uvm32.UVM32_SYSCALL_GETC, 0); if (key == 0xFFFFFFFF) { return null; } else { @@ -24,7 +24,7 @@ pub inline fn getch() ?u8 { } pub inline fn millis() u32 { - return syscall(uvm32.IOREQ_MILLIS, 0); + return syscall(uvm32.UVM32_SYSCALL_MILLIS, 0); } // dupeZ would be better, but want to avoid using an allocator @@ -35,21 +35,21 @@ pub inline fn print(m: []const u8) void { @memcpy(termination_buf[0..m.len], m); termination_buf[m.len] = 0; const s = termination_buf[0..m.len :0]; - _ = syscall(uvm32.IOREQ_PRINT, @intFromPtr(s.ptr)); + _ = syscall(uvm32.UVM32_SYSCALL_PRINT, @intFromPtr(s.ptr)); } pub inline fn println(m: []const u8) void { @memcpy(termination_buf[0..m.len], m); termination_buf[m.len] = 0; const s = termination_buf[0..m.len :0]; - _ = syscall(uvm32.IOREQ_PRINTLN, @intFromPtr(s.ptr)); + _ = syscall(uvm32.UVM32_SYSCALL_PRINTLN, @intFromPtr(s.ptr)); } pub inline fn yield() void { - _ = syscall(uvm32.IOREQ_YIELD, 0); + _ = syscall(uvm32.UVM32_SYSCALL_YIELD, 0); } pub inline fn printc(c:u8) void { - _ = syscall(uvm32.IOREQ_PRINTC, c); + _ = syscall(uvm32.UVM32_SYSCALL_PRINTC, c); } diff --git a/common/uvm32_common_custom.h b/common/uvm32_common_custom.h index 1131458..0fb8c94 100644 --- a/common/uvm32_common_custom.h +++ b/common/uvm32_common_custom.h @@ -1,11 +1,11 @@ // Definitions needed by both host and target // syscalls for exposed host functions -#define IOREQ_PRINT 0x13A -#define IOREQ_PRINTLN 0x13B -#define IOREQ_PRINTD 0x13C -#define IOREQ_PRINTX 0x13D -#define IOREQ_MILLIS 0x13F -#define IOREQ_PRINTC 0x140 -#define IOREQ_GETC 0x141 +#define UVM32_SYSCALL_PRINT 0x13A +#define UVM32_SYSCALL_PRINTLN 0x13B +#define UVM32_SYSCALL_PRINTD 0x13C +#define UVM32_SYSCALL_PRINTX 0x13D +#define UVM32_SYSCALL_MILLIS 0x13F +#define UVM32_SYSCALL_PRINTC 0x140 +#define UVM32_SYSCALL_GETC 0x141 diff --git a/common/uvm32_sys.h b/common/uvm32_sys.h index 5b2992a..e11b236 100644 --- a/common/uvm32_sys.h +++ b/common/uvm32_sys.h @@ -1,5 +1,5 @@ -// System provided IOREQs -#define IOREQ_HALT 0x138 -#define IOREQ_YIELD 0x139 +// System provided UVM32_SYSCALLs +#define UVM32_SYSCALL_HALT 0x138 +#define UVM32_SYSCALL_YIELD 0x139 #include "uvm32_common_custom.h" diff --git a/common/uvm32_target.h b/common/uvm32_target.h index 3754183..9a9c6b1 100644 --- a/common/uvm32_target.h +++ b/common/uvm32_target.h @@ -24,14 +24,14 @@ static uint32_t syscall(uint32_t id, uint32_t param) { } #define syscall_cast(id, x) syscall((uint32_t)id, (uint32_t)x) -#define println(x) syscall_cast(IOREQ_PRINTLN, x) -#define print(x) syscall_cast(IOREQ_PRINT, x) -#define printd(x) syscall_cast(IOREQ_PRINTD, x) -#define printx(x) syscall_cast(IOREQ_PRINTX, x) -#define millis() syscall_cast(IOREQ_MILLIS, 0) -#define printc() syscall_cast(IOREQ_PRINTC, 0) -#define getc() syscall_cast(IOREQ_GETC, 0) -#define yield() syscall_cast(IOREQ_YIELD, 0) +#define println(x) syscall_cast(UVM32_SYSCALL_PRINTLN, x) +#define print(x) syscall_cast(UVM32_SYSCALL_PRINT, x) +#define printd(x) syscall_cast(UVM32_SYSCALL_PRINTD, x) +#define printx(x) syscall_cast(UVM32_SYSCALL_PRINTX, x) +#define millis() syscall_cast(UVM32_SYSCALL_MILLIS, 0) +#define printc() syscall_cast(UVM32_SYSCALL_PRINTC, 0) +#define getc() syscall_cast(UVM32_SYSCALL_GETC, 0) +#define yield() syscall_cast(UVM32_SYSCALL_YIELD, 0) #include "uvm32_common_custom.h" diff --git a/host-arduino/common/uvm32_common_custom.h b/host-arduino/common/uvm32_common_custom.h index e5c0a35..2c56fb7 100644 --- a/host-arduino/common/uvm32_common_custom.h +++ b/host-arduino/common/uvm32_common_custom.h @@ -1,10 +1,10 @@ // Definitions needed by both host and target // CSRs for exposed host functions -#define IOREQ_PRINT 0x13A -#define IOREQ_PRINTLN 0x13B -#define IOREQ_PRINTD 0x13C -#define IOREQ_PRINTX 0x13D -#define IOREQ_MILLIS 0x13F -#define IOREQ_PRINTC 0x140 +#define UVM32_SYSCALL_PRINT 0x13A +#define UVM32_SYSCALL_PRINTLN 0x13B +#define UVM32_SYSCALL_PRINTD 0x13C +#define UVM32_SYSCALL_PRINTX 0x13D +#define UVM32_SYSCALL_MILLIS 0x13F +#define UVM32_SYSCALL_PRINTC 0x140 diff --git a/host-arduino/common/uvm32_sys.h b/host-arduino/common/uvm32_sys.h index 5b2992a..e11b236 100644 --- a/host-arduino/common/uvm32_sys.h +++ b/host-arduino/common/uvm32_sys.h @@ -1,5 +1,5 @@ -// System provided IOREQs -#define IOREQ_HALT 0x138 -#define IOREQ_YIELD 0x139 +// System provided UVM32_SYSCALLs +#define UVM32_SYSCALL_HALT 0x138 +#define UVM32_SYSCALL_YIELD 0x139 #include "uvm32_common_custom.h" diff --git a/host-arduino/host-arduino.ino b/host-arduino/host-arduino.ino index fb0d14c..5c99a07 100644 --- a/host-arduino/host-arduino.ino +++ b/host-arduino/host-arduino.ino @@ -3,7 +3,7 @@ #include "common/uvm32_common_custom.h" // Precompiled binary program to print integers -// This code expects to print via syscall 0x13C (IOREQ_PRINTD in common/uvm32_common_custom.h) +// This code expects to print via syscall 0x13C (UVM32_SYSCALL_PRINTD in common/uvm32_common_custom.h) uint8_t rom[] = { 0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0xc0, 0x00, 0x93, 0x08, 0x80, 0x13, 0x73, 0x00, 0x00, 0x00, 0x37, 0xf5, 0xff, 0xff, 0xb7, 0x15, 0x00, 0x00, @@ -34,11 +34,11 @@ typedef enum { F_PRINTC, } f_code_t; -// Map VM ioreq IOREQ_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32 +// Map VM syscall UVM32_SYSCALL_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32 const uvm32_mapping_t env[] = { - { IOREQ_PRINTD, F_PRINTD, IOREQ_TYP_U32_WR }, - { IOREQ_PRINTC, F_PRINTC, IOREQ_TYP_U32_WR }, - { IOREQ_PRINTLN, F_PRINTLN, IOREQ_TYP_BUF_TERMINATED_WR }, + { UVM32_SYSCALL_PRINTD, F_PRINTD, UVM32_SYSCALL_TYP_U32_WR }, + { UVM32_SYSCALL_PRINTC, F_PRINTC, UVM32_SYSCALL_TYP_U32_WR }, + { UVM32_SYSCALL_PRINTLN, F_PRINTLN, UVM32_SYSCALL_TYP_BUF_TERMINATED_WR }, }; uvm32_state_t vmst; @@ -68,17 +68,17 @@ void loop(void) { case UVM32_EVT_END: isrunning = false; break; - case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ - switch((f_code_t)evt.data.ioreq.code) { + case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL + switch((f_code_t)evt.data.syscall.code) { case F_PRINTD: - Serial.println(evt.data.ioreq.val.u32); + Serial.println(evt.data.syscall.val.u32); break; case F_PRINTC: - Serial.print((char)evt.data.ioreq.val.u32); + Serial.print((char)evt.data.syscall.val.u32); break; case F_PRINTLN: - for (int i=0;i= UVM32_MEMORY_SIZE) { @@ -91,7 +91,7 @@ static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t t } #if 0 -static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_evt_ioreq_buf_t *buf) { +static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_evt_syscall_buf_t *buf) { uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET; if (ptrstart + len >= UVM32_MEMORY_SIZE) { setStatusErr(vmst, UVM32_ERR_MEM_RD); @@ -104,7 +104,7 @@ static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) { uint32_t num_instr = 0; -// uvm32_evt_ioreq_buf_t b; +// uvm32_evt_syscall_buf_t b; if (vmst->status != UVM32_STATUS_PAUSED) { setStatusErr(vmst, UVM32_ERR_NOTREADY); @@ -128,11 +128,11 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) vmst->core->pc += 4; switch(syscall) { // inbuilt syscalls - case IOREQ_HALT: + case UVM32_SYSCALL_HALT: setStatus(vmst, UVM32_STATUS_ENDED); syscall_valid = true; break; - case IOREQ_YIELD: + case UVM32_SYSCALL_YIELD: vmst->ioevt.typ = UVM32_EVT_YIELD; setStatus(vmst, UVM32_STATUS_PAUSED); syscall_valid = true; @@ -145,24 +145,21 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) if (syscall == vmst->mappings[i].syscall) { // setup ioevt.data according to mapping typ switch(vmst->mappings[i].typ) { - case IOREQ_TYP_VOID: + case UVM32_SYSCALL_TYP_VOID: break; - case IOREQ_TYP_U32_WR: - vmst->ioevt.data.ioreq.val.u32 = value; + case UVM32_SYSCALL_TYP_U32_WR: + vmst->ioevt.data.syscall.val.u32 = value; break; - case IOREQ_TYP_BUF_TERMINATED_WR: - get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.ioreq.val.buf); + case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR: + get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.syscall.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; + case UVM32_SYSCALL_TYP_U32_RD: + vmst->ioevt.data.syscall.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 + vmst->ioevt.typ = UVM32_EVT_UVM32_SYSCALL; + vmst->ioevt.data.syscall.code = vmst->mappings[i].code; + vmst->ioevt.data.syscall.typ = vmst->mappings[i].typ; setStatus(vmst, UVM32_STATUS_PAUSED); syscall_valid = true; break; // stop searching diff --git a/host-arduino/uvm32.h b/host-arduino/uvm32.h index 9a55b76..786390f 100644 --- a/host-arduino/uvm32.h +++ b/host-arduino/uvm32.h @@ -4,9 +4,9 @@ #include #include -// "well-known" system IOREQ functions -#define IOREQ_HALT 0x138 -#define IOREQ_YIELD 0x139 +// "well-known" system UVM32_SYSCALL functions +#define UVM32_SYSCALL_HALT 0x138 +#define UVM32_SYSCALL_YIELD 0x139 #define LIST_OF_UVM32_ERRS \ X(UVM32_ERR_NONE) \ @@ -26,41 +26,41 @@ typedef enum { typedef enum { UVM32_EVT_ERR, - UVM32_EVT_IOREQ, + UVM32_EVT_UVM32_SYSCALL, UVM32_EVT_YIELD, UVM32_EVT_END, } uvm32_evt_typ_t; typedef enum { - IOREQ_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_ioreq_t.val.buf - IOREQ_TYP_VOID, // no data - IOREQ_TYP_U32_WR, // data write from vm, in uvm32_evt_ioreq_t.val.u32 - IOREQ_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_ioreq_t.val.u32p -} uvm32_ioreq_typ_t; + UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_syscall_t.val.buf + UVM32_SYSCALL_TYP_VOID, // no data + UVM32_SYSCALL_TYP_U32_WR, // data write from vm, in uvm32_evt_syscall_t.val.u32 + UVM32_SYSCALL_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_syscall_t.val.u32p +} uvm32_syscall_typ_t; -typedef uint32_t uvm32_user_ioreq_code_t; +typedef uint32_t uvm32_user_syscall_code_t; -// user supplied mapping from syscall to typed ioreq +// user supplied mapping from syscall to typed syscall typedef struct { uint32_t syscall; - uvm32_user_ioreq_code_t code; - uvm32_ioreq_typ_t typ; + uvm32_user_syscall_code_t code; + uvm32_syscall_typ_t typ; } uvm32_mapping_t; typedef struct { uint8_t *ptr; uint32_t len; -} uvm32_evt_ioreq_buf_t; +} uvm32_evt_syscall_buf_t; typedef struct { - uvm32_ioreq_typ_t typ; - uvm32_user_ioreq_code_t code; + uvm32_syscall_typ_t typ; + uvm32_user_syscall_code_t code; union { - uvm32_evt_ioreq_buf_t buf; + uvm32_evt_syscall_buf_t buf; uint32_t u32; uint32_t *u32p; } val; -} uvm32_evt_ioreq_t; +} uvm32_evt_syscall_t; typedef struct { uvm32_err_t errcode; @@ -70,7 +70,7 @@ typedef struct { typedef struct { uvm32_evt_typ_t typ; union { - uvm32_evt_ioreq_t ioreq; + uvm32_evt_syscall_t syscall; uvm32_evt_err_t err; } data; } uvm32_evt_t; diff --git a/host-mini/host-mini.c b/host-mini/host-mini.c index fe1e76a..9a86bff 100644 --- a/host-mini/host-mini.c +++ b/host-mini/host-mini.c @@ -5,7 +5,7 @@ #include "../common/uvm32_common_custom.h" // Precompiled binary program to print integers -// This code expects to print via syscall 0x13C (IOREQ_PRINTD in common/uvm32_common_custom.h) +// This code expects to print via syscall 0x13C (UVM32_SYSCALL_PRINTD in common/uvm32_common_custom.h) uint8_t rom[] = { 0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x93, 0x08, 0x80, 0x13, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00, @@ -18,9 +18,9 @@ typedef enum { F_PRINTD, } f_code_t; -// Map VM ioreq IOREQ_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32 +// Map VM syscall UVM32_SYSCALL_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32 const uvm32_mapping_t env[] = { - { .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD }, + { .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD }, }; int main(int argc, char *argv[]) { @@ -38,11 +38,11 @@ int main(int argc, char *argv[]) { case UVM32_EVT_END: isrunning = false; break; - case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ - switch((f_code_t)evt.data.ioreq.code) { + case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL + switch((f_code_t)evt.data.syscall.code) { case F_PRINTD: - // Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in evt.data.ioreq.val.u32 - printf("%d\n", evt.data.ioreq.val.u32); + // Type of F_PRINTD is UVM32_SYSCALL_TYP_U32_WR, so expect value in evt.data.syscall.val.u32 + printf("%d\n", evt.data.syscall.val.u32); break; } break; diff --git a/host-parallel/host-parallel.c b/host-parallel/host-parallel.c index f9f09e0..c6eee6c 100644 --- a/host-parallel/host-parallel.c +++ b/host-parallel/host-parallel.c @@ -13,7 +13,7 @@ #define SCHEDULE_RANDOM() scheduler_index = rand()%NUM_VM // Precompiled binary program to print integers -// This code expects to print via syscall 0x13C (IOREQ_PRINTD in common/uvm32_common_custom.h) +// This code expects to print via syscall 0x13C (UVM32_SYSCALL_PRINTD in common/uvm32_common_custom.h) uint8_t rom[] = { 0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x93, 0x08, 0x80, 0x13, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00, @@ -26,9 +26,9 @@ typedef enum { F_PRINTD, } f_code_t; -// Map VM ioreq IOREQ_PRINTD to F_PRINTD, tell VM to expect write of a U32 +// Map VM syscall UVM32_SYSCALL_PRINTD to F_PRINTD, tell VM to expect write of a U32 const uvm32_mapping_t env[] = { - { .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD }, + { .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD }, }; int main(int argc, char *argv[]) { @@ -55,11 +55,11 @@ int main(int argc, char *argv[]) { printf("[VM %d ended]\n", scheduler_index); numVmRunning--; break; - case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ - switch((f_code_t)evt.data.ioreq.code) { + case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL + switch((f_code_t)evt.data.syscall.code) { case F_PRINTD: - // Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in evt.data.ioreq.val.u32 - printf("[VM %d]: %d\n", scheduler_index, evt.data.ioreq.val.u32); + // Type of F_PRINTD is UVM32_SYSCALL_TYP_U32_WR, so expect value in evt.data.syscall.val.u32 + printf("[VM %d]: %d\n", scheduler_index, evt.data.syscall.val.u32); break; } break; diff --git a/host/host.c b/host/host.c index d6d2cc8..e3f0b5a 100644 --- a/host/host.c +++ b/host/host.c @@ -12,7 +12,7 @@ // stash terminal settings on startup static struct termios orig_termios; -// ioreqs exposed to vm environement +// syscalls exposed to vm environement typedef enum { F_PRINT, F_PRINTD, @@ -23,15 +23,15 @@ typedef enum { F_GETC, } f_code_t; -// Map exposed ioreqs to syscalls +// Map exposed syscalls to syscalls const uvm32_mapping_t env[] = { - { .syscall = IOREQ_PRINTLN, .typ = IOREQ_TYP_BUF_TERMINATED_WR, .code = F_PRINTLN }, - { .syscall = IOREQ_PRINT, .typ = IOREQ_TYP_BUF_TERMINATED_WR, .code = F_PRINT }, - { .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD }, - { .syscall = IOREQ_PRINTX, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTX }, - { .syscall = IOREQ_PRINTC, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTC }, - { .syscall = IOREQ_MILLIS, .typ = IOREQ_TYP_U32_RD, .code = F_MILLIS }, - { .syscall = IOREQ_GETC, .typ = IOREQ_TYP_U32_RD, .code = F_GETC }, + { .syscall = UVM32_SYSCALL_PRINTLN, .typ = UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, .code = F_PRINTLN }, + { .syscall = UVM32_SYSCALL_PRINT, .typ = UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, .code = F_PRINT }, + { .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD }, + { .syscall = UVM32_SYSCALL_PRINTX, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTX }, + { .syscall = UVM32_SYSCALL_PRINTC, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTC }, + { .syscall = UVM32_SYSCALL_MILLIS, .typ = UVM32_SYSCALL_TYP_U32_RD, .code = F_MILLIS }, + { .syscall = UVM32_SYSCALL_GETC, .typ = UVM32_SYSCALL_TYP_U32_RD, .code = F_GETC }, }; void disableRawMode(void) { @@ -159,14 +159,14 @@ int main(int argc, char *argv[]) { uvm32_evt_t evt; bool isrunning = true; uint32_t total_instrs = 0; - uint32_t num_ioreqs = 0; + uint32_t num_syscalls = 0; // setup terminal for getch() enableRawMode(); while(isrunning) { total_instrs += uvm32_run(&vmst, &evt, 1000000); // num instructions before vm considered hung - num_ioreqs++; + num_syscalls++; switch(evt.typ) { case UVM32_EVT_END: @@ -175,57 +175,57 @@ int main(int argc, char *argv[]) { break; case UVM32_EVT_YIELD: //printf("UVM32_EVT_YIELD\n"); - // program has paused, but no ioreq + // program has paused, but no syscall break; case UVM32_EVT_ERR: printf("UVM32_EVT_ERR '%s' (%d)\n", evt.data.err.errstr, (int)evt.data.err.errcode); isrunning = false; break; - case UVM32_EVT_IOREQ: - switch((f_code_t)evt.data.ioreq.code) { + case UVM32_EVT_UVM32_SYSCALL: + switch((f_code_t)evt.data.syscall.code) { case F_PRINT: - printf("%.*s", evt.data.ioreq.val.buf.len, evt.data.ioreq.val.buf.ptr); + printf("%.*s", evt.data.syscall.val.buf.len, evt.data.syscall.val.buf.ptr); break; case F_PRINTLN: - printf("%.*s\n", evt.data.ioreq.val.buf.len, evt.data.ioreq.val.buf.ptr); + printf("%.*s\n", evt.data.syscall.val.buf.len, evt.data.syscall.val.buf.ptr); break; case F_PRINTD: - printf("%d\n", evt.data.ioreq.val.u32); + printf("%d\n", evt.data.syscall.val.u32); break; case F_PRINTC: - printf("%c", evt.data.ioreq.val.u32); + printf("%c", evt.data.syscall.val.u32); break; case F_PRINTX: - printf("%08x", evt.data.ioreq.val.u32); + printf("%08x", evt.data.syscall.val.u32); break; case F_GETC: { uint8_t ch; if (poll_getch(&ch)) { - *evt.data.ioreq.val.u32p = ch; + *evt.data.syscall.val.u32p = ch; } else { - *evt.data.ioreq.val.u32p = 0xFFFFFFFF; // nothing + *evt.data.syscall.val.u32p = 0xFFFFFFFF; // nothing } } break; case F_MILLIS: { clock_t now = clock() / (CLOCKS_PER_SEC / 1000); - *evt.data.ioreq.val.u32p = now - start_time; + *evt.data.syscall.val.u32p = now - start_time; } break; default: // catch any others - switch(evt.data.ioreq.typ) { - case IOREQ_TYP_BUF_TERMINATED_WR: - printf("IOREQ_TYP_BUF_TERMINATED_WR code=%d val=", evt.data.ioreq.code); - hexdump(evt.data.ioreq.val.buf.ptr, evt.data.ioreq.val.buf.len); + switch(evt.data.syscall.typ) { + case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR: + printf("UVM32_SYSCALL_TYP_BUF_TERMINATED_WR code=%d val=", evt.data.syscall.code); + hexdump(evt.data.syscall.val.buf.ptr, evt.data.syscall.val.buf.len); printf("\n"); break; - case IOREQ_TYP_VOID: - printf("IOREQ_TYP_VOID code=%d\n", evt.data.ioreq.code); + case UVM32_SYSCALL_TYP_VOID: + printf("UVM32_SYSCALL_TYP_VOID code=%d\n", evt.data.syscall.code); break; - case IOREQ_TYP_U32_WR: - printf("IOREQ_TYP_U32_WR code=%d val=%d (0x%08x)\n", evt.data.ioreq.code, evt.data.ioreq.val.u32, evt.data.ioreq.val.u32); + case UVM32_SYSCALL_TYP_U32_WR: + printf("UVM32_SYSCALL_TYP_U32_WR code=%d val=%d (0x%08x)\n", evt.data.syscall.code, evt.data.syscall.val.u32, evt.data.syscall.val.u32); break; - case IOREQ_TYP_U32_RD: - printf("IOREQ_TYP_U32_RD code=%d\n", evt.data.ioreq.code); - *evt.data.ioreq.val.u32p = 123456; + case UVM32_SYSCALL_TYP_U32_RD: + printf("UVM32_SYSCALL_TYP_U32_RD code=%d\n", evt.data.syscall.code); + *evt.data.syscall.val.u32p = 123456; break; } break; @@ -239,7 +239,7 @@ int main(int argc, char *argv[]) { fflush(stdout); } - printf("Executed total of %d instructions and %d ioreqs\n", (int)total_instrs, (int)num_ioreqs); + printf("Executed total of %d instructions and %d syscalls\n", (int)total_instrs, (int)num_syscalls); free(rom); diff --git a/uvm32/uvm32.c b/uvm32/uvm32.c index 86d4678..5831bd8 100644 --- a/uvm32/uvm32.c +++ b/uvm32/uvm32.c @@ -67,7 +67,7 @@ bool uvm32_load(uvm32_state_t *vmst, uint8_t *rom, int len) { } // Read C-string up to terminator and return len,ptr -static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t terminator, uvm32_evt_ioreq_buf_t *buf) { +static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t terminator, uvm32_evt_syscall_buf_t *buf) { uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET; uint32_t p = ptrstart; if (p >= UVM32_MEMORY_SIZE) { @@ -90,7 +90,7 @@ static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t t } #if 0 -static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_evt_ioreq_buf_t *buf) { +static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_evt_syscall_buf_t *buf) { uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET; if (ptrstart + len >= UVM32_MEMORY_SIZE) { setStatusErr(vmst, UVM32_ERR_MEM_RD); @@ -103,7 +103,7 @@ static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) { uint32_t num_instr = 0; -// uvm32_evt_ioreq_buf_t b; +// uvm32_evt_syscall_buf_t b; if (vmst->status != UVM32_STATUS_PAUSED) { setStatusErr(vmst, UVM32_ERR_NOTREADY); @@ -127,11 +127,11 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) vmst->core->pc += 4; switch(syscall) { // inbuilt syscalls - case IOREQ_HALT: + case UVM32_SYSCALL_HALT: setStatus(vmst, UVM32_STATUS_ENDED); syscall_valid = true; break; - case IOREQ_YIELD: + case UVM32_SYSCALL_YIELD: vmst->ioevt.typ = UVM32_EVT_YIELD; setStatus(vmst, UVM32_STATUS_PAUSED); syscall_valid = true; @@ -144,22 +144,22 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) if (syscall == vmst->mappings[i].syscall) { // setup ioevt.data according to mapping typ switch(vmst->mappings[i].typ) { - case IOREQ_TYP_VOID: + case UVM32_SYSCALL_TYP_VOID: break; - case IOREQ_TYP_U32_WR: - vmst->ioevt.data.ioreq.val.u32 = value; + case UVM32_SYSCALL_TYP_U32_WR: + vmst->ioevt.data.syscall.val.u32 = value; break; - case IOREQ_TYP_BUF_TERMINATED_WR: - get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.ioreq.val.buf); + case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR: + get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.syscall.val.buf); break; - case IOREQ_TYP_U32_RD: + case UVM32_SYSCALL_TYP_U32_RD: // pass link to r1 for user function to update - vmst->ioevt.data.ioreq.val.u32p = &vmst->core->regs[11]; + vmst->ioevt.data.syscall.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; + vmst->ioevt.typ = UVM32_EVT_UVM32_SYSCALL; + vmst->ioevt.data.syscall.code = vmst->mappings[i].code; + vmst->ioevt.data.syscall.typ = vmst->mappings[i].typ; setStatus(vmst, UVM32_STATUS_PAUSED); syscall_valid = true; break; // stop searching diff --git a/uvm32/uvm32.h b/uvm32/uvm32.h index 9a55b76..786390f 100644 --- a/uvm32/uvm32.h +++ b/uvm32/uvm32.h @@ -4,9 +4,9 @@ #include #include -// "well-known" system IOREQ functions -#define IOREQ_HALT 0x138 -#define IOREQ_YIELD 0x139 +// "well-known" system UVM32_SYSCALL functions +#define UVM32_SYSCALL_HALT 0x138 +#define UVM32_SYSCALL_YIELD 0x139 #define LIST_OF_UVM32_ERRS \ X(UVM32_ERR_NONE) \ @@ -26,41 +26,41 @@ typedef enum { typedef enum { UVM32_EVT_ERR, - UVM32_EVT_IOREQ, + UVM32_EVT_UVM32_SYSCALL, UVM32_EVT_YIELD, UVM32_EVT_END, } uvm32_evt_typ_t; typedef enum { - IOREQ_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_ioreq_t.val.buf - IOREQ_TYP_VOID, // no data - IOREQ_TYP_U32_WR, // data write from vm, in uvm32_evt_ioreq_t.val.u32 - IOREQ_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_ioreq_t.val.u32p -} uvm32_ioreq_typ_t; + UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_syscall_t.val.buf + UVM32_SYSCALL_TYP_VOID, // no data + UVM32_SYSCALL_TYP_U32_WR, // data write from vm, in uvm32_evt_syscall_t.val.u32 + UVM32_SYSCALL_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_syscall_t.val.u32p +} uvm32_syscall_typ_t; -typedef uint32_t uvm32_user_ioreq_code_t; +typedef uint32_t uvm32_user_syscall_code_t; -// user supplied mapping from syscall to typed ioreq +// user supplied mapping from syscall to typed syscall typedef struct { uint32_t syscall; - uvm32_user_ioreq_code_t code; - uvm32_ioreq_typ_t typ; + uvm32_user_syscall_code_t code; + uvm32_syscall_typ_t typ; } uvm32_mapping_t; typedef struct { uint8_t *ptr; uint32_t len; -} uvm32_evt_ioreq_buf_t; +} uvm32_evt_syscall_buf_t; typedef struct { - uvm32_ioreq_typ_t typ; - uvm32_user_ioreq_code_t code; + uvm32_syscall_typ_t typ; + uvm32_user_syscall_code_t code; union { - uvm32_evt_ioreq_buf_t buf; + uvm32_evt_syscall_buf_t buf; uint32_t u32; uint32_t *u32p; } val; -} uvm32_evt_ioreq_t; +} uvm32_evt_syscall_t; typedef struct { uvm32_err_t errcode; @@ -70,7 +70,7 @@ typedef struct { typedef struct { uvm32_evt_typ_t typ; union { - uvm32_evt_ioreq_t ioreq; + uvm32_evt_syscall_t syscall; uvm32_evt_err_t err; } data; } uvm32_evt_t;