rvemu

RISC-V RV32I execution engine
git clone git://mcdim.xyz/rvemu.git
Log | Files | Refs | README

commit 6b84f3c15862bbb0f449ea6867ff5237c25e8a0b
parent f03a0c9fd688ec40d0268660b221e742efc40a35
Author: Michail Konstantinos Dimopoulos <mk@mcdim.xyz>
Date:   Tue,  8 Sep 2026 14:34:41 +0300

Added README

Diffstat:
AREADME | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mexec.c | 4----
2 files changed, 115 insertions(+), 4 deletions(-)

diff --git a/README b/README @@ -0,0 +1,115 @@ +rvemu +===== +This is a compact RV32I instruction simulator written in C as part of a +MEng thesis on low-latency execution strategies. It is still in development +and there is no release version. + +So far, it can run handwritten RISC-V assembly programs, but also +freestanding C code (tested with riscv64-unknown-elf-gcc), compiled as flat +non-ELF binaries. + +Unlike my other tools, this project is an experimental environment and as +such, it is intended for hands-on use. It includes separate execution, +monitoring and testing components and offers an interface that requires +familiarity with the projects internals. + + +Features: +--------- +- simple execution API for embedding in custom drivers +- static disassembler with a single function API +- interactive monitor supporting continuous execution, single-stepping, + memory/register inspection and static disassembly +- separate regression harness with a couple dozen tests, including small + programs, instruction edge cases and expected traps + + +Planned features: +----------------- +- ELF loading +- JIT compilation component for x86-64 (including a wrapper) +- latency benchmarking scaffolding + + +Not currently planned: +---------------------- +- further RISC-V extensions, like M +- RV64 support +- MMU, privileged modes +- GDB protocol support +- peripheral emulation such as UARTs + + +Dependencies: +------------- +- C compiler, make, host C stdlib +- Optional: GNU Readline +- Optional: RISC-V cross-toolchain for building guest programs + + +Clone and use +------------- +Clone the repository with: + + $ git clone git://mcdim.xyz/revmu.git + +Build monitor environment without GNU readline: + + $ make + +Build monitor environment with GNU readline): + + $ make READLINE=1 + +Run: + + $ ./emu + +Build and run tests: + + $ make test + $ ./test + + +Design philosophy: +------------------ +- keep the hot path clean and minimal for low latency and high throughput +- traps are recorded by the core and returned to the driver to define + policy handling + + +Interpreter API: +---------------- +The interpreter itself consists of exec.c, exec.h, decode.h, mem.h, trap.h + +A driver needs to +1. #include "exec.h" +2. allocate and zero a uint8_t array of MEMSIZE bytes as memory + (here named mem) +3. zero-initialize a cpu_state_t struct (here named cpu) + +To execute a step, use the function: + + void cpu_step(cpu_state_t *cpu, uint8_t *mem); + +A step executions a single instruction or records a trap. The driver +must inspect CPU status afterward. + +View exec.h and trap.h for CPU and trap internals/initializations. + + +Disassembly API: +---------------- +The disassembly component consits of disasm.c and disasm.h and works +through this single function: + + void disassemble_instruction(uint32_t inst); + +It prints directly to stdout. + + +Memory size +----------- +The interpreter can handle arbitrary memory sizes, as long as they are +defined in exec.h (MEMSIZE). Some tests, however, assume 4096 bytes and +will fail otherwise. diff --git a/exec.c b/exec.c @@ -7,7 +7,6 @@ #include "exec.h" #include "mem.h" #include "decode.h" -#include "disasm.h" #include "trap.h" static inline void print_bin16(uint16_t x) { @@ -211,8 +210,6 @@ static void exec_itype_loads(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { uint32_t addr = (uint32_t)i.imm + cpu->x[i.rs1]; - /* TODO: do I need to check before loading halves and words */ - uint32_t x; switch(i.funct3) { case 0x0: @@ -395,7 +392,6 @@ static void exec_btype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { } else { cpu->pc += 4; } - } static void exec_itype_jalr(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {