commit b6b3810842a068f27100369152fef579a38b8d82
parent 3c2728dcacd6ffade0618e79e00c1bf2651a8ea2
Author: Brian Swetland <swetland@frotz.net>
Date: Tue, 15 Oct 2019 21:31:22 -0700
initial checkin
- disassembler basically works, needs more aliases
- suspect some immediate unpacking is broken
- sim just loads and disassembles at the moment
Diffstat:
A | .gitignore | | | 4 | ++++ |
A | Makefile | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
A | hello.c | | | 13 | +++++++++++++ |
A | instab.txt | | | 54 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | mkinstab.c | | | 38 | ++++++++++++++++++++++++++++++++++++++ |
A | riscv.h | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | rvdis.c | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | rvsim.c | | | 72 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | simple.ld | | | 15 | +++++++++++++++ |
A | start.S | | | 9 | +++++++++ |
10 files changed, 355 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,4 @@
+out/
+bin/
+gen/
+.*
diff --git a/Makefile b/Makefile
@@ -0,0 +1,42 @@
+
+TOOLCHAIN := ../toolchains/riscv32-elf-7.3.0-Linux-x86_64/bin/riscv32-elf-
+
+CC := $(TOOLCHAIN)gcc
+OBJDUMP := $(TOOLCHAIN)objdump
+OBJCOPY := $(TOOLCHAIN)objcopy
+
+CFLAGS := -march=rv32i -mabi=ilp32 -O2
+CFLAGS += -ffreestanding -nostdlib
+CFLAGS += -Wl,-Bstatic,-T,simple.ld
+
+all: bin/rvsim out/hello.bin out/hello.elf out/hello.lst
+
+out/%.bin: out/%.elf
+ @mkdir -p out
+ $(OBJCOPY) -O binary $< $@
+
+out/%.lst: out/%.elf
+ @mkdir -p out
+ $(OBJDUMP) -D $< > $@
+
+HELLO_SRCS := start.S hello.c
+out/hello.elf: $(HELLO_SRCS) Makefile
+ @mkdir -p out
+ $(CC) $(CFLAGS) -o $@ $(HELLO_SRCS)
+
+RVSIM_SRCS := rvsim.c rvdis.c
+bin/rvsim: $(RVSIM_SRCS) Makefile gen/instab.h
+ @mkdir -p bin
+ gcc -O3 -Wall -o $@ $(RVSIM_SRCS)
+
+bin/mkinstab: mkinstab.c
+ @mkdir -p bin
+ gcc -O3 -Wall -o $@ $<
+
+gen/instab.h: instab.txt bin/mkinstab
+ @mkdir -p gen
+ bin/mkinstab < instab.txt > gen/instab.h
+
+clean:
+ rm -rf out bin gen
+
diff --git a/hello.c b/hello.c
@@ -0,0 +1,13 @@
+// Copyright 2019, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+volatile unsigned *uart = (void*) 0x80001000;
+
+int main() {
+ unsigned n;
+ for (n = 0; n < 10; n++) {
+ *uart = n;
+ }
+ return 42;
+}
+
diff --git a/instab.txt b/instab.txt
@@ -0,0 +1,54 @@
+# Copyright 2018, Brian Swetland <swetland@frotz.net>
+# Licensed under the Apache License, Version 2.0.
+
+-------------------------0110111 lui %d, %u
+-------------------------0010111 auipc %d, %u
+--------------------000001101111 j %j
+--------------------000011101111 jal %j
+-------------------------1101111 jal %d, %j
+00000000000000001000000001100111 ret
+000000000000-----000000001100111 jr %1
+-----------------000000001100111 jr %i(%1)
+000000000000-----000000011100111 jalr %1
+-----------------000000011100111 jalr %i(%1)
+-----------------000-----1100111 jalr %d, %i(%1)
+-----------------000-----1100011 beq %1, %2, %b
+-----------------001-----1100011 bne %1, %2, %b
+-----------------100-----1100011 blt %1, %2, %b
+-----------------101-----1100011 bge %1, %2, %b
+-----------------110-----1100011 bltu %1, %2, %b
+-----------------111-----1100011 bgeu %1, %2, %b
+-----------------000-----0000011 lb %d, %i(%1)
+-----------------001-----0000011 lh %d, %i(%1)
+-----------------010-----0000011 lw %d, %i(%1)
+-----------------100-----0000011 lbu %d, %i(%1)
+-----------------101-----0000011 lhu %d, %i(%1)
+-----------------000-----0100011 sb %2, %s(%1)
+-----------------001-----0100011 sh %2, %s(%1)
+-----------------010-----0100011 sw %2, %s(%1)
+00000000000000000000000000010011 nop
+------------00000000-----0010011 li %d, %i
+000000000000-----000-----0010011 mv %d, %1
+-----------------000-----0010011 addi %d, %1, %i
+-----------------010-----0010011 slti %d, %1, %i
+-----------------011-----0010011 sltui %d, %1, %i
+-----------------100-----0010011 xori %d, %1, %i
+-----------------110-----0010011 ori %d, %1, %i
+-----------------111-----0010011 andi %d, %1, %i
+0000000----------001-----0010011 slli %d, %1, %x
+0000000----------101-----0010011 srli %d, %1, %x
+0100000----------101-----0010011 srai %d, %1, %x
+0000000----------000-----0110011 add %d, %1, %2
+0100000----------000-----0110011 sub %d, %1, %2
+0000000----------001-----0110011 sll %d, %1, %2
+0000000----------010-----0110011 slt %d, %1, %2
+0000000----------011-----0110011 sltu %d, %1, %2
+0000000----------100-----0110011 xor %d, %1, %2
+0000000----------101-----0110011 srl %d, %1, %2
+0100000----------101-----0110011 sra %d, %1, %2
+0000000----------110-----0110011 or %d, %1, %2
+0000000----------111-----0110011 and %d, %1, %2
+-----------------000-----0001111 fence
+00000000000000000000000001110011 ecall
+00000000000100000000000001110011 ebreak
+-------------------------------- unknown
diff --git a/mkinstab.c b/mkinstab.c
@@ -0,0 +1,38 @@
+// Copyright 2019, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+
+int main(int argc, char** argv) {
+ char line[128];
+ while (fgets(line, sizeof(line), stdin) != NULL) {
+ unsigned end = strlen(line);
+ while (end > 0) {
+ end--;
+ if (!isspace(line[end])) break;
+ line[end] = 0;
+ }
+ if ((line[0] == 0) || (line[0] == '#') ||
+ isspace(line[0]) || (end < 34)) {
+ continue;
+ }
+ uint32_t mask = 0, bits = 0;
+ for (unsigned n = 0; n < 32; n++) {
+ uint32_t bit = 1U << (31 - n);
+ switch (line[n]) {
+ case '1':
+ mask |= bit;
+ bits |= bit;
+ break;
+ case '0':
+ mask |= bit;
+ break;
+ }
+ }
+ printf("{ 0x%08x, 0x%08x, \"%s\" },\n", mask, bits, line + 33);
+ }
+ return 0;
+}
diff --git a/riscv.h b/riscv.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <stdint.h>
+
+// extract instruction fields
+static inline uint32_t get_rd(uint32_t ins) {
+ return (ins >> 7) & 0x1f;
+}
+static inline uint32_t get_r1(uint32_t ins) {
+ return (ins >> 15) & 0x1f;
+}
+static inline uint32_t get_r2(uint32_t ins) {
+ return (ins >> 20) & 0x1f;
+}
+static inline uint32_t get_ii(uint32_t ins) {
+ return ((int32_t)ins) >> 20;
+}
+static inline uint32_t get_is(uint32_t ins) {
+ return ((((int32_t)ins) >> 20) & 0xffffffe0) | ((ins >> 7) & 0x1f);
+}
+static inline uint32_t get_ib(uint32_t ins) {
+ return ((ins >> 7) & 0x1e) |
+ ((ins >> 20) & 0x7e0) |
+ ((ins << 4) & 0x800) |
+ (((int32_t)ins) >> 19);
+}
+static inline uint32_t get_iu(uint32_t ins) {
+ return ins & 0xFFFFF000;
+}
+static inline uint32_t get_ij(uint32_t ins) {
+ return (((int32_t)ins) >> 11) |
+ (ins & 0xFF000) |
+ ((ins >> 9) & 0x800) |
+ ((ins >> 20) & 0x7fe);
+}
+
+#define OP_LUI 0b0110111
+#define OP_AUIPC 0b0010111
+#define OP_JAL 0b1101111
+#define OP_JALR 0b1100111
+#define OP_B
+
+void rvdis(uint32_t ins, char *out);
diff --git a/rvdis.c b/rvdis.c
@@ -0,0 +1,65 @@
+// Copyright 2019, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+#include <string.h>
+#include <stdio.h>
+
+#include "riscv.h"
+
+static char *append_str(char *buf, const char *s) {
+ while (*s) *buf++ = *s++;
+ return buf;
+}
+
+static char *append_i32(char *buf, int32_t n) {
+ return buf + sprintf(buf, "%d", n);
+}
+
+static const char* regname[32] = {
+#if 0
+ "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
+ "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
+ "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+ "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
+#else
+ "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",
+#endif
+};
+
+typedef struct {
+ uint32_t mask;
+ uint32_t bits;
+ const char* fmt;
+} rvins_t;
+
+static rvins_t instab[] = {
+#include "gen/instab.h"
+};
+
+void rvdis(uint32_t ins, char *out) {
+ unsigned n = 0;
+ while ((ins & instab[n].mask) != instab[n].bits) n++;
+ const char* fmt = instab[n].fmt;
+ char c;
+ while ((c = *fmt++) != 0) {
+ if (c != '%') {
+ *out++ = c;
+ continue;
+ }
+ switch (*fmt++) {
+ case '1': out = append_str(out, regname[get_r1(ins)]); break;
+ case '2': out = append_str(out, regname[get_r2(ins)]); break;
+ case 'd': out = append_str(out, regname[get_rd(ins)]); break;
+ case 'i': out = append_i32(out, get_ii(ins)); break;
+ case 'j': out = append_i32(out, get_ij(ins)); break;
+ case 'b': out = append_i32(out, 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 'x': out = append_i32(out, get_r2(ins)); break;
+ }
+ }
+ *out = 0;
+}
diff --git a/rvsim.c b/rvsim.c
@@ -0,0 +1,72 @@
+// 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 "riscv.h"
+
+uint8_t memory[32768];
+
+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;
+}
+
+uint32_t rd32(uint32_t addr) {
+ addr &= (sizeof(memory) - 1);
+ return ((uint32_t*) memory)[addr >> 2];
+}
+
+void wr32(uint32_t addr, uint32_t val) {
+ addr &= (sizeof(memory) - 1);
+ ((uint32_t*) memory)[addr >> 2] = val;
+}
+
+typedef struct {
+ uint32_t x[32];
+ uint32_t pc;
+} rvstate;
+
+void rvsim(rvstate* s) {
+ char dis[128];
+ uint32_t pc, ins;
+ pc = s->pc;
+ while (pc < 64) {
+ ins = rd32(pc);
+ rvdis(ins, dis);
+ printf("%08x: %08x %s\n", pc, ins, dis);
+ pc += 4;
+ }
+}
+
+
+int main(int argc, char** argv) {
+ rvstate s;
+ if (load_image("out/hello.bin", memory, sizeof(memory)) < 0) return -1;
+ memset(&s, 0, sizeof(s));
+ rvsim(&s);
+ return 0;
+}
+
diff --git a/simple.ld b/simple.ld
@@ -0,0 +1,15 @@
+
+MEMORY {
+ mem : ORIGIN = 0x00000000, LENGTH = 0x00020000
+}
+
+SECTIONS {
+ .memory : {
+ . = 0x000000;
+ start*(.text);
+ *(.text);
+ *(*);
+ end = .;
+ . = ALIGN(4);
+ } > mem
+}
diff --git a/start.S b/start.S
@@ -0,0 +1,9 @@
+
+.globl _start
+
+_start:
+ jal ra, main
+ jal main
+ nop
+ mv x3, x4
+ j .