You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a simple and readable **RISC-V RV32IMAC emulator** written in pure Python. It supports machine mode, atomic instructions (A extension), compressed instructions (RVC extension), multiply/divide instructions (M extension), and can run programs compiled with **Newlib** or **Newlib-nano**. It is designed for educational use, experimentation, and portability — not for high performance or full system emulation.
3
+
This is a simple and readable **RISC-V RV32IMAC emulator** written in pure Python. It supports machine mode, multiply/divide instructions (M extension), atomic instructions (A extension), compressed instructions (C extension), and can run programs compiled with **Newlib** or **Newlib-nano**. It is designed for educational use, experimentation, and portability — not for high performance or full system emulation.
4
4
5
5
## ✅ Features
6
6
7
-
-**Implements the full RV32I base integer ISA**
8
-
-**Implements the M extension** with multiply (`MUL`, `MULH`, `MULHSU`, `MULHU`) and divide (`DIV`, `DIVU`, `REM`, `REMU`) instructions
9
-
-**Implements the A extension** with all 11 atomic memory operations (`LR.W`, `SC.W`, `AMOSWAP.W`, `AMOADD.W`, `AMOXOR.W`, `AMOAND.W`, `AMOOR.W`, `AMOMIN.W`, `AMOMAX.W`, `AMOMINU.W`, `AMOMAXU.W`) and proper LR/SC reservation tracking
10
-
-**Implements the RVC (Compressed) extension** with full support for 16-bit compressed instructions, achieving 25-30% code density improvement
7
+
-**Implements the full RV32I base integer ISA** with the **M extension** (multiply and divide instructions) and the **A extension** (atomic memory operations)
8
+
-**Implements the C extension** (compressed instructions), switchable at run time
11
9
-**Implements all RV32MI machine-mode instructions and trap mechanisms**, including synchronous traps (`ecall`, `ebreak`, illegal instruction trap), asynchronous traps (machine timer interrupt), `mret`, and the **Zicsr (Control Status Registers) extension** and registers (`mstatus`, `mepc`, `mtvec`, `mcause`, `mscratch`, ...)
12
10
-**Supports loading ELF and flat binary formats**
13
11
-**Supports terminal I/O**, both "cooked" and raw
14
12
-**Provides most of the system calls needed by [Newlib](https://en.wikipedia.org/wiki/Newlib)**: `_write`, `_read`, `_exit`, **dynamic memory allocation** (`_sbrk`), **file I/O** (`_open`, `_close`, `_fstat`, `_lseek`, ...)
15
13
-**Supports argc/argv program arguments**
16
14
-**Supports memory-mapped IO** and provides a **UART peripheral** using a pseudo-terminal, and a **memory-mapped block device** backed by an image file
17
-
-**Passes all `rv32ui`, `rv32mi`, `rv32uc`, `rv32um`, and `rv32ua` unit tests** (60 tests total) provided by [RISC-V International](https://github.com/riscv-software-src/riscv-tests)
15
+
-**Passes all `rv32ui`, `rv32mi`, `rv32um`, `rv32ua`, and `rv32uc` unit tests** provided by [RISC-V International](https://github.com/riscv-software-src/riscv-tests)
18
16
-**Supports logging** of register values, function calls, system calls, traps, invalid memory accesses, and violations of invariants
19
17
- Runs [MicroPython](https://micropython.org/), [CircuitPython](https://circuitpython.org/) with emulated peripherals, and [FreeRTOS](https://www.freertos.org/) with preemptive multitasking
20
18
- Self-contained, modular, extensible codebase. Provides a **Python API** enabling users to control execution, inspect state, and script complex tests directly in Python.
|`--rvc`| Enable RVC (compressed instructions) support for 16-bit instructions |
90
89
|`--raw-tty`| Enable raw terminal mode |
91
90
|`--no-color`| Remove ANSI colors in debugging output |
92
91
|`--log LOG_FILE`| Log debug information to file `LOG_FILE`|
@@ -99,7 +98,7 @@ make all
99
98
100
99
The Makefile supports building with different RISC-V extensions, e.g., to build with rv32iac_zicsr (RV32IMAC):
101
100
```
102
-
make RVC=1 MUL=1 RVA=1 all
101
+
make RVM=1 RVA=1 RVC=1 all
103
102
```
104
103
105
104
If you just want to **test the emulator without installing a RISC-V compiler**, you will find pre-built binaries in `prebuilt/`.
@@ -207,7 +206,7 @@ and connect to the console using your favorite terminal program, e.g., `screen /
207
206
208
207
### Using the Python API
209
208
210
-
The emulator provides a Python API that allows users to control execution, set and inspect state, and run complex tests directly from Python programs. Here is an example of how you can load and run a simple program:
209
+
The emulator provides a Python API that allows users to control execution, set and inspect state, and run complex tests directly from Python programs. Here is an example of how you can load and run a simple RV32I program:
211
210
```python
212
211
from cpu importCPU
213
212
from ram importRAM
@@ -250,7 +249,7 @@ make
250
249
cd -
251
250
```
252
251
253
-
The script automatically runs all RV32UI, RV32MI, RV32UC, and RV32UM[RISC-V unit tests](https://github.com/riscv-software-src/riscv-tests) in `riscv-tests/`. The emulator passes all of them.
252
+
The script automatically runs all RV32UI, RV32MI, RV32UM, RV32UA, and RV32UC[RISC-V unit tests](https://github.com/riscv-software-src/riscv-tests) in `riscv-tests/`. The emulator passes all of them.
254
253
```
255
254
./run_unit_tests.py
256
255
Test rv32ui-p-bltu : PASS
@@ -354,27 +353,19 @@ Test rv32uc-p-rvc : PASS
354
353
The emulator achieves **over 2 MIPS** (million instructions per second) using Python 3.12 (Anaconda distribution) on a Macbook Pro (M1, 2020) running macOS Sequoia. Execution times for some binaries in `prebuilt/`:
355
354
```
356
355
time ./riscv-emu.py prebuilt/test_newlib2.elf
357
-
./riscv-emu.py prebuilt/test_newlib2.elf 11.43s user 0.05s system 99% cpu 11.506 total
356
+
./riscv-emu.py prebuilt/test_newlib2.elf 1.71s user 0.03s system 98% cpu 1.772 total
358
357
```
359
358
```
360
359
time ./riscv-emu.py prebuilt/test_newlib4.elf
361
-
./riscv-emu.py prebuilt/test_newlib4.elf 4.90s user 0.03s system 99% cpu 4.973 total
360
+
./riscv-emu.py prebuilt/test_newlib4.elf 0.37s user 0.03s system 94% cpu 0.416 total
362
361
```
363
362
```
364
363
time ./riscv-emu.py prebuilt/test_newlib6.elf
365
-
./riscv-emu.py prebuilt/test_newlib6.elf 75.85s user 0.24s system 99% cpu 1:16.37 total
364
+
./riscv-emu.py prebuilt/test_newlib6.elf 76.19s user 0.29s system 99% cpu 1:16.56 total
366
365
```
367
366
368
367
Running the emulator with [PyPy](https://pypy.org/) yields a speedup of almost 4x over CPython, achieving **over 9 MIPS**.
369
368
```
370
-
time pypy3 ./riscv-emu.py prebuilt/test_newlib2.elf
371
-
pypy3 ./riscv-emu.py prebuilt/test_newlib2.elf 2.76s user 0.06s system 97% cpu 2.891 total
372
-
```
373
-
```
374
-
time pypy3 ./riscv-emu.py prebuilt/test_newlib4.elf
375
-
pypy3 ./riscv-emu.py prebuilt/test_newlib4.elf 1.24s user 0.03s system 99% cpu 1.276 total
376
-
```
377
-
```
378
369
time pypy3 ./riscv-emu.py prebuilt/test_newlib6.elf
379
-
pypy3 ./riscv-emu.py prebuilt/test_newlib6.elf 19.82s user 0.15s system 99% cpu 20.046 total
370
+
pypy3 ./riscv-emu.py prebuilt/test_newlib6.elf 19.77s user 0.11s system 99% cpu 20.009 total
0 commit comments