mirror of
https://github.com/ringtailsoftware/uvm32.git
synced 2026-06-05 22:43:39 +00:00
Rename ioreq to syscall
This commit is contained in:
parent
b79a107a3d
commit
61fe0e8647
20 changed files with 187 additions and 190 deletions
32
README.md
32
README.md
|
|
@ -15,7 +15,7 @@ Although based on a fully fledged CPU emulator, uvm32 is intended for executing
|
||||||
|
|
||||||
## Samples
|
## 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-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-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)
|
* [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)
|
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.
|
`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.
|
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)
|
(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_END` the program has ended
|
||||||
* `UVM32_EVT_ERR` the program has encountered an error
|
* `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_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
|
## Internals
|
||||||
|
|
||||||
|
|
@ -92,7 +92,7 @@ uvm32 is always in one of 4 states, paused, running, ended or error.
|
||||||
stateDiagram
|
stateDiagram
|
||||||
[*] --> UVM32_STATUS_PAUSED : uvm32_init()
|
[*] --> UVM32_STATUS_PAUSED : uvm32_init()
|
||||||
UVM32_STATUS_PAUSED-->UVM32_STATUS_RUNNING : uvm32_run()
|
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_ENDED : halt()
|
||||||
UVM32_STATUS_RUNNING --> UVM32_STATUS_ERROR
|
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.
|
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)
|
[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.
|
`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()`.
|
New syscalls 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.
|
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)
|
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"
|
#include "../common/uvm32_common_custom.h"
|
||||||
|
|
||||||
// Precompiled binary program to print integers
|
// 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[] = {
|
uint8_t rom[] = {
|
||||||
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x73, 0x50, 0x80, 0x13,
|
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x73, 0x50, 0x80, 0x13,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x07, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x07, 0x00, 0x00,
|
||||||
|
|
@ -159,9 +159,9 @@ typedef enum {
|
||||||
F_PRINTD,
|
F_PRINTD,
|
||||||
} f_code_t;
|
} 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[] = {
|
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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
@ -179,11 +179,11 @@ int main(int argc, char *argv[]) {
|
||||||
case UVM32_EVT_END:
|
case UVM32_EVT_END:
|
||||||
isrunning = false;
|
isrunning = false;
|
||||||
break;
|
break;
|
||||||
case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ
|
case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL
|
||||||
switch((f_code_t)evt.data.ioreq.code) {
|
switch((f_code_t)evt.data.syscall.code) {
|
||||||
case F_PRINTD:
|
case F_PRINTD:
|
||||||
// Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in 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.ioreq.val.u32);
|
printf("%d\n", evt.data.syscall.val.u32);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ jal ra, main
|
||||||
#include "non-rust-crt0-hack.S"
|
#include "non-rust-crt0-hack.S"
|
||||||
#else
|
#else
|
||||||
// only rust will see this
|
// only rust will see this
|
||||||
li a7, {IOREQ_HALT}
|
li a7, {UVM32_SYSCALL_HALT}
|
||||||
#endif
|
#endif
|
||||||
ecall
|
ecall
|
||||||
.section .data
|
.section .data
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
la a0, str
|
la a0, str
|
||||||
li a7, IOREQ_PRINTLN
|
li a7, UVM32_SYSCALL_PRINTLN
|
||||||
ecall
|
ecall
|
||||||
li a7, IOREQ_HALT
|
li a7, UVM32_SYSCALL_HALT
|
||||||
ecall
|
ecall
|
||||||
str:
|
str:
|
||||||
.ascii "Hi\0"
|
.ascii "Hi\0"
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
li a7,IOREQ_HALT
|
li a7,UVM32_SYSCALL_HALT
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ use core::arch::global_asm;
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
// fetch IOREQ definitions from C header
|
// fetch UVM32_SYSCALL definitions from C header
|
||||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||||
|
|
||||||
// startup code
|
// 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 {
|
fn syscall(id: u32, n: u32) -> u32 {
|
||||||
let mut value;
|
let mut value;
|
||||||
|
|
@ -25,11 +25,11 @@ fn syscall(id: u32, n: u32) -> u32 {
|
||||||
|
|
||||||
fn println(message: &str) {
|
fn println(message: &str) {
|
||||||
let addr_value = message.as_ptr() as u32;
|
let addr_value = message.as_ptr() as u32;
|
||||||
syscall(IOREQ_PRINTLN, addr_value);
|
syscall(UVM32_SYSCALL_PRINTLN, addr_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn printd(n: u32) {
|
fn printd(n: u32) {
|
||||||
syscall(IOREQ_PRINTD, n);
|
syscall(UVM32_SYSCALL_PRINTD, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,14 @@ pub inline fn syscall(id: u32, param: u32) u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn println(val: [:0]const u8) void {
|
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 {
|
pub inline fn yield() void {
|
||||||
_ = syscall(uvm32.IOREQ_YIELD, 0);
|
_ = syscall(uvm32.UVM32_SYSCALL_YIELD, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn printc(c:u8) void {
|
pub inline fn printc(c:u8) void {
|
||||||
_ = syscall(uvm32.IOREQ_PRINTC, c);
|
_ = syscall(uvm32.UVM32_SYSCALL_PRINTC, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub inline fn syscall(id: u32, param: u32) u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn getch() ?u8 {
|
pub inline fn getch() ?u8 {
|
||||||
const key = syscall(uvm32.IOREQ_GETC, 0);
|
const key = syscall(uvm32.UVM32_SYSCALL_GETC, 0);
|
||||||
if (key == 0xFFFFFFFF) {
|
if (key == 0xFFFFFFFF) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -24,7 +24,7 @@ pub inline fn getch() ?u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn millis() u32 {
|
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
|
// 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);
|
@memcpy(termination_buf[0..m.len], m);
|
||||||
termination_buf[m.len] = 0;
|
termination_buf[m.len] = 0;
|
||||||
const s = termination_buf[0..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 {
|
pub inline fn println(m: []const u8) void {
|
||||||
@memcpy(termination_buf[0..m.len], m);
|
@memcpy(termination_buf[0..m.len], m);
|
||||||
termination_buf[m.len] = 0;
|
termination_buf[m.len] = 0;
|
||||||
const s = termination_buf[0..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 {
|
pub inline fn yield() void {
|
||||||
_ = syscall(uvm32.IOREQ_YIELD, 0);
|
_ = syscall(uvm32.UVM32_SYSCALL_YIELD, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn printc(c:u8) void {
|
pub inline fn printc(c:u8) void {
|
||||||
_ = syscall(uvm32.IOREQ_PRINTC, c);
|
_ = syscall(uvm32.UVM32_SYSCALL_PRINTC, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
// Definitions needed by both host and target
|
// Definitions needed by both host and target
|
||||||
|
|
||||||
// syscalls for exposed host functions
|
// syscalls for exposed host functions
|
||||||
#define IOREQ_PRINT 0x13A
|
#define UVM32_SYSCALL_PRINT 0x13A
|
||||||
#define IOREQ_PRINTLN 0x13B
|
#define UVM32_SYSCALL_PRINTLN 0x13B
|
||||||
#define IOREQ_PRINTD 0x13C
|
#define UVM32_SYSCALL_PRINTD 0x13C
|
||||||
#define IOREQ_PRINTX 0x13D
|
#define UVM32_SYSCALL_PRINTX 0x13D
|
||||||
#define IOREQ_MILLIS 0x13F
|
#define UVM32_SYSCALL_MILLIS 0x13F
|
||||||
#define IOREQ_PRINTC 0x140
|
#define UVM32_SYSCALL_PRINTC 0x140
|
||||||
#define IOREQ_GETC 0x141
|
#define UVM32_SYSCALL_GETC 0x141
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// System provided IOREQs
|
// System provided UVM32_SYSCALLs
|
||||||
#define IOREQ_HALT 0x138
|
#define UVM32_SYSCALL_HALT 0x138
|
||||||
#define IOREQ_YIELD 0x139
|
#define UVM32_SYSCALL_YIELD 0x139
|
||||||
|
|
||||||
#include "uvm32_common_custom.h"
|
#include "uvm32_common_custom.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 syscall_cast(id, x) syscall((uint32_t)id, (uint32_t)x)
|
||||||
#define println(x) syscall_cast(IOREQ_PRINTLN, x)
|
#define println(x) syscall_cast(UVM32_SYSCALL_PRINTLN, x)
|
||||||
#define print(x) syscall_cast(IOREQ_PRINT, x)
|
#define print(x) syscall_cast(UVM32_SYSCALL_PRINT, x)
|
||||||
#define printd(x) syscall_cast(IOREQ_PRINTD, x)
|
#define printd(x) syscall_cast(UVM32_SYSCALL_PRINTD, x)
|
||||||
#define printx(x) syscall_cast(IOREQ_PRINTX, x)
|
#define printx(x) syscall_cast(UVM32_SYSCALL_PRINTX, x)
|
||||||
#define millis() syscall_cast(IOREQ_MILLIS, 0)
|
#define millis() syscall_cast(UVM32_SYSCALL_MILLIS, 0)
|
||||||
#define printc() syscall_cast(IOREQ_PRINTC, 0)
|
#define printc() syscall_cast(UVM32_SYSCALL_PRINTC, 0)
|
||||||
#define getc() syscall_cast(IOREQ_GETC, 0)
|
#define getc() syscall_cast(UVM32_SYSCALL_GETC, 0)
|
||||||
#define yield() syscall_cast(IOREQ_YIELD, 0)
|
#define yield() syscall_cast(UVM32_SYSCALL_YIELD, 0)
|
||||||
|
|
||||||
#include "uvm32_common_custom.h"
|
#include "uvm32_common_custom.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
// Definitions needed by both host and target
|
// Definitions needed by both host and target
|
||||||
|
|
||||||
// CSRs for exposed host functions
|
// CSRs for exposed host functions
|
||||||
#define IOREQ_PRINT 0x13A
|
#define UVM32_SYSCALL_PRINT 0x13A
|
||||||
#define IOREQ_PRINTLN 0x13B
|
#define UVM32_SYSCALL_PRINTLN 0x13B
|
||||||
#define IOREQ_PRINTD 0x13C
|
#define UVM32_SYSCALL_PRINTD 0x13C
|
||||||
#define IOREQ_PRINTX 0x13D
|
#define UVM32_SYSCALL_PRINTX 0x13D
|
||||||
#define IOREQ_MILLIS 0x13F
|
#define UVM32_SYSCALL_MILLIS 0x13F
|
||||||
#define IOREQ_PRINTC 0x140
|
#define UVM32_SYSCALL_PRINTC 0x140
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// System provided IOREQs
|
// System provided UVM32_SYSCALLs
|
||||||
#define IOREQ_HALT 0x138
|
#define UVM32_SYSCALL_HALT 0x138
|
||||||
#define IOREQ_YIELD 0x139
|
#define UVM32_SYSCALL_YIELD 0x139
|
||||||
|
|
||||||
#include "uvm32_common_custom.h"
|
#include "uvm32_common_custom.h"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "common/uvm32_common_custom.h"
|
#include "common/uvm32_common_custom.h"
|
||||||
|
|
||||||
// Precompiled binary program to print integers
|
// 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[] = {
|
uint8_t rom[] = {
|
||||||
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0xc0, 0x00, 0x93, 0x08, 0x80, 0x13,
|
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0xc0, 0x00, 0x93, 0x08, 0x80, 0x13,
|
||||||
0x73, 0x00, 0x00, 0x00, 0x37, 0xf5, 0xff, 0xff, 0xb7, 0x15, 0x00, 0x00,
|
0x73, 0x00, 0x00, 0x00, 0x37, 0xf5, 0xff, 0xff, 0xb7, 0x15, 0x00, 0x00,
|
||||||
|
|
@ -34,11 +34,11 @@ typedef enum {
|
||||||
F_PRINTC,
|
F_PRINTC,
|
||||||
} f_code_t;
|
} 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[] = {
|
const uvm32_mapping_t env[] = {
|
||||||
{ IOREQ_PRINTD, F_PRINTD, IOREQ_TYP_U32_WR },
|
{ UVM32_SYSCALL_PRINTD, F_PRINTD, UVM32_SYSCALL_TYP_U32_WR },
|
||||||
{ IOREQ_PRINTC, F_PRINTC, IOREQ_TYP_U32_WR },
|
{ UVM32_SYSCALL_PRINTC, F_PRINTC, UVM32_SYSCALL_TYP_U32_WR },
|
||||||
{ IOREQ_PRINTLN, F_PRINTLN, IOREQ_TYP_BUF_TERMINATED_WR },
|
{ UVM32_SYSCALL_PRINTLN, F_PRINTLN, UVM32_SYSCALL_TYP_BUF_TERMINATED_WR },
|
||||||
};
|
};
|
||||||
|
|
||||||
uvm32_state_t vmst;
|
uvm32_state_t vmst;
|
||||||
|
|
@ -68,17 +68,17 @@ void loop(void) {
|
||||||
case UVM32_EVT_END:
|
case UVM32_EVT_END:
|
||||||
isrunning = false;
|
isrunning = false;
|
||||||
break;
|
break;
|
||||||
case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ
|
case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL
|
||||||
switch((f_code_t)evt.data.ioreq.code) {
|
switch((f_code_t)evt.data.syscall.code) {
|
||||||
case F_PRINTD:
|
case F_PRINTD:
|
||||||
Serial.println(evt.data.ioreq.val.u32);
|
Serial.println(evt.data.syscall.val.u32);
|
||||||
break;
|
break;
|
||||||
case F_PRINTC:
|
case F_PRINTC:
|
||||||
Serial.print((char)evt.data.ioreq.val.u32);
|
Serial.print((char)evt.data.syscall.val.u32);
|
||||||
break;
|
break;
|
||||||
case F_PRINTLN:
|
case F_PRINTLN:
|
||||||
for (int i=0;i<evt.data.ioreq.val.buf.len;i++) {
|
for (int i=0;i<evt.data.syscall.val.buf.len;i++) {
|
||||||
Serial.print((char)evt.data.ioreq.val.buf.ptr[i]);
|
Serial.print((char)evt.data.syscall.val.buf.ptr[i]);
|
||||||
}
|
}
|
||||||
Serial.println("");
|
Serial.println("");
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ bool uvm32_load(uvm32_state_t *vmst, uint8_t *rom, int len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read C-string up to terminator and return len,ptr
|
// 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 ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET;
|
||||||
uint32_t p = ptrstart;
|
uint32_t p = ptrstart;
|
||||||
if (p >= UVM32_MEMORY_SIZE) {
|
if (p >= UVM32_MEMORY_SIZE) {
|
||||||
|
|
@ -91,7 +91,7 @@ static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t t
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#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;
|
uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET;
|
||||||
if (ptrstart + len >= UVM32_MEMORY_SIZE) {
|
if (ptrstart + len >= UVM32_MEMORY_SIZE) {
|
||||||
setStatusErr(vmst, UVM32_ERR_MEM_RD);
|
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 uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) {
|
||||||
uint32_t num_instr = 0;
|
uint32_t num_instr = 0;
|
||||||
// uvm32_evt_ioreq_buf_t b;
|
// uvm32_evt_syscall_buf_t b;
|
||||||
|
|
||||||
if (vmst->status != UVM32_STATUS_PAUSED) {
|
if (vmst->status != UVM32_STATUS_PAUSED) {
|
||||||
setStatusErr(vmst, UVM32_ERR_NOTREADY);
|
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;
|
vmst->core->pc += 4;
|
||||||
switch(syscall) {
|
switch(syscall) {
|
||||||
// inbuilt syscalls
|
// inbuilt syscalls
|
||||||
case IOREQ_HALT:
|
case UVM32_SYSCALL_HALT:
|
||||||
setStatus(vmst, UVM32_STATUS_ENDED);
|
setStatus(vmst, UVM32_STATUS_ENDED);
|
||||||
syscall_valid = true;
|
syscall_valid = true;
|
||||||
break;
|
break;
|
||||||
case IOREQ_YIELD:
|
case UVM32_SYSCALL_YIELD:
|
||||||
vmst->ioevt.typ = UVM32_EVT_YIELD;
|
vmst->ioevt.typ = UVM32_EVT_YIELD;
|
||||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||||
syscall_valid = true;
|
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) {
|
if (syscall == vmst->mappings[i].syscall) {
|
||||||
// setup ioevt.data according to mapping typ
|
// setup ioevt.data according to mapping typ
|
||||||
switch(vmst->mappings[i].typ) {
|
switch(vmst->mappings[i].typ) {
|
||||||
case IOREQ_TYP_VOID:
|
case UVM32_SYSCALL_TYP_VOID:
|
||||||
break;
|
break;
|
||||||
case IOREQ_TYP_U32_WR:
|
case UVM32_SYSCALL_TYP_U32_WR:
|
||||||
vmst->ioevt.data.ioreq.val.u32 = value;
|
vmst->ioevt.data.syscall.val.u32 = value;
|
||||||
break;
|
break;
|
||||||
case IOREQ_TYP_BUF_TERMINATED_WR:
|
case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR:
|
||||||
get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.ioreq.val.buf);
|
get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.syscall.val.buf);
|
||||||
break;
|
break;
|
||||||
case IOREQ_TYP_U32_RD:
|
case UVM32_SYSCALL_TYP_U32_RD:
|
||||||
// get_safeptr(vmst, value, 4, &b);
|
vmst->ioevt.data.syscall.val.u32p = &vmst->core->regs[11];
|
||||||
vmst->ioevt.data.ioreq.val.u32p = &vmst->core->regs[11]; // r1, //(uint32_t *)b.ptr;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vmst->ioevt.typ = UVM32_EVT_IOREQ;
|
vmst->ioevt.typ = UVM32_EVT_UVM32_SYSCALL;
|
||||||
vmst->ioevt.data.ioreq.code = vmst->mappings[i].code;
|
vmst->ioevt.data.syscall.code = vmst->mappings[i].code;
|
||||||
vmst->ioevt.data.ioreq.typ = vmst->mappings[i].typ;
|
vmst->ioevt.data.syscall.typ = vmst->mappings[i].typ;
|
||||||
//#warning FIXME, retval
|
|
||||||
// vmst->core->regs[11] = 456; // r1
|
|
||||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||||
syscall_valid = true;
|
syscall_valid = true;
|
||||||
break; // stop searching
|
break; // stop searching
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// "well-known" system IOREQ functions
|
// "well-known" system UVM32_SYSCALL functions
|
||||||
#define IOREQ_HALT 0x138
|
#define UVM32_SYSCALL_HALT 0x138
|
||||||
#define IOREQ_YIELD 0x139
|
#define UVM32_SYSCALL_YIELD 0x139
|
||||||
|
|
||||||
#define LIST_OF_UVM32_ERRS \
|
#define LIST_OF_UVM32_ERRS \
|
||||||
X(UVM32_ERR_NONE) \
|
X(UVM32_ERR_NONE) \
|
||||||
|
|
@ -26,41 +26,41 @@ typedef enum {
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UVM32_EVT_ERR,
|
UVM32_EVT_ERR,
|
||||||
UVM32_EVT_IOREQ,
|
UVM32_EVT_UVM32_SYSCALL,
|
||||||
UVM32_EVT_YIELD,
|
UVM32_EVT_YIELD,
|
||||||
UVM32_EVT_END,
|
UVM32_EVT_END,
|
||||||
} uvm32_evt_typ_t;
|
} uvm32_evt_typ_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
IOREQ_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_ioreq_t.val.buf
|
UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_syscall_t.val.buf
|
||||||
IOREQ_TYP_VOID, // no data
|
UVM32_SYSCALL_TYP_VOID, // no data
|
||||||
IOREQ_TYP_U32_WR, // data write from vm, in uvm32_evt_ioreq_t.val.u32
|
UVM32_SYSCALL_TYP_U32_WR, // data write from vm, in uvm32_evt_syscall_t.val.u32
|
||||||
IOREQ_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_ioreq_t.val.u32p
|
UVM32_SYSCALL_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_syscall_t.val.u32p
|
||||||
} uvm32_ioreq_typ_t;
|
} 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 {
|
typedef struct {
|
||||||
uint32_t syscall;
|
uint32_t syscall;
|
||||||
uvm32_user_ioreq_code_t code;
|
uvm32_user_syscall_code_t code;
|
||||||
uvm32_ioreq_typ_t typ;
|
uvm32_syscall_typ_t typ;
|
||||||
} uvm32_mapping_t;
|
} uvm32_mapping_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
} uvm32_evt_ioreq_buf_t;
|
} uvm32_evt_syscall_buf_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uvm32_ioreq_typ_t typ;
|
uvm32_syscall_typ_t typ;
|
||||||
uvm32_user_ioreq_code_t code;
|
uvm32_user_syscall_code_t code;
|
||||||
union {
|
union {
|
||||||
uvm32_evt_ioreq_buf_t buf;
|
uvm32_evt_syscall_buf_t buf;
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
uint32_t *u32p;
|
uint32_t *u32p;
|
||||||
} val;
|
} val;
|
||||||
} uvm32_evt_ioreq_t;
|
} uvm32_evt_syscall_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uvm32_err_t errcode;
|
uvm32_err_t errcode;
|
||||||
|
|
@ -70,7 +70,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uvm32_evt_typ_t typ;
|
uvm32_evt_typ_t typ;
|
||||||
union {
|
union {
|
||||||
uvm32_evt_ioreq_t ioreq;
|
uvm32_evt_syscall_t syscall;
|
||||||
uvm32_evt_err_t err;
|
uvm32_evt_err_t err;
|
||||||
} data;
|
} data;
|
||||||
} uvm32_evt_t;
|
} uvm32_evt_t;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#include "../common/uvm32_common_custom.h"
|
#include "../common/uvm32_common_custom.h"
|
||||||
|
|
||||||
// Precompiled binary program to print integers
|
// 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[] = {
|
uint8_t rom[] = {
|
||||||
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x93, 0x08, 0x80, 0x13,
|
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x93, 0x08, 0x80, 0x13,
|
||||||
0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00,
|
0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00,
|
||||||
|
|
@ -18,9 +18,9 @@ typedef enum {
|
||||||
F_PRINTD,
|
F_PRINTD,
|
||||||
} f_code_t;
|
} 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[] = {
|
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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
@ -38,11 +38,11 @@ int main(int argc, char *argv[]) {
|
||||||
case UVM32_EVT_END:
|
case UVM32_EVT_END:
|
||||||
isrunning = false;
|
isrunning = false;
|
||||||
break;
|
break;
|
||||||
case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ
|
case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL
|
||||||
switch((f_code_t)evt.data.ioreq.code) {
|
switch((f_code_t)evt.data.syscall.code) {
|
||||||
case F_PRINTD:
|
case F_PRINTD:
|
||||||
// Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in 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.ioreq.val.u32);
|
printf("%d\n", evt.data.syscall.val.u32);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
#define SCHEDULE_RANDOM() scheduler_index = rand()%NUM_VM
|
#define SCHEDULE_RANDOM() scheduler_index = rand()%NUM_VM
|
||||||
|
|
||||||
// Precompiled binary program to print integers
|
// 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[] = {
|
uint8_t rom[] = {
|
||||||
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x93, 0x08, 0x80, 0x13,
|
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x93, 0x08, 0x80, 0x13,
|
||||||
0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00,
|
0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00,
|
||||||
|
|
@ -26,9 +26,9 @@ typedef enum {
|
||||||
F_PRINTD,
|
F_PRINTD,
|
||||||
} f_code_t;
|
} 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[] = {
|
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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
@ -55,11 +55,11 @@ int main(int argc, char *argv[]) {
|
||||||
printf("[VM %d ended]\n", scheduler_index);
|
printf("[VM %d ended]\n", scheduler_index);
|
||||||
numVmRunning--;
|
numVmRunning--;
|
||||||
break;
|
break;
|
||||||
case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ
|
case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL
|
||||||
switch((f_code_t)evt.data.ioreq.code) {
|
switch((f_code_t)evt.data.syscall.code) {
|
||||||
case F_PRINTD:
|
case F_PRINTD:
|
||||||
// Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in 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.ioreq.val.u32);
|
printf("[VM %d]: %d\n", scheduler_index, evt.data.syscall.val.u32);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
68
host/host.c
68
host/host.c
|
|
@ -12,7 +12,7 @@
|
||||||
// stash terminal settings on startup
|
// stash terminal settings on startup
|
||||||
static struct termios orig_termios;
|
static struct termios orig_termios;
|
||||||
|
|
||||||
// ioreqs exposed to vm environement
|
// syscalls exposed to vm environement
|
||||||
typedef enum {
|
typedef enum {
|
||||||
F_PRINT,
|
F_PRINT,
|
||||||
F_PRINTD,
|
F_PRINTD,
|
||||||
|
|
@ -23,15 +23,15 @@ typedef enum {
|
||||||
F_GETC,
|
F_GETC,
|
||||||
} f_code_t;
|
} f_code_t;
|
||||||
|
|
||||||
// Map exposed ioreqs to syscalls
|
// Map exposed syscalls to syscalls
|
||||||
const uvm32_mapping_t env[] = {
|
const uvm32_mapping_t env[] = {
|
||||||
{ .syscall = IOREQ_PRINTLN, .typ = IOREQ_TYP_BUF_TERMINATED_WR, .code = F_PRINTLN },
|
{ .syscall = UVM32_SYSCALL_PRINTLN, .typ = UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, .code = F_PRINTLN },
|
||||||
{ .syscall = IOREQ_PRINT, .typ = IOREQ_TYP_BUF_TERMINATED_WR, .code = F_PRINT },
|
{ .syscall = UVM32_SYSCALL_PRINT, .typ = UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, .code = F_PRINT },
|
||||||
{ .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD },
|
{ .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD },
|
||||||
{ .syscall = IOREQ_PRINTX, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTX },
|
{ .syscall = UVM32_SYSCALL_PRINTX, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTX },
|
||||||
{ .syscall = IOREQ_PRINTC, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTC },
|
{ .syscall = UVM32_SYSCALL_PRINTC, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTC },
|
||||||
{ .syscall = IOREQ_MILLIS, .typ = IOREQ_TYP_U32_RD, .code = F_MILLIS },
|
{ .syscall = UVM32_SYSCALL_MILLIS, .typ = UVM32_SYSCALL_TYP_U32_RD, .code = F_MILLIS },
|
||||||
{ .syscall = IOREQ_GETC, .typ = IOREQ_TYP_U32_RD, .code = F_GETC },
|
{ .syscall = UVM32_SYSCALL_GETC, .typ = UVM32_SYSCALL_TYP_U32_RD, .code = F_GETC },
|
||||||
};
|
};
|
||||||
|
|
||||||
void disableRawMode(void) {
|
void disableRawMode(void) {
|
||||||
|
|
@ -159,14 +159,14 @@ int main(int argc, char *argv[]) {
|
||||||
uvm32_evt_t evt;
|
uvm32_evt_t evt;
|
||||||
bool isrunning = true;
|
bool isrunning = true;
|
||||||
uint32_t total_instrs = 0;
|
uint32_t total_instrs = 0;
|
||||||
uint32_t num_ioreqs = 0;
|
uint32_t num_syscalls = 0;
|
||||||
|
|
||||||
// setup terminal for getch()
|
// setup terminal for getch()
|
||||||
enableRawMode();
|
enableRawMode();
|
||||||
|
|
||||||
while(isrunning) {
|
while(isrunning) {
|
||||||
total_instrs += uvm32_run(&vmst, &evt, 1000000); // num instructions before vm considered hung
|
total_instrs += uvm32_run(&vmst, &evt, 1000000); // num instructions before vm considered hung
|
||||||
num_ioreqs++;
|
num_syscalls++;
|
||||||
|
|
||||||
switch(evt.typ) {
|
switch(evt.typ) {
|
||||||
case UVM32_EVT_END:
|
case UVM32_EVT_END:
|
||||||
|
|
@ -175,57 +175,57 @@ int main(int argc, char *argv[]) {
|
||||||
break;
|
break;
|
||||||
case UVM32_EVT_YIELD:
|
case UVM32_EVT_YIELD:
|
||||||
//printf("UVM32_EVT_YIELD\n");
|
//printf("UVM32_EVT_YIELD\n");
|
||||||
// program has paused, but no ioreq
|
// program has paused, but no syscall
|
||||||
break;
|
break;
|
||||||
case UVM32_EVT_ERR:
|
case UVM32_EVT_ERR:
|
||||||
printf("UVM32_EVT_ERR '%s' (%d)\n", evt.data.err.errstr, (int)evt.data.err.errcode);
|
printf("UVM32_EVT_ERR '%s' (%d)\n", evt.data.err.errstr, (int)evt.data.err.errcode);
|
||||||
isrunning = false;
|
isrunning = false;
|
||||||
break;
|
break;
|
||||||
case UVM32_EVT_IOREQ:
|
case UVM32_EVT_UVM32_SYSCALL:
|
||||||
switch((f_code_t)evt.data.ioreq.code) {
|
switch((f_code_t)evt.data.syscall.code) {
|
||||||
case F_PRINT:
|
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;
|
break;
|
||||||
case F_PRINTLN:
|
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;
|
break;
|
||||||
case F_PRINTD:
|
case F_PRINTD:
|
||||||
printf("%d\n", evt.data.ioreq.val.u32);
|
printf("%d\n", evt.data.syscall.val.u32);
|
||||||
break;
|
break;
|
||||||
case F_PRINTC:
|
case F_PRINTC:
|
||||||
printf("%c", evt.data.ioreq.val.u32);
|
printf("%c", evt.data.syscall.val.u32);
|
||||||
break;
|
break;
|
||||||
case F_PRINTX:
|
case F_PRINTX:
|
||||||
printf("%08x", evt.data.ioreq.val.u32);
|
printf("%08x", evt.data.syscall.val.u32);
|
||||||
break;
|
break;
|
||||||
case F_GETC: {
|
case F_GETC: {
|
||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
if (poll_getch(&ch)) {
|
if (poll_getch(&ch)) {
|
||||||
*evt.data.ioreq.val.u32p = ch;
|
*evt.data.syscall.val.u32p = ch;
|
||||||
} else {
|
} else {
|
||||||
*evt.data.ioreq.val.u32p = 0xFFFFFFFF; // nothing
|
*evt.data.syscall.val.u32p = 0xFFFFFFFF; // nothing
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case F_MILLIS: {
|
case F_MILLIS: {
|
||||||
clock_t now = clock() / (CLOCKS_PER_SEC / 1000);
|
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;
|
} break;
|
||||||
default: // catch any others
|
default: // catch any others
|
||||||
switch(evt.data.ioreq.typ) {
|
switch(evt.data.syscall.typ) {
|
||||||
case IOREQ_TYP_BUF_TERMINATED_WR:
|
case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR:
|
||||||
printf("IOREQ_TYP_BUF_TERMINATED_WR code=%d val=", evt.data.ioreq.code);
|
printf("UVM32_SYSCALL_TYP_BUF_TERMINATED_WR code=%d val=", evt.data.syscall.code);
|
||||||
hexdump(evt.data.ioreq.val.buf.ptr, evt.data.ioreq.val.buf.len);
|
hexdump(evt.data.syscall.val.buf.ptr, evt.data.syscall.val.buf.len);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
break;
|
break;
|
||||||
case IOREQ_TYP_VOID:
|
case UVM32_SYSCALL_TYP_VOID:
|
||||||
printf("IOREQ_TYP_VOID code=%d\n", evt.data.ioreq.code);
|
printf("UVM32_SYSCALL_TYP_VOID code=%d\n", evt.data.syscall.code);
|
||||||
break;
|
break;
|
||||||
case IOREQ_TYP_U32_WR:
|
case UVM32_SYSCALL_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);
|
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;
|
break;
|
||||||
case IOREQ_TYP_U32_RD:
|
case UVM32_SYSCALL_TYP_U32_RD:
|
||||||
printf("IOREQ_TYP_U32_RD code=%d\n", evt.data.ioreq.code);
|
printf("UVM32_SYSCALL_TYP_U32_RD code=%d\n", evt.data.syscall.code);
|
||||||
*evt.data.ioreq.val.u32p = 123456;
|
*evt.data.syscall.val.u32p = 123456;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -239,7 +239,7 @@ int main(int argc, char *argv[]) {
|
||||||
fflush(stdout);
|
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);
|
free(rom);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
// 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 ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET;
|
||||||
uint32_t p = ptrstart;
|
uint32_t p = ptrstart;
|
||||||
if (p >= UVM32_MEMORY_SIZE) {
|
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
|
#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;
|
uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET;
|
||||||
if (ptrstart + len >= UVM32_MEMORY_SIZE) {
|
if (ptrstart + len >= UVM32_MEMORY_SIZE) {
|
||||||
setStatusErr(vmst, UVM32_ERR_MEM_RD);
|
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 uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) {
|
||||||
uint32_t num_instr = 0;
|
uint32_t num_instr = 0;
|
||||||
// uvm32_evt_ioreq_buf_t b;
|
// uvm32_evt_syscall_buf_t b;
|
||||||
|
|
||||||
if (vmst->status != UVM32_STATUS_PAUSED) {
|
if (vmst->status != UVM32_STATUS_PAUSED) {
|
||||||
setStatusErr(vmst, UVM32_ERR_NOTREADY);
|
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;
|
vmst->core->pc += 4;
|
||||||
switch(syscall) {
|
switch(syscall) {
|
||||||
// inbuilt syscalls
|
// inbuilt syscalls
|
||||||
case IOREQ_HALT:
|
case UVM32_SYSCALL_HALT:
|
||||||
setStatus(vmst, UVM32_STATUS_ENDED);
|
setStatus(vmst, UVM32_STATUS_ENDED);
|
||||||
syscall_valid = true;
|
syscall_valid = true;
|
||||||
break;
|
break;
|
||||||
case IOREQ_YIELD:
|
case UVM32_SYSCALL_YIELD:
|
||||||
vmst->ioevt.typ = UVM32_EVT_YIELD;
|
vmst->ioevt.typ = UVM32_EVT_YIELD;
|
||||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||||
syscall_valid = true;
|
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) {
|
if (syscall == vmst->mappings[i].syscall) {
|
||||||
// setup ioevt.data according to mapping typ
|
// setup ioevt.data according to mapping typ
|
||||||
switch(vmst->mappings[i].typ) {
|
switch(vmst->mappings[i].typ) {
|
||||||
case IOREQ_TYP_VOID:
|
case UVM32_SYSCALL_TYP_VOID:
|
||||||
break;
|
break;
|
||||||
case IOREQ_TYP_U32_WR:
|
case UVM32_SYSCALL_TYP_U32_WR:
|
||||||
vmst->ioevt.data.ioreq.val.u32 = value;
|
vmst->ioevt.data.syscall.val.u32 = value;
|
||||||
break;
|
break;
|
||||||
case IOREQ_TYP_BUF_TERMINATED_WR:
|
case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR:
|
||||||
get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.ioreq.val.buf);
|
get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.syscall.val.buf);
|
||||||
break;
|
break;
|
||||||
case IOREQ_TYP_U32_RD:
|
case UVM32_SYSCALL_TYP_U32_RD:
|
||||||
// pass link to r1 for user function to update
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
vmst->ioevt.typ = UVM32_EVT_IOREQ;
|
vmst->ioevt.typ = UVM32_EVT_UVM32_SYSCALL;
|
||||||
vmst->ioevt.data.ioreq.code = vmst->mappings[i].code;
|
vmst->ioevt.data.syscall.code = vmst->mappings[i].code;
|
||||||
vmst->ioevt.data.ioreq.typ = vmst->mappings[i].typ;
|
vmst->ioevt.data.syscall.typ = vmst->mappings[i].typ;
|
||||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||||
syscall_valid = true;
|
syscall_valid = true;
|
||||||
break; // stop searching
|
break; // stop searching
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// "well-known" system IOREQ functions
|
// "well-known" system UVM32_SYSCALL functions
|
||||||
#define IOREQ_HALT 0x138
|
#define UVM32_SYSCALL_HALT 0x138
|
||||||
#define IOREQ_YIELD 0x139
|
#define UVM32_SYSCALL_YIELD 0x139
|
||||||
|
|
||||||
#define LIST_OF_UVM32_ERRS \
|
#define LIST_OF_UVM32_ERRS \
|
||||||
X(UVM32_ERR_NONE) \
|
X(UVM32_ERR_NONE) \
|
||||||
|
|
@ -26,41 +26,41 @@ typedef enum {
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UVM32_EVT_ERR,
|
UVM32_EVT_ERR,
|
||||||
UVM32_EVT_IOREQ,
|
UVM32_EVT_UVM32_SYSCALL,
|
||||||
UVM32_EVT_YIELD,
|
UVM32_EVT_YIELD,
|
||||||
UVM32_EVT_END,
|
UVM32_EVT_END,
|
||||||
} uvm32_evt_typ_t;
|
} uvm32_evt_typ_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
IOREQ_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_ioreq_t.val.buf
|
UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_syscall_t.val.buf
|
||||||
IOREQ_TYP_VOID, // no data
|
UVM32_SYSCALL_TYP_VOID, // no data
|
||||||
IOREQ_TYP_U32_WR, // data write from vm, in uvm32_evt_ioreq_t.val.u32
|
UVM32_SYSCALL_TYP_U32_WR, // data write from vm, in uvm32_evt_syscall_t.val.u32
|
||||||
IOREQ_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_ioreq_t.val.u32p
|
UVM32_SYSCALL_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_syscall_t.val.u32p
|
||||||
} uvm32_ioreq_typ_t;
|
} 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 {
|
typedef struct {
|
||||||
uint32_t syscall;
|
uint32_t syscall;
|
||||||
uvm32_user_ioreq_code_t code;
|
uvm32_user_syscall_code_t code;
|
||||||
uvm32_ioreq_typ_t typ;
|
uvm32_syscall_typ_t typ;
|
||||||
} uvm32_mapping_t;
|
} uvm32_mapping_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
} uvm32_evt_ioreq_buf_t;
|
} uvm32_evt_syscall_buf_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uvm32_ioreq_typ_t typ;
|
uvm32_syscall_typ_t typ;
|
||||||
uvm32_user_ioreq_code_t code;
|
uvm32_user_syscall_code_t code;
|
||||||
union {
|
union {
|
||||||
uvm32_evt_ioreq_buf_t buf;
|
uvm32_evt_syscall_buf_t buf;
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
uint32_t *u32p;
|
uint32_t *u32p;
|
||||||
} val;
|
} val;
|
||||||
} uvm32_evt_ioreq_t;
|
} uvm32_evt_syscall_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uvm32_err_t errcode;
|
uvm32_err_t errcode;
|
||||||
|
|
@ -70,7 +70,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uvm32_evt_typ_t typ;
|
uvm32_evt_typ_t typ;
|
||||||
union {
|
union {
|
||||||
uvm32_evt_ioreq_t ioreq;
|
uvm32_evt_syscall_t syscall;
|
||||||
uvm32_evt_err_t err;
|
uvm32_evt_err_t err;
|
||||||
} data;
|
} data;
|
||||||
} uvm32_evt_t;
|
} uvm32_evt_t;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue