commit 3960a8a7fe04cce7b2ce8657f7fe410a913ec6ec
parent ad3967fb66d5b653f2de970b55f35a45a8875f23
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed, 23 Oct 2019 06:51:09 -0700
rvsim: tidy things up
- trap on illegal instructions
- remove branch alignment checks from hot path
- separate sim core (rvsim.[ch]) from loader/driver (rvmain.c)
- featurize tracing of instructions, writes, traps, etc
Diffstat:
| M | Makefile | | | 2 | +- | 
| M | riscv.h | | | 3 | +++ | 
| A | rvmain.c | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| M | rvsim.c | | | 250 | +++++++++++++++++++++++++++++++++---------------------------------------------- | 
| A | rvsim.h | | | 17 | +++++++++++++++++ | 
5 files changed, 224 insertions(+), 148 deletions(-)
diff --git a/Makefile b/Makefile
@@ -24,7 +24,7 @@ out/hello.elf: $(HELLO_SRCS) Makefile
 	@mkdir -p out
 	$(CC) $(CFLAGS) -o $@ $(HELLO_SRCS)
 
-RVSIM_SRCS := rvsim.c rvdis.c
+RVSIM_SRCS := rvmain.c rvsim.c rvdis.c
 bin/rvsim: $(RVSIM_SRCS) Makefile gen/instab.h
 	@mkdir -p bin
 	gcc -O3 -Wall -o $@ $(RVSIM_SRCS)
diff --git a/riscv.h b/riscv.h
@@ -1,3 +1,6 @@
+// Copyright 2019, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
 #pragma once
 
 #include <stdint.h>
