riscv

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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:
MMakefile | 2+-
Mriscv.h | 3+++
Arvmain.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mrvsim.c | 250+++++++++++++++++++++++++++++++++----------------------------------------------
Arvsim.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); + +