commit 3292d1830178f0c241f6d33718662d29d04a528a
parent 90a954dd1ca4cce3846c5fde6e7b6c2bc9595e01
Author: Brian Swetland <swetland@frotz.net>
Date: Sat, 2 Nov 2019 04:36:28 -0700
rvsim: support RV32IM
- add mul and div instructions
Diffstat:
M | Makefile | | | 4 | ++-- |
M | instab.txt | | | 8 | ++++++++ |
M | riscv.h | | | 32 | ++++++++++++++++++++++---------- |
M | rvsim.c | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
4 files changed, 87 insertions(+), 30 deletions(-)
diff --git a/Makefile b/Makefile
@@ -5,7 +5,7 @@ CC := $(TOOLCHAIN)gcc
OBJDUMP := $(TOOLCHAIN)objdump
OBJCOPY := $(TOOLCHAIN)objcopy
-CFLAGS := -march=rv32i -mabi=ilp32 -O2
+CFLAGS := -march=rv32i -mabi=ilp32 -O3
CFLAGS += -ffreestanding -nostdlib
CFLAGS += -Wl,-Bstatic,-T,simple.ld
@@ -27,7 +27,7 @@ out/hello.elf: $(HELLO_SRCS) Makefile
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)
+ gcc -g -O3 -Wall -o $@ $(RVSIM_SRCS)
bin/mkinstab: mkinstab.c
@mkdir -p bin
diff --git a/instab.txt b/instab.txt
@@ -60,6 +60,14 @@
0100000----------101-----0110011 sra %d, %1, %2
0000000----------110-----0110011 or %d, %1, %2
0000000----------111-----0110011 and %d, %1, %2
+0000001----------000-----0110011 mul %d, %1, %2
+0000001----------001-----0110011 mulh %d, %1, %2
+0000001----------010-----0110011 mulhsu %d, %1, %2
+0000001----------011-----0110011 mulhu %d, %1, %2
+0000001----------100-----0110011 div %d, %1, %2
+0000001----------101-----0110011 divu %d, %1, %2
+0000001----------110-----0110011 rem %d, %1, %2
+0000001----------111-----0110011 remu %d, %1, %2
-----------------000-----0001111 fence
-----------------000-----0001011 _exiti %i
-----------------100-----0001011 _exit %1
diff --git a/riscv.h b/riscv.h
@@ -52,6 +52,7 @@ static inline uint32_t get_iC(uint32_t ins) {
return ins >> 20;
}
+
// opcode constants (6:0)
#define OC_LOAD 0b0000011
#define OC_CUSTOM_0 0b0001011
@@ -90,17 +91,28 @@ static inline uint32_t get_iC(uint32_t ins) {
#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
+#define F3_ADD 0b000
+#define F3_SLL 0b001
+#define F3_SLT 0b010
+#define F3_SLTU 0b011
+#define F3_XOR 0b100
+#define F3_SRL 0b101
+#define F3_OR 0b110
+#define F3_AND 0b111
+
// OC_OP (14:12) (fn7==0b0100000)
-#define F3_SUB 0b1000
-#define F3_SRA 0b1101
+#define F3_SUB 0b000
+#define F3_SRA 0b101
+
+// OC_OP (14:12) (fn7==0b0000001)
+#define F3_MUL 0b000
+#define F3_MULH 0b001
+#define F3_MULHSU 0b010
+#define F3_MULHU 0b011
+#define F3_DIV 0b100
+#define F3_DIVU 0b101
+#define F3_REM 0b110
+#define F3_REMU 0b111
// further discrimination of OC_BRANCH
#define F3_BEQ 0b000
diff --git a/rvsim.c b/rvsim.c
@@ -9,10 +9,10 @@
#include "riscv.h"
#include "rvsim.h"
-#define DO_TRACE_INS 0
-#define DO_TRACE_TRAPS 0
-#define DO_TRACE_MEM_WR 0
-#define DO_TRACE_REG_WR 0
+#define DO_TRACE_INS 1
+#define DO_TRACE_TRAPS 1
+#define DO_TRACE_MEM_WR 1
+#define DO_TRACE_REG_WR 1
#define RVMEMBASE 0x80000000
#define RVMEMSIZE 32768
@@ -280,20 +280,53 @@ int rvsim_exec(rvstate_t* s, uint32_t _pc) {
case OC_OP: {
uint32_t a = RdR1();
uint32_t b = RdR2();
- uint32_t n;
- if (ins & 0xBE000000) 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;
+ uint32_t n = get_fn3(ins);
+ switch (ins >> 25) {
+ case 0b0000000:
+ switch (n) {
+ 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;
+ }
+ break;
+ case 0b0000001:
+ switch (n) {
+ case F3_MUL: n = a * b; break;
+ case F3_MULH: n = ((int64_t)(int32_t)a * (int64_t)(int32_t)b) >> 32; break;
+ case F3_MULHSU: n = ((int64_t)(int32_t)a * (uint64_t)b) >> 32; break;
+ case F3_MULHU: n = ((uint64_t)a * (uint64_t)b) >> 32; break;
+ case F3_DIV:
+ if (b == 0) { n = 0xffffffff; }
+ else if ((a == 0x80000000) && (b == 0xffffffff)) { n = a; }
+ else { n = ((int32_t)a / (int32_t)b); }
+ break;
+ case F3_DIVU:
+ if (b == 0) { n = 0xffffffff; }
+ else { n = a / b; }
+ break;
+ case F3_REM:
+ if (b == 0) { n = a; }
+ else if ((a == 0x80000000) && (b == 0xffffffff)) { n = 0; }
+ else { n = ((int32_t)a % (int32_t)b); }
+ break;
+ case F3_REMU:
+ if (b == 0) { n = a; }
+ else { n = a % b; }
+ break;
+ }
+ break;
+ case 0b0100000:
+ switch (n) {
+ case F3_SUB: n = a - b; break;
+ case F3_SRA: n = ((int32_t)a) >> (b & 31); break;
+ default: goto inval;
+ }
+ break;
}
WrRd(n);
trace_reg_wr(n);
@@ -392,6 +425,10 @@ trap_pc_align:
inval:
s->mcause = EC_I_ILLEGAL;
s->mtval = ins;
+#if DO_ABORT_INVAL
+ fprintf(stderr," (TRAP ILLEGAL %08x)\n", ins);
+ return -1;
+#endif
trap_common:
s->mepc = pc;
next = s->mtvec & 0xFFFFFFFD;