riscv

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

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++++
AMakefile | 42++++++++++++++++++++++++++++++++++++++++++
Ahello.c | 13+++++++++++++
Ainstab.txt | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amkinstab.c | 38++++++++++++++++++++++++++++++++++++++
Ariscv.h | 43+++++++++++++++++++++++++++++++++++++++++++
Arvdis.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arvsim.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asimple.ld | 15+++++++++++++++
Astart.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 .