riscv

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

commit f9d029a85313d1a909a73dcdb2ef9079cee7998a
parent 78f5bde3560fc41e88ceee3c4e46d9fa8cb3d3e1
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 20 Oct 2019 14:51:20 -0700

rvsim: start actually simulating instructions

- trivial test program works
- needs a lot more testing

Diffstat:
Minstab.txt | 4++--
Mriscv.h | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mrvdis.c | 1+
Mrvsim.c | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mstart.S | 28++++++++++++++++++++++++----
5 files changed, 252 insertions(+), 19 deletions(-)

diff --git a/instab.txt b/instab.txt @@ -1,8 +1,8 @@ # Copyright 2018, Brian Swetland <swetland@frotz.net> # Licensed under the Apache License, Version 2.0. --------------------------0110111 lui %d, %u --------------------------0010111 auipc %d, %u +-------------------------0110111 lui %d, %U +-------------------------0010111 auipc %d, %U --------------------000001101111 j %J --------------------000011101111 jal %J -------------------------1101111 jal %d, %J diff --git a/riscv.h b/riscv.h @@ -3,6 +3,9 @@ #include <stdint.h> // extract instruction fields +static inline uint32_t get_oc(uint32_t ins) { + return ins & 0x7f; +} static inline uint32_t get_rd(uint32_t ins) { return (ins >> 7) & 0x1f; } @@ -33,11 +36,69 @@ static inline uint32_t get_ij(uint32_t ins) { ((ins >> 9) & 0x800) | ((ins >> 20) & 0x7fe); } +static inline uint32_t get_fn3(uint32_t ins) { + return (ins >> 12) & 7; +} +static inline uint32_t get_fn7(uint32_t ins) { + return ins >> 25; +} + +// opcode constants (6:0) +#define OC_LOAD 0b0000011 +#define OC_CUSTOM_0 0b0001011 +#define OC_MISC_MEM 0b0001111 +#define OC_OP_IMM 0b0010011 +#define OC_AUIPC 0b0010111 +#define OC_STORE 0b0100011 +#define OC_OP 0b0110011 +#define OC_LUI 0b0110111 +#define OC_BRANCH 0b1100011 +#define OC_JALR 0b1100111 +#define OC_JAL 0b1101111 +#define OC_SYSTEM 0b1110011 + +// further discrimination of OC_OP_IMM (14:12) +#define F3_ADDI 0b000 +#define F3_SLLI 0b001 // 0b0000000 +#define F3_SLTI 0b010 +#define F3_SLTIU 0b011 +#define F3_XORI 0b100 +#define F3_SRLI 0b101 // 0b0000000 +#define F3_SRAI 0b101 // 0b0100000 +#define F3_ORI 0b110 +#define F3_ANDI 0b111 + +// further discrimination of OC_OP_LOAD (14:12) +#define F3_LB 0b000 +#define F3_LH 0b001 +#define F3_LW 0b010 +#define F3_LBU 0b100 +#define F3_LHU 0b101 + +// further discrimination of OC_OP_STORE (14:12) +#define F3_SB 0b000 +#define F3_SH 0b001 +#define F3_SW 0b010 + +// further discrimination of OC_OP (14:12) (fn7==0) +#define F3_ADD 0b0000 +#define F3_SLL 0b0001 +#define F3_SLT 0b0010 +#define F3_SLTU 0b0011 +#define F3_XOR 0b0100 +#define F3_SRL 0b0101 +#define F3_OR 0b0110 +#define F3_AND 0b0111 +// OC_OP (14:12) (fn7==0b0100000) +#define F3_SUB 0b1000 +#define F3_SRA 0b1101 -#define OP_LUI 0b0110111 -#define OP_AUIPC 0b0010111 -#define OP_JAL 0b1101111 -#define OP_JALR 0b1100111 -#define OP_B +// further discrimination of OP_BRANCH +#define F3_BEQ 0b000 +#define F3_BNE 0b001 +#define F3_BLT 0b100 +#define F3_BGE 0b101 +#define F3_BLTU 0b110 +#define F3_BGEU 0b111 void rvdis(uint32_t pc, uint32_t ins, char *out); diff --git a/rvdis.c b/rvdis.c @@ -64,6 +64,7 @@ void rvdis(uint32_t pc, uint32_t ins, char *out) { case 'B': out = append_u32(out, pc + (2 * get_ib(ins))); break; case 's': out = append_i32(out, get_is(ins)); break; case 'u': out = append_i32(out, get_iu(ins)); break; + case 'U': out = append_u32(out, get_iu(ins)); break; case 'x': out = append_i32(out, get_r2(ins)); break; } } diff --git a/rvsim.c b/rvsim.c @@ -11,6 +11,13 @@ #include "riscv.h" +static const char* regname[32] = { + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", +}; + uint8_t memory[32768]; int load_image(const char* fn, uint8_t* ptr, size_t sz) { @@ -62,23 +69,167 @@ void wr32(uint32_t addr, uint32_t val) { typedef struct { uint32_t x[32]; uint32_t pc; -} rvstate; +} rvstate_t; + +static inline uint32_t rreg(rvstate_t* s, uint32_t n) { + return n ? s->x[n] : 0; +} +static inline void wreg(rvstate_t* s, uint32_t n, uint32_t v) { + s->x[n] = v; +} + -void rvsim(rvstate* s) { - char dis[128]; - uint32_t pc, ins; - pc = s->pc; - while (pc < 0x80000100) { +#define RdR1() rreg(s, get_r1(ins)) +#define RdR2() rreg(s, get_r2(ins)) +#define WrRd(v) wreg(s, get_rd(ins), v) + +#define DO_DISASM 1 +#define DO_TRACK 1 + +void rvsim(rvstate_t* s) { +#if DO_TRACK + uint32_t last[32]; +#endif + uint32_t pc = s->pc; + uint32_t next = pc; + uint32_t ccount = 0; + uint32_t ins; + for (;;) { + pc = next; +#if DO_TRACK + memcpy(last, &s->x, sizeof(last)); +#endif ins = rd32(pc); +#if DO_DISASM + char dis[128]; rvdis(pc, ins, dis); printf("%08x: %08x %s\n", pc, ins, dis); - pc += 4; +#endif + next = pc + 4; + ccount++; + switch (get_oc(ins)) { + case OC_LOAD: + switch (get_fn3(ins)) { + case F3_LW: + WrRd(rd32(RdR1() + get_ii(ins))); + break; + default: + goto inval; + } + break; + case OC_CUSTOM_0: + goto inval; + case OC_MISC_MEM: + if (get_fn3(ins) != 0) goto inval; + // fence -- do nothing + break; + case OC_OP_IMM: { + uint32_t a = RdR1(); + uint32_t b = get_ii(ins); + uint32_t n; + switch (get_fn3(ins)) { + case F3_ADDI: n = a + b; break; + case F3_SLLI: + if (b & 0b111111100000) goto inval; + n = a << b; break; + case F3_SLTI: n = ((int32_t)a) < ((int32_t)b); break; + case F3_SLTIU: n = a < b; break; + case F3_XORI: n = a ^ b; break; + case F3_SRLI: + if (b & 0b101111100000) goto inval; + if (b & 0b010000000000) { + n = ((int32_t)a) >> b; + } else { + n = a >> b; + } + break; + case F3_ORI: n = a | b; break; + case F3_ANDI: n = a & b; break; + } + WrRd(n); + break; + } + case OC_AUIPC: + WrRd(pc + get_iu(ins)); + break; + case OC_STORE: + switch (get_fn3(ins)) { + case F3_SW: + wr32(RdR2() + get_is(ins), RdR1()); + break; + default: + goto inval; + } + case OC_OP: { + uint32_t a = RdR1(); + uint32_t b = RdR1(); + uint32_t n; + if (ins & 0xDE000000) goto inval; + switch (get_fn3(ins) | (ins >> 27)) { + case F3_ADD: n = a + b; break; + case F3_SLL: n = a << (b & 31); break; + case F3_SLT: n = ((int32_t)a) < ((int32_t)b); break; + case F3_SLTU: n = a < b; break; + case F3_XOR: n = a ^ b; break; + case F3_SRL: n = a >> (b & 31); break; + case F3_OR: n = a | b; break; + case F3_AND: n = a & b; break; + case F3_SUB: n = a - b; break; + case F3_SRA: n = ((int32_t)a) >> (b & 31); break; + default: goto inval; + } + WrRd(n); + break; + } + case OC_LUI: + WrRd(get_iu(ins)); + break; + case OC_BRANCH: { + uint32_t a = RdR1(); + uint32_t b = RdR2(); + int32_t p; + switch (get_fn3(ins)) { + case F3_BEQ: p = (a == b); break; + case F3_BNE: p = (a != b); break; + case F3_BLT: p = (((int32_t)a) == ((int32_t)b)); break; + case F3_BGE: p = (((int32_t)a) == ((int32_t)b)); break; + case F3_BLTU: p = (a <= b); break; + case F3_BGEU: p = (a >= b); break; + default: + goto inval; + } + if (p) next = pc + (get_ib(ins) << 1); + break; + } + case OC_JALR: + if (get_fn3(ins) != 0) goto inval; + WrRd(next); + next = RdR1() + (get_ii(ins) << 1); + break; + case OC_JAL: + WrRd(next); + next = pc + get_ij(ins); + break; + case OC_SYSTEM: + goto inval; + default: + inval: + return; + } +#if DO_TRACK + for (unsigned n = 1; n < 32; n++) { + if (s->x[n] != last[n]) { + printf(" (%s = 0x%08x)\n", + regname[n], s->x[n]); + } + } +#endif } } int main(int argc, char** argv) { - rvstate s; + rvstate_t s; if (load_image("out/hello.bin", memory, sizeof(memory)) < 0) return -1; memset(&s, 0, sizeof(s)); s.pc = 0x80000000; diff --git a/start.S b/start.S @@ -1,9 +1,29 @@ +#define PASS .long 0x0000000b // _exiti 0 +#define FAIL .long 0xFFF0000b // _exiti -1 +#define PUTC .long 0x0005500b // _putc a0 + .globl _start _start: - jal ra, main +#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 - nop - mv x3, x4 - j . + PASS