riscv

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

commit ad3967fb66d5b653f2de970b55f35a45a8875f23
parent 9d593b6becb3f017b5df2e14e2e79a41d2fb02a7
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed, 23 Oct 2019 03:33:12 -0700

rvsim: implement traps

- CSRs: mtvec, mtval, mepc, mcause
- opcodes: mexec, mbreak, mret
- load/store alignment traps
- instruction alignment traps
- all riscv-compliance tests now pass

Diffstat:
Minstab.txt | 1+
Mriscv.h | 16++++++++++++++++
Mrvsim.c | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 87 insertions(+), 13 deletions(-)

diff --git a/instab.txt b/instab.txt @@ -79,4 +79,5 @@ -----------------111-----1110011 csrrci %d, %C, %c 00000000000000000000000001110011 ecall 00000000000100000000000001110011 ebreak +00110000001000000000000001110011 mret -------------------------------- unknown diff --git a/riscv.h b/riscv.h @@ -136,6 +136,22 @@ static inline uint32_t get_iC(uint32_t ins) { #define CSR_MTVAL 0x343 #define CSR_MIP 0x344 +// exception codes +#define EC_I_ALIGN 0 +#define EC_I_ACCESS 1 +#define EC_I_ILLEGAL 2 +#define EC_BREAKPOINT 3 +#define EC_L_ALIGN 4 +#define EC_L_ACCESS 5 +#define EC_S_ALIGN 6 +#define EC_S_ACCESS 7 +#define EC_ECALL_FROM_U 8 +#define EC_ECALL_FROM_S 9 +#define EC_ECALL_FROM_M 11 +#define EC_I_PAGEFAULT 12 +#define EC_L_PAGEFAULT 13 +#define EC_S_PAGEFAULT 15 + void rvdis(uint32_t pc, uint32_t ins, char *out); const char* rvregname(uint32_t n); diff --git a/rvsim.c b/rvsim.c @@ -90,6 +90,10 @@ 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; static inline uint32_t rreg(rvstate_t* s, uint32_t n) { @@ -101,15 +105,25 @@ static inline void wreg(rvstate_t* s, uint32_t n, uint32_t v) { static void put_csr(rvstate_t* s, uint32_t csr, uint32_t v) { switch (csr) { - case CSR_MSCRATCH: - s->mscratch = v; - break; + case CSR_MSCRATCH: s->mscratch = v; break; + case CSR_MTVEC: s->mtvec = v & 0xFFFFFFFC; break; + case CSR_MTVAL: s->mtval = v; break; + case CSR_MEPC: s->mepc = v; break; + case CSR_MCAUSE: s->mcause = v; break; } } static uint32_t get_csr(rvstate_t* s, uint32_t csr) { switch (csr) { - case CSR_MSCRATCH: - return s->mscratch; + case CSR_MISA: return 0x40000100; // RV32I + case CSR_MVENDORID: return 0; // NONE + case CSR_MARCHID: return 0; // NONE + case CSR_MIMPID: return 0; // NONE + case CSR_MHARTID: return 0; // Thread Zero + case CSR_MSCRATCH: return s->mscratch; + case CSR_MTVEC: return s->mtvec; + case CSR_MTVAL: return s->mtval; + case CSR_MEPC: return s->mepc; + case CSR_MCAUSE: return s->mcause; default: return 0; } @@ -142,7 +156,16 @@ void rvsim(rvstate_t* s) { uint32_t ccount = 0; uint32_t ins; for (;;) { - pc = next; + 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 char dis[128]; @@ -156,10 +179,16 @@ void rvsim(rvstate_t* s) { uint32_t a = RdR1() + get_ii(ins); uint32_t v; switch (get_fn3(ins)) { - case F3_LW: v = rd32(a); break; - case F3_LHU: v = rd16(a); break; + case F3_LW: + if (a & 3) goto trap_load_align; + v = rd32(a); break; + case F3_LHU: + if (a & 1) goto trap_load_align; + v = rd16(a); break; case F3_LBU: v = rd8(a); break; - case F3_LH: v = rd16(a); + case F3_LH: + if (a & 1) goto trap_load_align; + v = rd16(a); if (v & 0x8000) { v |= 0xFFFF0000; } break; case F3_LB: v = rd8(a); if (v & 0x80) { v |= 0xFFFFFF00; } break; @@ -169,6 +198,10 @@ void rvsim(rvstate_t* s) { WrRd(v); trace_reg_wr(v); break; + trap_load_align: + s->mcause = EC_L_ALIGN; + s->mtval = a; + goto trap_common; } case OC_CUSTOM_0: goto inval; @@ -218,14 +251,23 @@ void rvsim(rvstate_t* s) { uint32_t a = RdR1() + get_is(ins); uint32_t v = RdR2(); switch (get_fn3(ins)) { - case F3_SW: wr32(a, v); break; - case F3_SH: wr16(a, v); break; - case F3_SB: wr8(a, v); break; + case F3_SW: + if (a & 3) goto trap_store_align; + wr32(a, v); break; + case F3_SH: + if (a & 1) goto trap_store_align; + wr16(a, v); break; + case F3_SB: + wr8(a, v); break; default: goto inval; } trace_mem_wr(a, v); break; + trap_store_align: + s->mcause = EC_S_ALIGN; + s->mtval = a; + goto trap_common; } case OC_OP: { uint32_t a = RdR1(); @@ -288,7 +330,22 @@ void rvsim(rvstate_t* s) { case OC_SYSTEM: { uint32_t fn = get_fn3(ins); if (fn == 0) { - goto inval; + switch(ins >> 7) { + case 0b0000000000000000000000000: // ecall + s->mcause = EC_ECALL_FROM_M; + s->mtval = 0; + goto trap_common; + case 0b0000000000010000000000000: // ebreak + s->mcause = EC_BREAKPOINT; + s->mtval = 0; + goto trap_common; + case 0b0011000000100000000000000: // mret + next = s->mepc; + break; + default: + goto inval; + } + break; } uint32_t c = get_iC(ins); uint32_t nv = (fn & 4) ? get_ic(ins) : RdR1();