README (2918B)
1 rvemu 2 ===== 3 This is a compact RV32I instruction simulator written in C as part of a 4 MEng thesis on low-latency execution strategies. It is still in development 5 and there is no release version. 6 7 So far, it can run handwritten RISC-V assembly programs, but also 8 freestanding C code (tested with riscv64-unknown-elf-gcc), compiled as flat 9 non-ELF binaries. 10 11 Unlike my other tools, this project is an experimental environment and as 12 such, it is intended for hands-on use. It includes separate execution, 13 monitoring and testing components and offers an interface that requires 14 familiarity with the projects internals. 15 16 17 Features: 18 --------- 19 - simple execution API for embedding in custom drivers 20 - static disassembler with a single function API 21 - interactive monitor supporting continuous execution, single-stepping, 22 memory/register inspection and static disassembly 23 - separate regression harness with a couple dozen tests, including small 24 programs, instruction edge cases and expected traps 25 26 27 Planned features: 28 ----------------- 29 - ELF loading 30 - JIT compilation component for x86-64 (including a wrapper) 31 - latency benchmarking scaffolding 32 33 34 Not currently planned: 35 ---------------------- 36 - further RISC-V extensions, like M 37 - RV64 support 38 - MMU, privileged modes 39 - GDB protocol support 40 - peripheral emulation such as UARTs 41 42 43 Dependencies: 44 ------------- 45 - C compiler, make, host C stdlib 46 - Optional: GNU Readline 47 - Optional: RISC-V cross-toolchain for building guest programs 48 49 50 Clone and use 51 ------------- 52 Clone the repository with: 53 54 $ git clone git://mcdim.xyz/revmu.git 55 56 Build monitor environment without GNU readline: 57 58 $ make 59 60 Build monitor environment with GNU readline): 61 62 $ make READLINE=1 63 64 Run: 65 66 $ ./emu 67 68 Build and run tests: 69 70 $ make test 71 $ ./test 72 73 74 Design philosophy: 75 ------------------ 76 - keep the hot path clean and minimal for low latency and high throughput 77 - traps are recorded by the core and returned to the driver to define 78 policy handling 79 80 81 Interpreter API: 82 ---------------- 83 The interpreter itself consists of exec.c, exec.h, decode.h, mem.h, trap.h 84 85 A driver needs to 86 1. #include "exec.h" 87 2. allocate and zero a uint8_t array of MEMSIZE bytes as memory 88 (here named mem) 89 3. zero-initialize a cpu_state_t struct (here named cpu) 90 91 To execute a step, use the function: 92 93 void cpu_step(cpu_state_t *cpu, uint8_t *mem); 94 95 A step executions a single instruction or records a trap. The driver 96 must inspect CPU status afterward. 97 98 View exec.h and trap.h for CPU and trap internals/initializations. 99 100 101 Disassembly API: 102 ---------------- 103 The disassembly component consits of disasm.c and disasm.h and works 104 through this single function: 105 106 void disassemble_instruction(uint32_t inst); 107 108 It prints directly to stdout. 109 110 111 Memory size 112 ----------- 113 The interpreter can handle arbitrary memory sizes, as long as they are 114 defined in exec.h (MEMSIZE). Some tests, however, assume 4096 bytes and 115 will fail otherwise.