diff --git a/rvmain.c b/rvmain.c
@@ -0,0 +1,100 @@
+// Copyright 2019, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "rvsim.h"
+
+uint32_t ior32(uint32_t addr) {
+        return 0xffffffff;
+}
+
+void iow32(uint32_t addr, uint32_t val) {
+}
+
+int load_image(const char* fn, uint8_t* ptr, size_t sz) {
+	struct stat s;
+	int fd = open(fn, O_RDONLY);
+	if (fd < 0) return -1;
+	if (fstat(fd, &s) < 0) return -1;
+	if (s.st_size > sz) return -1;
+	sz = s.st_size;
+	while (sz > 0) {
+		ssize_t r = read(fd, ptr, sz);
+		if (r <= 0) {
+			close(fd);
+			return -1;
+		}
+		ptr += r;
+		sz -= r;
+	}
+	close(fd);
+	fprintf(stderr, "image: %ld bytes\n", s.st_size);
+	return 0;
+}
+
+int main(int argc, char** argv) {
+	const char* fn = NULL;
+	const char* dumpfn = NULL;
+	uint32_t dumpfrom = 0, dumpto = 0;
+	while (argc > 1) {
+		argc--;
+		argv++;
+		if (argv[0][0] != '-') {
+			if (fn != NULL) {
+				fprintf(stderr, "error: multiple inputs\n");
+				return -1;
+			}
+			fn = argv[0];
+			continue;
+		}
+		if (!strncmp(argv[0],"-dump=",6)) {
+			dumpfn = argv[0] + 6;
+			continue;
+		}
+		if (!strncmp(argv[0],"-from=",6)) {
+			dumpfrom = strtoul(argv[0] + 6, NULL, 16);
+			continue;
+		}
+		if (!strncmp(argv[0],"-to=",4)) {
+			dumpto = strtoul(argv[0] + 4, NULL, 16);
+			continue;
+		}
+		fprintf(stderr, "error: unknown argument: %s\n", argv[0]);
+		return -1;
+	}
+	void* memory;
+	uint32_t memsize = 0;
+	rvstate_t* s;
+
+	if (rvsim_init(&s, &memory, &memsize)) {
+		fprintf(stderr, "error: cannot initialize simulator\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);
+
+	if (dumpfn && (dumpto > dumpfrom)) {
+		FILE* fp;
+		if ((fp = fopen(dumpfn, "w")) == NULL) {
+			fprintf(stderr, "error: failed to open '%s' to write\n", dumpfn);
+			return -1;
+		}
+		for (uint32_t n = dumpfrom; n < dumpto; n += 4) {
+			uint32_t v = rvsim_rd32(s, n);
+			fprintf(fp, "%08x\n", v);
+		}
+		fclose(fp);
+	}
+	return 0;
+}
+
diff --git a/rvsim.c b/rvsim.c
@@ -5,96 +5,95 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
 
 #include "riscv.h"
+#include "rvsim.h"
 
-uint8_t memory[32768];
+#define DO_TRACE_INS     1
+#define DO_TRACE_TRAPS   1
+#define DO_TRACE_MEM_WR  1
+#define DO_TRACE_REG_WR  1
 
-int load_image(const char* fn, uint8_t* ptr, size_t sz) {
-	struct stat s;
-	int fd = open(fn, O_RDONLY);
-	if (fd < 0) return -1;
-	if (fstat(fd, &s) < 0) return -1;
-	if (s.st_size > sz) return -1;
-	sz = s.st_size;
-	while (sz > 0) {
-		ssize_t r = read(fd, ptr, sz);
-		if (r <= 0) {
-			close(fd);
-			return -1;
-		}
-		ptr += r;
-		sz -= r;
-	}
-	close(fd);
-	fprintf(stderr, "image: %ld bytes\n", s.st_size);
-	return 0;
-}
+#define RVMEMBASE 0x80000000
+#define RVMEMSIZE 32768
+#define RVMEMMASK (RVMEMSIZE - 1)
 
-uint32_t ior32(uint32_t addr) {
-	return 0xffffffff;
-}
-
-void iow32(uint32_t addr, uint32_t val) {
-}
+typedef struct rvstate {
+	uint32_t x[32];
+	void* memory;
+	uint32_t mscratch;
+	uint32_t mtvec;
+	uint32_t mtval;
+	uint32_t mepc;
+	uint32_t mcause;
+} rvstate_t;
 
-uint32_t rd32(uint32_t addr) {
-	if (addr < 0x80000000) {
+static uint32_t rd32(uint8_t* memory, uint32_t addr) {
+	if (addr < RVMEMBASE) {
 		return ior32(addr);
 	} else {
-		addr &= (sizeof(memory) - 1);
+		addr &= RVMEMMASK;
 		return ((uint32_t*) memory)[addr >> 2];
 	}
 }
-void wr32(uint32_t addr, uint32_t val) {
-	if (addr < 0x80000000) {
+static void wr32(uint8_t* memory, uint32_t addr, uint32_t val) {
+	if (addr < RVMEMBASE) {
 		iow32(addr, val);
 	} else {
-		addr &= (sizeof(memory) - 1);
+		addr &= RVMEMMASK;
 		((uint32_t*) memory)[addr >> 2] = val;
 	}
 }
-uint32_t rd16(uint32_t addr) {
-	if (addr < 0x80000000) {
+static uint32_t rd16(uint8_t* memory, uint32_t addr) {
+	if (addr < RVMEMBASE) {
 		return 0xffff;
 	} else {
-		addr &= (sizeof(memory) - 1);
+		addr &= RVMEMMASK;
 		return ((uint16_t*) memory)[addr >> 1];
 	}
 }
-void wr16(uint32_t addr, uint32_t val) {
-	if (addr >= 0x80000000) {
-		addr &= (sizeof(memory) - 1);
+static void wr16(uint8_t* memory, uint32_t addr, uint32_t val) {
+	if (addr >= RVMEMBASE) {
+		addr &= RVMEMMASK;
 		((uint16_t*) memory)[addr >> 1] = val;
 	}
 }
-uint32_t rd8(uint32_t addr) {
-	if (addr < 0x80000000) {
+static uint32_t rd8(uint8_t* memory, uint32_t addr) {
+	if (addr < RVMEMBASE) {
 		return 0xff;
 	} else {
-		addr &= (sizeof(memory) - 1);
+		addr &= RVMEMMASK;
 		return memory[addr];
 	}
 }
-void wr8(uint32_t addr, uint32_t val) {
-	if (addr >= 0x80000000) {
-		addr &= (sizeof(memory) - 1);
+static void wr8(uint8_t* memory, uint32_t addr, uint32_t val) {
+	if (addr >= RVMEMBASE) {
+		addr &= RVMEMMASK;
 		memory[addr] = val;
 	}
 }
 
-typedef struct {
-	uint32_t x[32];
-	uint32_t pc;
-	uint32_t mscratch;
-	uint32_t mtvec;
-	uint32_t mtval;
-	uint32_t mepc;
-	uint32_t mcause;
-} rvstate_t;
+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) {
+	rvstate_t *s;
+	if ((s = malloc(sizeof(rvstate_t))) == NULL) {
+		return -1;
+	}
+	memset(s, 0, sizeof(rvstate_t));
+	if ((s->memory = malloc(RVMEMSIZE)) == NULL) {
+		free(s);
+		return -1;
+	}
+	memset(s->memory, 0, RVMEMSIZE);
+	s->mtvec = 0x80000000;
+	*_s = s;
+	*_memory = s->memory;
+	*_memsize = RVMEMSIZE;
+	return 0;
+}
 
 static inline uint32_t rreg(rvstate_t* s, uint32_t n) {
 	return n ? s->x[n] : 0;
@@ -134,46 +133,38 @@ static uint32_t get_csr(rvstate_t* s, uint32_t csr) {
 #define RdRd() rreg(s, get_rd(ins))
 #define WrRd(v) wreg(s, get_rd(ins), v)
 
-#define DO_DISASM 1
-#define DO_TRACK  1
-
-#define trace_reg(fmt...) printf(fmt...)
-
+#if DO_TRACE_REG_WR
 #define trace_reg_wr(v) do {\
 	uint32_t r = get_rd(ins); \
 	if (r) { \
-	printf("          (%s = %08x)\n", \
+	fprintf(stderr, "          (%s = %08x)\n", \
 		rvregname(get_rd(ins)), v); \
 	}} while (0)
+#else
+#define trace_reg_wr(v) do {} while (0)
+#endif
 
+#if DO_TRACE_MEM_WR
 #define trace_mem_wr(a, v) do {\
-	printf("          ([%08x] = %08x)\n", a, v);\
+	fprintf(stderr, "          ([%08x] = %08x)\n", a, v);\
 	} while (0)
+#else
+#define trace_mem_wr(v) do {} while (0)
+#endif
 
-void rvsim(rvstate_t* s) {
-	uint32_t pc = s->pc;
-	uint32_t next = pc;
-	uint32_t ccount = 0;
+int rvsim_exec(rvstate_t* s, uint32_t _pc) {
+	uint32_t pc = _pc;
+	uint32_t next = _pc;
 	uint32_t ins;
 	for (;;) {
-		if (next & 3) {
-			s->mcause = EC_I_ALIGN;
-			s->mepc = pc;
-			s->mtval = next;
-trap_common:
-			s->mepc = pc;
-			pc = s->mtvec & 0xFFFFFFFD;
-		} else {
-			pc = next;
-		}
-		ins = rd32(pc);
-#if DO_DISASM
+		pc = next;
+		ins = rd32(s->memory, pc);
+#if DO_TRACE_INS
 		char dis[128];
 		rvdis(pc, ins, dis);
-		printf("%08x: %08x %s\n", pc, ins, dis);
+		fprintf(stderr, "%08x: %08x %s\n", pc, ins, dis);
 #endif
 		next = pc + 4;
-		ccount++;
 		switch (get_oc(ins)) {
 		case OC_LOAD: {
 			uint32_t a = RdR1() + get_ii(ins);
@@ -181,16 +172,18 @@ trap_common:
 			switch (get_fn3(ins)) {
 			case F3_LW:
 				if (a & 3) goto trap_load_align;
-				v = rd32(a); break;
+				v = rd32(s->memory, a); break;
 			case F3_LHU:
 				if (a & 1) goto trap_load_align;
-				v = rd16(a); break;
-			case F3_LBU: v = rd8(a); break;
+				v = rd16(s->memory, a); break;
+			case F3_LBU:
+				v = rd8(s->memory, a); break;
 			case F3_LH:
 				if (a & 1) goto trap_load_align;
-				v = rd16(a);
+				v = rd16(s->memory, a);
 				if (v & 0x8000) { v |= 0xFFFF0000; } break;
-			case F3_LB: v = rd8(a);
+			case F3_LB:
+				v = rd8(s->memory, a);
 				if (v & 0x80) { v |= 0xFFFFFF00; } break;
 			default:
 				goto inval;
@@ -204,7 +197,7 @@ trap_common:
 			goto trap_common;
 		}
 		case OC_CUSTOM_0:
-			goto inval;
+			return 0;
 		case OC_MISC_MEM:
 			switch (get_fn3(ins)) {
 			case F3_FENCE:
@@ -253,12 +246,12 @@ trap_common:
 			switch (get_fn3(ins)) {
 			case F3_SW:
 				if (a & 3) goto trap_store_align;
-				wr32(a, v); break;
+				wr32(s->memory, a, v); break;
 			case F3_SH:
 				if (a & 1) goto trap_store_align;
-				wr16(a, v); break;
+				wr16(s->memory, a, v); break;
 			case F3_SB:
-				wr8(a, v); break;
+				wr8(s->memory, a, v); break;
 			default:
 				goto inval;
 			}
@@ -311,7 +304,10 @@ trap_common:
 			default:
 				goto inval;
 			}
-			if (p) next = pc + get_ib(ins);
+			if (p) {
+				next = pc + get_ib(ins);
+				if (next & 3) goto trap_pc_align;
+			}
 			break;
 			}
 		case OC_JALR: {
@@ -320,12 +316,14 @@ trap_common:
 			WrRd(next);
 			trace_reg_wr(next);
 			next = a;
+			if (next & 3) goto trap_pc_align;
 			break;
 			}
 		case OC_JAL:
 			WrRd(next);
 			trace_reg_wr(next);
 			next = pc + get_ij(ins);
+			if (next & 3) goto trap_pc_align;
 			break;
 		case OC_SYSTEM: {
 			uint32_t fn = get_fn3(ins);
@@ -371,64 +369,22 @@ trap_common:
 			WrRd(ov);
 			break;
 			}
+trap_pc_align:
+			s->mcause = EC_I_ALIGN;
+			s->mtval = next;
+			goto trap_common;
 		default:
 		inval:
-			return;
-		}
-	}
-}
-
-
-int main(int argc, char** argv) {
-	const char* fn = NULL;
-	const char* dumpfn = NULL;
-	uint32_t dumpfrom = 0, dumpto = 0;
-	while (argc > 1) {
-		argc--;
-		argv++;
-		if (argv[0][0] != '-') {
-			if (fn != NULL) {
-				fprintf(stderr, "error: multiple inputs\n");
-				return -1;
-			}
-			fn = argv[0];
-			continue;
-		}
-		if (!strncmp(argv[0],"-dump=",6)) {
-			dumpfn = argv[0] + 6;
-			continue;
-		}
-		if (!strncmp(argv[0],"-from=",6)) {
-			dumpfrom = strtoul(argv[0] + 6, NULL, 16);
-			continue;
-		}
-		if (!strncmp(argv[0],"-to=",4)) {
-			dumpto = strtoul(argv[0] + 4, NULL, 16);
-			continue;
-		}
-		fprintf(stderr, "error: unknown argument: %s\n", argv[0]);
-		return -1;
-	}
-	rvstate_t s;
-	if (load_image(fn, memory, sizeof(memory)) < 0) {
-		fprintf(stderr, "error: failed to load '%s'\n", fn);
-		return -1;
-	}
-	memset(&s, 0, sizeof(s));
-	s.pc = 0x80000000;
-	rvsim(&s);
-	if (dumpfn && (dumpto > dumpfrom)) {
-		FILE* fp;
-		if ((fp = fopen(dumpfn, "w")) == NULL) {
-			fprintf(stderr, "error: failed to open '%s' to write\n", dumpfn);
-			return -1;
-		}
-		for (uint32_t n = dumpfrom; n < dumpto; n += 4) {
-			uint32_t v = rd32(n);
-			fprintf(fp, "%08x\n", v);
+			s->mcause = EC_I_ILLEGAL;
+			s->mtval = ins;
+trap_common:
+			s->mepc = pc;
+			next = s->mtvec & 0xFFFFFFFD;
+#if DO_TRACE_TRAPS
+			fprintf(stderr, "          (TRAP C=%08x V=%08x)\n", s->mcause, s->mtval);
+#endif
+			break;
 		}
-		fclose(fp);
 	}
-	return 0;
 }
 
diff --git a/rvsim.h b/rvsim.h
@@ -0,0 +1,17 @@
+// Copyright 2019, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+#pragma once
+
+typedef struct rvstate rvstate_t;
+
+int rvsim_init(rvstate_t** s, void** memory, uint32_t* memsize);
+
+int rvsim_exec(rvstate_t* s, uint32_t pc);
+
+uint32_t rvsim_rd32(rvstate_t* s, uint32_t addr);
+
+uint32_t ior32(uint32_t addr);
+void iow32(uint32_t addr, uint32_t val);
+
+