Open-source project
sysprog21/rv32emu avatar
sysprog21/rv32emu

rv32emu models a RISC-V RV32 core in C, with a JIT when you outgrow the interpreter

Compact and Efficient RISC-V RV32I[MAFC] emulator

593 stars156 forksCMIT

At a glance

What is it?
rv32emu is a compact RISC-V RV32I[MAFC] emulator written in C99, with an ELF loader, a Newlib system-call layer, enough system emulation to boot an RV32 Linux kernel, a GDB stub and a tiered JIT. It is MIT licensed, and the documentation is split across seventeen files so that each feature has a page of its own.
Who is it for?
Adopt rv32emu if you are teaching or experimenting with a RISC-V RV32 processor, want to run bare-metal and Linux binaries without hardware, or need a debugger-attached emulator small enough to read in an afternoon. Skip it if you need a production virtual machine, since the vector extension is only partially supported and the project positions itself as an educational tool.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

An exercise in modelling a processor, written to be read

rv32emu is an emulator for the 32 bit RISC-V processor model, and the README is explicit about what kind of project this is. It serves as an exercise in modeling a modern RISC-based processor, demonstrating the device's operations without the complexities of a hardware implementation, and the code is designed to be accessible and expandable, which makes it an ideal educational tool and starting point for customization. The implementation is primarily written in C99, using C11 atomics for memory management, with an explicit focus on efficiency and readability. Those two goals together are the design brief. An emulator that is fast but unreadable teaches nothing about the architecture, and one that is beautiful but slow is not usable for the system emulation the project supports. The primary language is C, and the licence is a permissive MIT-style one, so reading it, borrowing a file from it or shipping it inside a product are all unencumbered choices.

Full RV32I coverage plus the extensions that matter

The feature list starts with a fast interpreter that faithfully executes the complete RV32 instruction set, and the coverage is spelled out in detail. You get the full of RV32I and RV32E, plus the M extension for integer multiply and divide, the A extension for atomics, the F extension for single-precision floating point, the C extension for compressed instructions, and the Zba, Zbb, Zbc and Zbs bit-manipulation extensions. The V extension for vector instructions is only partially supported, with decode plus partial execution at VLEN=128, and it is opt-in through the configuration menu where you select the V Vector Extension entry. That last point is the boundary of the project in one line. The compressed and bit-manipulation extensions are complete, the vector extension is not, and the fact that the vector work is behind a configuration switch rather than a separate branch suggests it is a work in progress rather than a finished feature.

From user-mode ELF to booting a Linux kernel

The emulation side splits into two levels, and the project supports both. At the user-mode level there is a built-in ELF loader for user-mode emulation and a Newlib-compatible system-call layer for standalone programs, which means a program compiled against Newlib for RISC-V can run without you writing a syscall layer. Above that sits minimal system emulation, described as capable of booting an RV32 Linux kernel and running user-space binaries. That second capability is what turns the project from an instruction set exerciser into a system simulator, and it comes with its own documentation covering Linux booting, virtio block devices and bootargs. Around that core there are two specialised systems. An SDL-based display, event and audio system call layer exists for running video games, which is what the Doom and Quake demos rely on. And a WebAssembly build covers both user-mode and system emulation with SDL graphics and audio in modern browsers, so the emulator runs in a browser tab without a local build.

Building it: SDL2, a defconfig, and a test run

The emulator relies on the SDL2 library and the SDL2_Mixer library for full functionality, and the install commands are given per platform.

shell
* macOS: `brew install sdl2 sdl2_mixer`
shell
* Ubuntu Linux / Debian: `sudo apt install libsdl2-dev libsdl2-mixer-dev`

The build itself is three commands, and the first one is not optional, because the Makefile errors out if there is no `.config` file.

shell
$ make defconfig      # Apply default configuration
$ make                # Build rv32emu
$ make check          # Run tests

The Makefile also spells out what the configuration targets are, and the list is the clearest statement of the project's scope. There is a default configuration with tier-1 JIT, an interactive `make config` menu, a CI configuration with architecture tests, a default configuration without the JIT, a tiered JIT configuration, a minimal build for embedded use, and system emulation variants with and without the JIT, plus WebAssembly builds for both user-mode and system modes. The Makefile also enforces a minimum GNU Make version of 3.80, because it uses order-only prerequisites.

The tiered JIT and the two demo games

