commit 0abd4fab15a9fd01d804d4e250147434520af696
parent af4786689df0090d6e7bfc136b73b5a71d352893
Author: Brian Swetland <swetland@frotz.net>
Date: Sat, 2 Nov 2019 16:30:16 -0700
rvsim: iocall mechanism
- provide syscall-like traps for dputc, open, close, read, write
- header (system.h) and stubs (start.S) for iocalls
- remove dedicated dputc instruction
- provide a mechanism to ask the sim for direct memory access
Diffstat:
7 files changed, 110 insertions(+), 42 deletions(-)
diff --git a/instab.txt b/instab.txt
@@ -70,8 +70,8 @@
0000001----------111-----0110011 remu %d, %1, %2
-----------------000-----0001111 fence
-----------------000-----0001011 _exiti %i
+-----------------001-----0001011 _iocall %i
-----------------100-----0001011 _exit %1
------------------101-----0001011 _putc %1
-----------------001000001110011 csrw %C, %1
-----------------001-----1110011 csrrw %d, %C, %1
------------00000010-----1110011 csrr %d, %C
diff --git a/iocall.h b/iocall.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#define IOCALL_DPUTC 0x00
+
+#define IOCALL_OPEN 0x10
+#define IOCALL_CLOSE 0x11
+#define IOCALL_READ 0x12
+#define IOCALL_WRITE 0x13
diff --git a/rvmain.c b/rvmain.c
@@ -10,6 +10,7 @@
#include <sys/stat.h>
#include "rvsim.h"
+#include "iocall.h"
uint32_t ior32(uint32_t addr) {
return 0xffffffff;
@@ -18,9 +19,36 @@ uint32_t ior32(uint32_t addr) {
void iow32(uint32_t addr, uint32_t val) {
}
-void ioputc(uint32_t c) {
- uint8_t x = c;
- if (write(1, &x, 1)) {} // appease warning
+uint32_t iocall(void* ctx, uint32_t n, const uint32_t args[8]) {
+ rvstate_t* s = ctx;
+ switch (n) {
+ case IOCALL_DPUTC: {
+ uint8_t x = args[0];
+ if (write(1, &x, 1)) { return -1; }
+ return 0;
+ }
+ case IOCALL_OPEN: { // (path, flags, mode) -> fd/error
+ void* ptr = rvsim_dma(s, args[0], 1024);
+ if (ptr == NULL) return -1;
+ if (memchr(ptr, 0, 1024) == NULL) return -1;
+ return open(ptr, args[1], args[2]);
+ }
+ case IOCALL_CLOSE: { // (fd) -> 0/error
+ return close(args[0]);
+ }
+ case IOCALL_READ: { // (fd, ptr, len) -> len/error
+ void* ptr = rvsim_dma(s, args[1], args[2]);
+ if (ptr == NULL) return -1;
+ return read(args[0], ptr, args[2]);
+ }
+ case IOCALL_WRITE: { // (fd, ptr, len) -> len/error
+ void* ptr = rvsim_dma(s, args[1], args[2]);
+ if (ptr == NULL) return -1;
+ return write(args[0], ptr, args[2]);
+ }
+ default:
+ return -1;
+ }
}
int load_image(const char* fn, uint8_t* ptr, size_t sz) {
@@ -75,18 +103,23 @@ int main(int argc, char** argv) {
return -1;
}
void* memory;
- uint32_t memsize = 0;
+ uint32_t membase = 0x80000000;
+ uint32_t memsize = 32768;
rvstate_t* s;
- if (rvsim_init(&s, &memory, &memsize)) {
+ if (rvsim_init(&s, NULL)) {
fprintf(stderr, "error: cannot initialize simulator\n");
return -1;
}
+ if ((memory = rvsim_dma(s, membase, memsize)) == NULL) {
+ fprintf(stderr, "error: cannot access sim memory\n");
+ return -1;
+ }
if (load_image(fn, memory, memsize) < 0) {
fprintf(stderr, "error: failed to load '%s'\n", fn);
return -1;
}
- rvsim_exec(s, 0x80000000);
+ rvsim_exec(s, membase);
if (dumpfn && (dumpto > dumpfrom)) {
FILE* fp;
diff --git a/rvsim.c b/rvsim.c
@@ -9,10 +9,10 @@
#include "riscv.h"
#include "rvsim.h"
-#define DO_TRACE_INS 1
-#define DO_TRACE_TRAPS 1
-#define DO_TRACE_MEM_WR 1
-#define DO_TRACE_REG_WR 1
+#define DO_TRACE_INS 0
+#define DO_TRACE_TRAPS 0
+#define DO_TRACE_MEM_WR 0
+#define DO_TRACE_REG_WR 0
#define RVMEMBASE 0x80000000
#define RVMEMSIZE 32768
@@ -26,8 +26,17 @@ typedef struct rvstate {
uint32_t mtval;
uint32_t mepc;
uint32_t mcause;
+ void* ctx;
} rvstate_t;
+void* rvsim_dma(rvstate_t* s, uint32_t va, uint32_t len) {
+ if (va < RVMEMBASE) return NULL;
+ va -= RVMEMBASE;
+ if (va >= RVMEMSIZE) return NULL;
+ if (len > (RVMEMSIZE - va)) return NULL;
+ return s->memory + va;
+}
+
static uint32_t rd32(uint8_t* memory, uint32_t addr) {
if (addr < RVMEMBASE) {
return ior32(addr);
@@ -77,7 +86,7 @@ uint32_t rvsim_rd32(rvstate_t* s, uint32_t addr) {
return rd32(s->memory, addr);
}
-int rvsim_init(rvstate_t** _s, void** _memory, uint32_t* _memsize) {
+int rvsim_init(rvstate_t** _s, void* ctx) {
rvstate_t *s;
if ((s = malloc(sizeof(rvstate_t))) == NULL) {
return -1;
@@ -89,9 +98,8 @@ int rvsim_init(rvstate_t** _s, void** _memory, uint32_t* _memsize) {
}
memset(s->memory, 0, RVMEMSIZE);
s->mtvec = 0x80000000;
+ s->ctx = ctx ? ctx : s;
*_s = s;
- *_memory = s->memory;
- *_memsize = RVMEMSIZE;
return 0;
}
@@ -206,8 +214,8 @@ int rvsim_exec(rvstate_t* s, uint32_t _pc) {
case 0b100: // _exit
fprintf(stderr, "CCOUNT %lu\n", ccount);
return RdR1();
- case 0b101: // _putc
- ioputc(RdR1());
+ case 0b001: // _iocall
+ s->x[10] = iocall(s->ctx, get_ii(ins), s->x + 10);
break;
default:
goto inval;
diff --git a/rvsim.h b/rvsim.h
@@ -5,13 +5,23 @@
typedef struct rvstate rvstate_t;
-int rvsim_init(rvstate_t** s, void** memory, uint32_t* memsize);
+// initialize simulator
+int rvsim_init(rvstate_t** s, void* ctx);
+// start simulator running at pc
int rvsim_exec(rvstate_t* s, uint32_t pc);
+// obtain a pointer for direct memory access
+void* rvsim_dma(rvstate_t* s, uint32_t va, uint32_t len);
+
+// read a word from memory
uint32_t rvsim_rd32(rvstate_t* s, uint32_t addr);
+
+// hook for "syscalls"
+uint32_t iocall(void* ctx, uint32_t n, const uint32_t args[8]);
+
+// hooks to implement io read/write access
uint32_t ior32(uint32_t addr);
void iow32(uint32_t addr, uint32_t val);
-void ioputc(uint32_t c);
diff --git a/start.S b/start.S
@@ -1,29 +1,21 @@
-#define PASS .long 0x0000000b // _exiti 0
-#define FAIL .long 0xFFF0000b // _exiti -1
-#define PUTC .long 0x0005500b // _putc a0
+#include "iocall.h"
-.globl _start
+#define EXITI_0 .long 0x0000000b // _exiti 0
+#define IOCALL(n) .long 0x0000100b | ((n) << 20) // iocall n
+
+#define MKIOCALL(a,b) .globl a; a: IOCALL(IOCALL_##b); ret
+.globl _start
_start:
-#if 0
- li t1, 0x87654FFF
- PASS
- FAIL
- PUTC
- beqz t1, main0
- bnez t1, main0
- blez t1, main0
- bgez t1, main0
- bltz t1, main0
- bgtz t1, main0
- sltz s1, s2
- sgtz s1, s2
- snez s1, s2
- seqz s1, s2
- not s3, s5
- neg s5, s6
-#endif
-main0:
jal main
- PASS
+
+.globl exit
+exit:
+ EXITI_0
+
+MKIOCALL(dputc,DPUTC)
+MKIOCALL(open,OPEN)
+MKIOCALL(close,CLOSE)
+MKIOCALL(read,READ)
+MKIOCALL(write,WRITE)
diff --git a/system.h b/system.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#define O_RDONLY 00
+#define O_WRONLY 01
+#define O_RDWR 02
+
+#define O_CREAT 0100
+#define O_EXCL 0200
+#define O_RUNC 01000
+
+int dputc(unsigned ch);
+
+int open(const char* path, unsigned flags, unsigned mode);
+int close(int fd);
+int read(int fd, void* ptr, int len);
+int write(int fd, void* ptr, int len);
+