Performance comes from a tiered JIT compilation approach, which the README lists as a feature in its own right, for a performance boost while maintaining a small footprint. The architecture of that approach is the subject of a paper by the authors, Accelerate RISC-V Instruction Set Simulation by Tiered JIT Compilation, presented at VMIL 2024, the 16th ACM SIGPLAN International Workshop on Virtual Machines and Intermediate Languages, and the citation is given in the README along with a BibTeX entry. The configuration names make the tiering visible, since the default configuration is described as tier-1 JIT while a separate target is described as tiered JIT with both T1C and T2C. Running the demos is a single make target each, which is the quickest way to see the whole system working.

shell
$ make doom           # Doom (1993)
$ make quake          # Quake (requires RV32F, on by default)

The Quake target is annotated as requiring RV32F, which the README notes is on by default, so the floating point extension is not something you have to turn on for that demo. The documentation table points to a separate page for code generation and JIT internals, and another for benchmarks and continuous benchmarking, so the performance story is documented rather than asserted.

Debugging, testing and the documentation map

Two capabilities make this usable as an engineering tool rather than only a teaching example. The first is remote debugging through the GDB Remote Serial Protocol, with its own page covering the GDB stub and a register JSON dump, which means you can attach a real debugger to an emulated target. The second is architecture testing, documented on a page describing RISCOF and RISC-V architecture tests, which is a way of checking that the emulator implements the specification rather than just that it runs the author's own test programs. The documentation is unusually well organised, and the table in the README is a map of the project: build options, Kconfig and tiered JIT setup; system emulation with Linux, virtio block devices and bootargs; the WebAssembly build; the GDB stub and register dump; RISCOF and architecture tests; benchmarks; static analysis tools such as rv_histogram and rv_profiler; the Docker image; the demo applications; code generation and JIT internals; the RISC-V instruction reference; Newlib system calls; prebuilt binaries; base image preparation; networking guidance; and sound guidance. The repository also ships a Dockerfile that builds on Alpine 3.21 with the SDL2 development packages and produces the user-mode, system-mode and histogram executables.

Try it in a browser before you build anything

There is a hosted WebAssembly build of rv32emu that runs entirely in the browser, and the README presents it as the way to try the project without building locally. Two demo pages are linked, one for user-mode emulation and one for system emulation, and each mode page has a navigation button that switches directly to the other. That is worth pausing on for a moment, because it says something about the WebAssembly build's completeness. A browser build that can run a full system emulation with SDL graphics and audio is not a limited subset; it is the same emulator compiled to a different target. The landing page is at the rv32emu-demo path and the two modes hang off it. For an evaluation, that is the fastest way to form a view of what the project does, and the fastest way to check whether the browser build and your local build behave the same, which the documentation on the WebAssembly build covers in more detail. The release history is v1.0 in October 2024, v1.1 in May 2025 and v1.2 in January 2026, with the last push on 2026-10-19.

Editorial conclusion

Adopt rv32emu if you are teaching or experimenting with a RISC-V RV32 processor, want to run bare-metal and Linux binaries without hardware, or need a debugger-attached emulator small enough to read in an afternoon. Skip it if you need a production virtual machine, since the vector extension is only partially supported and the project positions itself as an educational tool. Before you start, choose a configuration deliberately with `make config`, because the default build already enables a JIT and the interpreter-only build is a different target, and read the system emulation documentation before attempting a Linux boot.

Frequently asked questions

How do I build and test rv32emu?

Install SDL2 and SDL2_Mixer for your platform, then run `make defconfig` to apply the default configuration, `make` to build the emulator, and `make check` to run the tests. The build fails without a `.config` file, so `make defconfig` comes first.

Which RISC-V extensions does rv32emu implement?

Full coverage of RV32I and RV32E plus the M, A, F and C extensions and the Zba, Zbb, Zbc and Zbs bit-manipulation extensions. The V vector extension is only partially supported, with decode plus partial execution at VLEN=128, and is opt-in through the configuration menu.

Can rv32emu boot a Linux kernel?

Yes. The project includes minimal system emulation capable of booting an RV32 Linux kernel and running user-space binaries, with documentation covering Linux booting, virtio block devices and bootargs.

Does rv32emu support debugging and a browser build?

Yes to both. Remote debugging works through the GDB Remote Serial Protocol, and there is a WebAssembly build for user-mode and system emulation with SDL graphics and audio, plus a hosted online demo for both modes that runs entirely in the browser.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. sysprog21/rv32emu on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sysprog21-rv32emu.svg)](https://hysenlabs.com/projects/sysprog21-rv32emu)

Was this useful?