mrve32 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mrve32-0.1.0/.gitignore +10 -0
- mrve32-0.1.0/CHANGELOG.md +62 -0
- mrve32-0.1.0/Cargo.lock +140 -0
- mrve32-0.1.0/Cargo.toml +30 -0
- mrve32-0.1.0/LICENSE +52 -0
- mrve32-0.1.0/PKG-INFO +327 -0
- mrve32-0.1.0/README.md +301 -0
- mrve32-0.1.0/benches/mips.rs +75 -0
- mrve32-0.1.0/docs/devices.md +191 -0
- mrve32-0.1.0/include/mrve32_device.h +71 -0
- mrve32-0.1.0/pyproject.toml +42 -0
- mrve32-0.1.0/python/mrve32/__init__.py +70 -0
- mrve32-0.1.0/python/mrve32/_native.pyi +239 -0
- mrve32-0.1.0/python/mrve32/py.typed +0 -0
- mrve32-0.1.0/scripts/arch-test.sh +192 -0
- mrve32-0.1.0/scripts/build-riscv-tests.sh +69 -0
- mrve32-0.1.0/scripts/build-test-firmware.sh +32 -0
- mrve32-0.1.0/src/bin/mrve32.rs +427 -0
- mrve32-0.1.0/src/bus.rs +519 -0
- mrve32-0.1.0/src/cpu/coprocessor.rs +21 -0
- mrve32-0.1.0/src/cpu/csr.rs +326 -0
- mrve32-0.1.0/src/cpu/csr_names.rs +125 -0
- mrve32-0.1.0/src/cpu/decode.rs +904 -0
- mrve32-0.1.0/src/cpu/decode_c.rs +555 -0
- mrve32-0.1.0/src/cpu/disasm.rs +505 -0
- mrve32-0.1.0/src/cpu/instructions.rs +355 -0
- mrve32-0.1.0/src/cpu/mod.rs +1946 -0
- mrve32-0.1.0/src/cpu/trap.rs +177 -0
- mrve32-0.1.0/src/devices/clint.rs +266 -0
- mrve32-0.1.0/src/devices/finisher.rs +99 -0
- mrve32-0.1.0/src/devices/htif.rs +171 -0
- mrve32-0.1.0/src/devices/mod.rs +5 -0
- mrve32-0.1.0/src/devices/ram.rs +195 -0
- mrve32-0.1.0/src/devices/uart.rs +406 -0
- mrve32-0.1.0/src/elf.rs +284 -0
- mrve32-0.1.0/src/lib.rs +35 -0
- mrve32-0.1.0/src/machine.rs +326 -0
- mrve32-0.1.0/src/plugin.rs +562 -0
- mrve32-0.1.0/src/python.rs +1122 -0
- mrve32-0.1.0/src/types.rs +1 -0
- mrve32-0.1.0/tests/arch-test/README.md +56 -0
- mrve32-0.1.0/tests/arch-test/local/rvtest_config.h +44 -0
- mrve32-0.1.0/tests/arch-test/mrve32-rv32imac/link.ld +56 -0
- mrve32-0.1.0/tests/arch-test/mrve32-rv32imac/mrve32-rv32imac.yaml +133 -0
- mrve32-0.1.0/tests/arch-test/mrve32-rv32imac/rvmodel_macros.h +83 -0
- mrve32-0.1.0/tests/arch-test/mrve32-rv32imac/sail.json +786 -0
- mrve32-0.1.0/tests/arch-test/mrve32-rv32imac/test_config.yaml +9 -0
- mrve32-0.1.0/tests/cli.rs +167 -0
- mrve32-0.1.0/tests/compliance.rs +102 -0
- mrve32-0.1.0/tests/decoder_fuzz.rs +112 -0
- mrve32-0.1.0/tests/firmware/hello.c +93 -0
- mrve32-0.1.0/tests/firmware/hello.elf +0 -0
- mrve32-0.1.0/tests/firmware/htif.S +40 -0
- mrve32-0.1.0/tests/firmware/htif.elf +0 -0
- mrve32-0.1.0/tests/firmware/link.ld +21 -0
- mrve32-0.1.0/tests/firmware/start.S +12 -0
- mrve32-0.1.0/tests/interrupts.rs +76 -0
- mrve32-0.1.0/tests/isa/LICENSE +28 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-csr.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-illegal.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-instret_overflow.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-lh-misaligned.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-lw-misaligned.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-ma_addr.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-ma_fetch.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-mcsr.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-sbreak.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-scall.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-sh-misaligned.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-shamt.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-sw-misaligned.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32mi-p-zicntr.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amoadd_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amoand_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amomax_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amomaxu_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amomin_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amominu_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amoor_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amoswap_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-amoxor_w.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ua-p-lrsc.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32uc-p-rvc.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-add.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-addi.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-and.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-andi.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-auipc.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-beq.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-bge.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-bgeu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-blt.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-bltu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-bne.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-fence_i.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-jal.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-jalr.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-lb.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-lbu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-ld_st.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-lh.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-lhu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-lui.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-lw.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-ma_data.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-or.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-ori.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-sb.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-sh.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-simple.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-sll.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-slli.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-slt.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-slti.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-sltiu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-sltu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-sra.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-srai.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-srl.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-srli.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-st_ld.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-sub.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-sw.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-xor.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32ui-p-xori.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32um-p-div.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32um-p-divu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32um-p-mul.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32um-p-mulh.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32um-p-mulhsu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32um-p-mulhu.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32um-p-rem.elf +0 -0
- mrve32-0.1.0/tests/isa/rv32um-p-remu.elf +0 -0
mrve32-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file. The format
|
|
4
|
+
is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
|
|
5
|
+
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
|
6
|
+
(before 1.0, a minor version bump may contain breaking changes).
|
|
7
|
+
|
|
8
|
+
The Rust crates (`mrve32`, `mrve32-snn`) and the Python packages of the same
|
|
9
|
+
names share version numbers. The device C ABI (`include/mrve32_device.h`) is
|
|
10
|
+
versioned separately by `MRVE32_DEVICE_ABI_VERSION`.
|
|
11
|
+
|
|
12
|
+
To release: rename `[Unreleased]` to `[X.Y.Z] - YYYY-MM-DD`, set the same
|
|
13
|
+
version in both `Cargo.toml` files, and push a `vX.Y.Z` tag (see
|
|
14
|
+
`.github/workflows/release.yml`).
|
|
15
|
+
|
|
16
|
+
## [Unreleased]
|
|
17
|
+
|
|
18
|
+
## [0.1.0] - 2026-11-03
|
|
19
|
+
|
|
20
|
+
First public release.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- RV32IMAC + Zicsr + Zifencei hart, machine mode only: precise exceptions
|
|
25
|
+
(`mcause`/`mepc`/`mtval`), strict CSR access checks, WARL fields,
|
|
26
|
+
IALIGN 16/32 (C can be disabled at runtime, `misa.C`).
|
|
27
|
+
- RV32A: LR/SC with a single-hart reservation, all AMOs; misaligned atomics
|
|
28
|
+
raise address-misaligned exceptions. Failing `sc.w` to unmapped address faults.
|
|
29
|
+
- RV32C (Zca) with variable-length fetch; fetch faults report the failing
|
|
30
|
+
half.
|
|
31
|
+
- Interrupts: machine timer/software/external, `WFI` with idle detection,
|
|
32
|
+
`mcycle`/`minstret` and their unprivileged shadows, `mcountinhibit`.
|
|
33
|
+
- Pluggable devices: the `BusDevice` trait (read/write, `tick`, IRQ lines,
|
|
34
|
+
exit requests, `is_mapped`); a versioned C ABI (version 2) and `ForeignDevice`
|
|
35
|
+
for devices built as separate native libraries; Python devices.
|
|
36
|
+
- Standard peripherals with a QEMU `virt`-like map: RAM, CLINT, NS16550A
|
|
37
|
+
UART subset, `sifive,test0` test finisher.
|
|
38
|
+
- Coprocessor slot for custom-0/custom-1 instructions (`trait Coprocessor`,
|
|
39
|
+
or a Python object via `Emulator.set_coprocessor`), with atomic register
|
|
40
|
+
commit.
|
|
41
|
+
- `Machine`: breakpoints, tracing hook, `run_until` with stop reasons
|
|
42
|
+
(step limit, breakpoint, trap, idle, exit, abort).
|
|
43
|
+
- ELF32 loader with symbols.
|
|
44
|
+
- GNU objdump-compatible disassembler (pseudo-instructions, all standard
|
|
45
|
+
CSR names), checked against binutils 2.46 over the whole 16-bit space and
|
|
46
|
+
random 32-bit words.
|
|
47
|
+
- `mrve32` command-line runner: UART console, finisher exit codes,
|
|
48
|
+
`--trace`, `--stats`, `--isa rv32imac|rv32ima`, configurable memory map,
|
|
49
|
+
`--htif` (HTIF `tohost` exit and console) and `--signature FILE`
|
|
50
|
+
(Sail-format signature dump) for compliance suites.
|
|
51
|
+
- `Htif`: a wrapper device that watches `tohost` in RAM (riscv-tests, Sail
|
|
52
|
+
and Spike-style tests).
|
|
53
|
+
- Python package `mrve32` (abi3 wheels for CPython >= 3.10) with type stubs.
|
|
54
|
+
- `mrve32-snn`: SNN layer accelerator device (behavioural model, spec v0)
|
|
55
|
+
as a separate crate and Python package, with a NumPy reference model.
|
|
56
|
+
- RISC-V Architectural Certification Tests (ACT4): device configuration
|
|
57
|
+
(`tests/arch-test/`), `scripts/arch-test.sh` for the Sail flow and for a
|
|
58
|
+
Sail-free differential flow against QEMU (104 unprivileged tests agree),
|
|
59
|
+
CI workflow.
|
|
60
|
+
- Verification: 75 riscv-tests (rv32ui/um/ua/uc/mi) on RV32IMAC and RV32IMA,
|
|
61
|
+
exhaustive decoder tests, cargo-fuzz targets (weekly CI), interpreter
|
|
62
|
+
throughput benchmark (`cargo bench --bench mips`), MSRV 1.88 checked in CI.
|
mrve32-0.1.0/Cargo.lock
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "heck"
|
|
7
|
+
version = "0.5.0"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "libc"
|
|
13
|
+
version = "0.2.191"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "mrve32"
|
|
19
|
+
version = "0.1.0"
|
|
20
|
+
dependencies = [
|
|
21
|
+
"pyo3",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[[package]]
|
|
25
|
+
name = "mrve32-snn"
|
|
26
|
+
version = "0.1.0"
|
|
27
|
+
dependencies = [
|
|
28
|
+
"mrve32",
|
|
29
|
+
"pyo3",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[[package]]
|
|
33
|
+
name = "once_cell"
|
|
34
|
+
version = "1.21.4"
|
|
35
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
36
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
37
|
+
|
|
38
|
+
[[package]]
|
|
39
|
+
name = "portable-atomic"
|
|
40
|
+
version = "1.15.0"
|
|
41
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
42
|
+
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
|
43
|
+
|
|
44
|
+
[[package]]
|
|
45
|
+
name = "proc-macro2"
|
|
46
|
+
version = "1.0.107"
|
|
47
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
48
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
49
|
+
dependencies = [
|
|
50
|
+
"unicode-ident",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[[package]]
|
|
54
|
+
name = "pyo3"
|
|
55
|
+
version = "0.30.1"
|
|
56
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
57
|
+
checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
|
|
58
|
+
dependencies = [
|
|
59
|
+
"libc",
|
|
60
|
+
"once_cell",
|
|
61
|
+
"portable-atomic",
|
|
62
|
+
"pyo3-build-config",
|
|
63
|
+
"pyo3-ffi",
|
|
64
|
+
"pyo3-macros",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[[package]]
|
|
68
|
+
name = "pyo3-build-config"
|
|
69
|
+
version = "0.30.1"
|
|
70
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
71
|
+
checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
|
|
72
|
+
dependencies = [
|
|
73
|
+
"target-lexicon",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[[package]]
|
|
77
|
+
name = "pyo3-ffi"
|
|
78
|
+
version = "0.30.1"
|
|
79
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
80
|
+
checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
|
|
81
|
+
dependencies = [
|
|
82
|
+
"libc",
|
|
83
|
+
"pyo3-build-config",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
[[package]]
|
|
87
|
+
name = "pyo3-macros"
|
|
88
|
+
version = "0.30.1"
|
|
89
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
90
|
+
checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
|
|
91
|
+
dependencies = [
|
|
92
|
+
"proc-macro2",
|
|
93
|
+
"pyo3-macros-backend",
|
|
94
|
+
"quote",
|
|
95
|
+
"syn",
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
[[package]]
|
|
99
|
+
name = "pyo3-macros-backend"
|
|
100
|
+
version = "0.30.1"
|
|
101
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
102
|
+
checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
|
|
103
|
+
dependencies = [
|
|
104
|
+
"heck",
|
|
105
|
+
"proc-macro2",
|
|
106
|
+
"quote",
|
|
107
|
+
"syn",
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
[[package]]
|
|
111
|
+
name = "quote"
|
|
112
|
+
version = "1.0.47"
|
|
113
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
114
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
115
|
+
dependencies = [
|
|
116
|
+
"proc-macro2",
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
[[package]]
|
|
120
|
+
name = "syn"
|
|
121
|
+
version = "3.0.9"
|
|
122
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
123
|
+
checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
|
|
124
|
+
dependencies = [
|
|
125
|
+
"proc-macro2",
|
|
126
|
+
"quote",
|
|
127
|
+
"unicode-ident",
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
[[package]]
|
|
131
|
+
name = "target-lexicon"
|
|
132
|
+
version = "0.13.5"
|
|
133
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
134
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
135
|
+
|
|
136
|
+
[[package]]
|
|
137
|
+
name = "unicode-ident"
|
|
138
|
+
version = "1.0.27"
|
|
139
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
140
|
+
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
mrve32-0.1.0/Cargo.toml
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "mrve32"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2024"
|
|
5
|
+
license = "Apache-2.0"
|
|
6
|
+
description = "RV32IMAC machine-mode RISC-V MCU emulator with pluggable memory-mapped devices"
|
|
7
|
+
rust-version = "1.88"
|
|
8
|
+
repository = "https://github.com/vladimirmitnovitskiy/MRVE32"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
keywords = ["risc-v", "emulator", "riscv", "microcontroller", "simulator"]
|
|
11
|
+
categories = ["emulators", "simulation", "embedded"]
|
|
12
|
+
# Python package sources, fuzzing and CI files are not part of the crate.
|
|
13
|
+
exclude = ["/python", "/tests/python", "/fuzz", "/.github", "/pyproject.toml", "/modules"]
|
|
14
|
+
|
|
15
|
+
[workspace]
|
|
16
|
+
exclude = ["fuzz"]
|
|
17
|
+
|
|
18
|
+
[dependencies]
|
|
19
|
+
pyo3 = { version = "0.30", features = ["extension-module", "abi3-py310"], optional = true }
|
|
20
|
+
|
|
21
|
+
[features]
|
|
22
|
+
default = []
|
|
23
|
+
# Helpers for device modules that ship as Python packages (capsule export).
|
|
24
|
+
python-device = ["dep:pyo3"]
|
|
25
|
+
# The `mrve32` Python package itself.
|
|
26
|
+
python = ["python-device"]
|
|
27
|
+
|
|
28
|
+
[[bench]]
|
|
29
|
+
name = "mips"
|
|
30
|
+
harness = false
|
mrve32-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
|
10
|
+
|
|
11
|
+
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
|
12
|
+
|
|
13
|
+
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
|
14
|
+
|
|
15
|
+
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
|
16
|
+
|
|
17
|
+
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
|
18
|
+
|
|
19
|
+
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
|
20
|
+
|
|
21
|
+
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
|
22
|
+
|
|
23
|
+
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
|
24
|
+
|
|
25
|
+
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
|
26
|
+
|
|
27
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
|
28
|
+
|
|
29
|
+
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
|
30
|
+
|
|
31
|
+
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
|
32
|
+
|
|
33
|
+
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
|
34
|
+
|
|
35
|
+
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
|
36
|
+
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
|
37
|
+
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
|
38
|
+
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
|
39
|
+
|
|
40
|
+
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
|
41
|
+
|
|
42
|
+
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
|
43
|
+
|
|
44
|
+
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
|
45
|
+
|
|
46
|
+
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
|
47
|
+
|
|
48
|
+
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
|
49
|
+
|
|
50
|
+
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
|
51
|
+
|
|
52
|
+
END OF TERMS AND CONDITIONS
|
mrve32-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mrve32
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: Intended Audience :: Science/Research
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Classifier: Programming Language :: Rust
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
11
|
+
Classifier: Topic :: System :: Emulators
|
|
12
|
+
Classifier: Topic :: System :: Hardware
|
|
13
|
+
Classifier: Typing :: Typed
|
|
14
|
+
Requires-Dist: pytest>=7 ; extra == 'test'
|
|
15
|
+
Provides-Extra: test
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Summary: Deterministic RV32IMAC microcontroller emulator with pluggable memory-mapped devices
|
|
18
|
+
Keywords: risc-v,riscv,emulator,microcontroller,testbench
|
|
19
|
+
License-Expression: Apache-2.0
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
22
|
+
Project-URL: Changelog, https://github.com/vladimirmitnovitskiy/MRVE32/blob/main/CHANGELOG.md
|
|
23
|
+
Project-URL: Issues, https://github.com/vladimirmitnovitskiy/MRVE32/issues
|
|
24
|
+
Project-URL: Repository, https://github.com/vladimirmitnovitskiy/MRVE32
|
|
25
|
+
|
|
26
|
+
[](https://www.rust-lang.org)
|
|
27
|
+
[](https://crates.io/crates/mrve32)
|
|
28
|
+
[](https://docs.rs/mrve32)
|
|
29
|
+
[](https://pypi.org/project/mrve32/)
|
|
30
|
+
[](LICENSE)
|
|
31
|
+
[](https://github.com/vladimirmitnovitskiy/MRVE32/actions/workflows/ci.yml)
|
|
32
|
+
|
|
33
|
+
# MRVE32 (Modular RISC-V Emulator 32-bit)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
**A modular, deterministic RV32IMAC bare-metal microcontroller emulator in Rust, with pluggable devices.**
|
|
37
|
+
|
|
38
|
+
MRVE32 is a lightweight RV32IMAC emulator designed for bare-metal firmware execution, custom SoC peripheral development, and hardware coprocessor prototyping. The core is a CPU, a memory-mapped I/O (MMIO) bus, RAM, a CLINT and an ELF loader; every other peripheral is a **device module** that anyone can write — in Rust, in Python, or as a separately built native package through a small, versioned C ABI. Python bindings make it a testbench engine.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Key Architecture & Features
|
|
43
|
+
|
|
44
|
+
- **RV32IMAC + Zicsr + Zifencei**: base integer ISA, multiplication/division, atomics (`lr.w`/`sc.w` and all `amo*.w`), compressed 16-bit instructions (C/Zca), CSR instructions, `fence`/`fence.i`. C can be switched off (`Cpu::set_compressed(false)`, `--isa rv32ima`, `Emulator(compressed=False)`) to model a core without it, with IALIGN = 32 and `misa.C` following it.
|
|
45
|
+
- **Machine-mode privileged architecture**: precise synchronous exceptions (illegal instruction, misaligned jump target, instruction/load/store access faults, `ecall`, `ebreak`) delivered through `mtvec` with `mepc`/`mcause`/`mtval`/`mstatus` updated as hardware does; `mret`.
|
|
46
|
+
- **Interrupts & timer**: machine external, software and timer interrupts with spec priority (MEI > MSI > MTI), direct and vectored `mtvec`, `wfi` that stalls the hart until an interrupt is pending. A CLINT device (`msip`, `mtime`, `mtimecmp`, SiFive memory map) is included; any device can raise interrupt lines through `BusDevice::irq_lines`.
|
|
47
|
+
- **Counters (Zicntr)**: 64-bit `mcycle`/`minstret` with `mcountinhibit`, read-only `cycle`/`instret` shadows; `mhpmcounter*`/`mhpmevent*` are hardwired to zero.
|
|
48
|
+
- **Strict CSR file**: accesses to unimplemented CSRs and writes to read-only CSRs raise illegal-instruction exceptions; WARL fields (`mstatus`, `mtvec`, `mepc`, `mie`, `mip`) are masked. Implemented: `mstatus`, `mstatush`, `misa`, `mie`, `mip`, `mtvec`, `mscratch`, `mepc`, `mcause`, `mtval`, `mcountinhibit`, `mcycle[h]`, `minstret[h]`, `cycle[h]`, `instret[h]`, `mvendorid`, `marchid`, `mimpid`, `mhartid`, `mconfigptr`.
|
|
49
|
+
- **Tested against riscv-tests**: passes all 75 applicable tests from [`riscv-tests`](https://github.com/riscv-software-src/riscv-tests) (`rv32ui-p-*`, `rv32um-p-*`, `rv32ua-p-*`, `rv32uc-p-rvc` and the M-mode `rv32mi-p-*` tests); every test except `rvc` runs both with and without C. The [RISC-V Architectural Certification Tests](tests/arch-test/README.md) (`riscv-arch-test`, ACT4) have a device configuration for MRVE32: the 104 unprivileged tests for RV32IMAC agree with QEMU at every signature point, and CI runs the full Sail-based flow.
|
|
50
|
+
- **Bare-Metal & Deterministic**: Machine mode only, no MMU, virtual memory, or OS overhead.
|
|
51
|
+
- **Modular Bus Architecture**: Devices, RAM, and memory-mapped peripherals implement the `BusDevice` trait. The bus performs offset translation and address routing.
|
|
52
|
+
- **Hardware Coprocessor Slot**: extension point via `trait Coprocessor` (or a Python object, `Emulator.set_coprocessor`) for custom instructions (opcodes `0x0B` and `0x2B`). Register updates are committed atomically and `x0` stays zero.
|
|
53
|
+
- **Unidirectional Ownership**: Clean Rust ownership model (`cpu.step(&mut bus)`). The CPU core maintains zero references to the system bus.
|
|
54
|
+
- **No dependencies**: the core library depends only on Rust `std`.
|
|
55
|
+
- **Standard peripherals**: RAM, CLINT, an NS16550A-compatible UART and a `sifive,test0` test finisher (firmware sets the exit status), in the QEMU `virt` register layout so existing drivers work unchanged.
|
|
56
|
+
- **Command-line runner**: `mrve32 firmware.elf` runs an ELF on a QEMU-virt-like memory map, streams the UART to stdout and exits with the firmware's status; `--trace` prints every instruction (GNU objdump-style disassembler), `--stop-on-trap`, `--max-steps`, double-fault detection; `--htif` and `--signature` for compliance suites (HTIF `tohost`, Sail-format signature dump).
|
|
57
|
+
- **Pluggable devices**: a device is anything implementing `BusDevice` (Rust), a Python object with `read`/`write` methods, or a native module built separately against the device C ABI ([`include/mrve32_device.h`](include/mrve32_device.h), `mrve32::plugin`). Devices get `tick()` time and can raise interrupt lines. See [`docs/devices.md`](docs/devices.md).
|
|
58
|
+
- **Python package (PyO3)**: `pip install`-able `mrve32` module with an `Emulator` class (ELF loading, symbols, breakpoints, run control, instruction tracing, memory/register/CSR access, `map_device`), `Uart`, `TestFinisher` and `disassemble`. Typed (`py.typed` stubs).
|
|
59
|
+
|
|
60
|
+
### Device modules
|
|
61
|
+
|
|
62
|
+
| Module | Description |
|
|
63
|
+
|---|---|
|
|
64
|
+
| [`mrve32-snn`](modules/snn) | SNN layer accelerator model (draft v0): LIF/IF neurons, `i16` potentials, `i8` weights, a bit-exact golden model behind a swappable `SnnBackend`, an analytical cycle model, a completion interrupt, and a NumPy reference. [Spec](modules/snn/docs/snn-accelerator-v0.md). |
|
|
65
|
+
|
|
66
|
+
Modules live in `modules/` for now but depend on the core only through its public API and could be moved to their own repositories unchanged.
|
|
67
|
+
|
|
68
|
+
### Not implemented (yet)
|
|
69
|
+
|
|
70
|
+
The `time`/`timeh` CSRs (read `mtime` from the CLINT instead), an interrupt controller (PLIC; the UART drives MEIP directly), User/Supervisor modes, PMP, debug triggers, HTIF/semihosting, the F/D extensions, and Zcb/Zcmp. Atomics assume a single hart: `aq`/`rl` have no effect and a trap clears the LR reservation.
|
|
71
|
+
Build firmware with `-march=rv32imac_zicsr_zifencei -mabi=ilp32` (or any subset, e.g. `rv32imc_zicsr`). Misaligned loads and stores are performed in hardware rather than trapped.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Command-line runner
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
cargo install --path . # installs the `mrve32` binary
|
|
79
|
+
mrve32 firmware.elf # UART -> stdout, exit status from the finisher
|
|
80
|
+
mrve32 --trace --max-steps 20 firmware.elf
|
|
81
|
+
mrve32 --htif --signature out.sig test.elf # Sail/Spike-style tests: HTIF tohost, signature dump
|
|
82
|
+
mrve32 --help
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Default memory map (QEMU `virt`-compatible, every address configurable):
|
|
86
|
+
|
|
87
|
+
| Device | Base | Notes |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| RAM | `0x8000_0000` | `--ram-size`, default 128 MiB |
|
|
90
|
+
| UART (NS16550A) | `0x1000_0000` | output to stdout; `--input FILE\|-` feeds its receiver |
|
|
91
|
+
| Test finisher (`sifive,test0`) | `0x0010_0000` | write `0x5555` to pass, `(code << 16) \| 0x3333` to fail |
|
|
92
|
+
| CLINT | `0x0200_0000` | `mtime`, `mtimecmp`, `msip` |
|
|
93
|
+
|
|
94
|
+
Exit status is the firmware's (0–255), or 123 (idle in `wfi` forever),
|
|
95
|
+
124 (`--max-steps`), 125 (usage/load error), 126 (trap with
|
|
96
|
+
`--stop-on-trap`, or a double fault such as running without `mtvec`).
|
|
97
|
+
[`tests/firmware`](tests/firmware) is a minimal freestanding C example
|
|
98
|
+
(startup, linker script, UART, finisher) built by
|
|
99
|
+
`scripts/build-test-firmware.sh`.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Architecture Overview
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
+------------------------------------+
|
|
107
|
+
| CPU Core (RV32IMAC) |
|
|
108
|
+
| - 32x Regs (x0 hardwired to zero) |<--- [ Coprocessor Slot ]
|
|
109
|
+
| - Program Counter (PC) | (Custom opcodes 0x0B, 0x2B)
|
|
110
|
+
+-----------------+------------------+
|
|
111
|
+
| cpu.step(&mut bus)
|
|
112
|
+
+-----------------v------------------+
|
|
113
|
+
| System Bus |
|
|
114
|
+
+--------+------------------+--------+
|
|
115
|
+
| |
|
|
116
|
+
+----------v---------+ +-----v--------------+
|
|
117
|
+
| RAM | | CLINT, Custom |
|
|
118
|
+
| (Little-Endian MM) | | Peripherals, IRQs |
|
|
119
|
+
+--------------------+ +--------------------+
|
|
120
|
+
```
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Rust Usage
|
|
124
|
+
|
|
125
|
+
Add MRVE32 to your `Cargo.toml`, then use the core:
|
|
126
|
+
|
|
127
|
+
```rust
|
|
128
|
+
use mrve32::{Bus, BusDevice, Cpu, Ram};
|
|
129
|
+
|
|
130
|
+
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
131
|
+
let mut bus = Bus::new();
|
|
132
|
+
let mut ram = Ram::new(1024);
|
|
133
|
+
|
|
134
|
+
// Write machine instructions into RAM:
|
|
135
|
+
// addi x1, x0, 42 (0x02A0_0093)
|
|
136
|
+
ram.write_u32(0, 0x02A0_0093)?;
|
|
137
|
+
bus.map_device(0x1000, 1024, Box::new(ram))?;
|
|
138
|
+
|
|
139
|
+
let mut cpu = Cpu::new(0x1000);
|
|
140
|
+
|
|
141
|
+
// `step` returns `Some(trap)` if the instruction raised an exception.
|
|
142
|
+
// The trap has already been taken: `pc` points to the `mtvec` handler.
|
|
143
|
+
if let Some(trap) = cpu.step(&mut bus) {
|
|
144
|
+
return Err(trap.into());
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
assert_eq!(cpu.read_reg(1), 42);
|
|
148
|
+
assert_eq!(cpu.pc, 0x1004);
|
|
149
|
+
|
|
150
|
+
Ok(())
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Time and interrupts
|
|
155
|
+
|
|
156
|
+
Each `step` is one clock cycle: the CPU samples `mip` from the bus
|
|
157
|
+
interrupt lines, takes an enabled pending interrupt (or executes one
|
|
158
|
+
instruction), then calls `BusDevice::tick(1)` on every mapped device.
|
|
159
|
+
Map a `Clint` to get `mtime`/`mtimecmp` and software interrupts:
|
|
160
|
+
|
|
161
|
+
```rust
|
|
162
|
+
use mrve32::devices::clint::CLINT_SIZE;
|
|
163
|
+
use mrve32::{Bus, Clint};
|
|
164
|
+
|
|
165
|
+
let mut bus = Bus::new();
|
|
166
|
+
// mtime advances once every 10 CPU cycles
|
|
167
|
+
bus.map_device(0x0200_0000, CLINT_SIZE, Box::new(Clint::with_divider(10)))
|
|
168
|
+
.unwrap();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Custom peripherals raise interrupts by overriding `BusDevice::irq_lines`
|
|
172
|
+
(return a mask of `MIP_MEIP`/`MIP_MSIP`/`MIP_MTIP`) and advance their own
|
|
173
|
+
state in `BusDevice::tick`; see [`docs/devices.md`](docs/devices.md).
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
## Python Testbenches (PyO3)
|
|
177
|
+
|
|
178
|
+
Install the `mrve32` package (builds the extension with [maturin](https://www.maturin.rs/);
|
|
179
|
+
needs a Rust toolchain and Python >= 3.10):
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
pip install . # or, for development: pip install -e ".[test]"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Run firmware and inspect the machine:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
import mrve32
|
|
189
|
+
|
|
190
|
+
# RAM at 0x8000_0000 and a CLINT at 0x0200_0000 by default
|
|
191
|
+
# (clint_base=None omits it); add a UART and a test finisher as in QEMU virt.
|
|
192
|
+
emu = mrve32.Emulator(ram_size=1 << 20)
|
|
193
|
+
uart = mrve32.Uart()
|
|
194
|
+
emu.map_device(0x1000_0000, uart)
|
|
195
|
+
emu.map_device(0x0010_0000, mrve32.TestFinisher())
|
|
196
|
+
|
|
197
|
+
entry = emu.load_elf("firmware.elf") # path or bytes; sets pc to the entry
|
|
198
|
+
res = emu.run(1_000_000, stop_on_trap=True)
|
|
199
|
+
print(res.reason, res.steps) # "exit" | "max_steps" | "breakpoint" | "trap" | "idle"
|
|
200
|
+
print(res.exit_code, uart.output()) # finisher status, bytes sent on the UART
|
|
201
|
+
if res.trap:
|
|
202
|
+
print(hex(res.trap.cause), res.trap.description)
|
|
203
|
+
|
|
204
|
+
print(emu.regs, hex(emu.pc), emu.cycles, emu.instret)
|
|
205
|
+
emu.add_breakpoint(emu.symbol("main"))
|
|
206
|
+
emu.set_tracer(lambda pc, word, trap: print(hex(pc), mrve32.disassemble(word, pc) if word else trap))
|
|
207
|
+
data = emu.read_bytes(emu.symbol("buffer"), 64) # raises mrve32.BusError if unmapped
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Attach devices: native modules or plain Python objects ([`docs/devices.md`](docs/devices.md)):
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
class Gpio:
|
|
214
|
+
size = 4
|
|
215
|
+
def __init__(self): self.pins = 0
|
|
216
|
+
def read(self, offset, width): return self.pins
|
|
217
|
+
def write(self, offset, width, value): self.pins = value
|
|
218
|
+
|
|
219
|
+
emu.map_device(0x1000_0000, Gpio()) # Python device
|
|
220
|
+
emu.map_device(0x2000_0000, mrve32.Ram(4096)) # native device
|
|
221
|
+
print(emu.devices) # [(base, size, name), ...]
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Prototype custom instructions (custom-0 `0x0B` / custom-1 `0x2B`) with a Python
|
|
225
|
+
coprocessor; register writes are committed only if `execute` succeeds:
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
class Mac:
|
|
229
|
+
def execute(self, call): # call: mrve32.CoprocessorCall
|
|
230
|
+
if call.funct3 != 0:
|
|
231
|
+
return False # illegal instruction trap
|
|
232
|
+
acc = call.read_reg(call.rd) + call.read_reg(call.rs1) * call.read_reg(call.rs2)
|
|
233
|
+
call.write_reg(call.rd, acc & 0xFFFF_FFFF)
|
|
234
|
+
# call.read_u32(addr) / call.write_u32(addr, v): bus access
|
|
235
|
+
# (an uncaught BusError becomes a load/store access fault);
|
|
236
|
+
# call.next_pc = target: branch
|
|
237
|
+
|
|
238
|
+
emu.set_coprocessor(Mac()) # None detaches it
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
For example, with the SNN module (`pip install ./modules/snn`):
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
import numpy as np
|
|
245
|
+
from mrve32 import Emulator
|
|
246
|
+
from mrve32_snn import SnnAccelerator, SnnDriver, reference_step
|
|
247
|
+
|
|
248
|
+
emu = Emulator()
|
|
249
|
+
emu.map_device(0x1000_0000, SnnAccelerator())
|
|
250
|
+
dev = SnnDriver(emu, 0x1000_0000)
|
|
251
|
+
|
|
252
|
+
weights = np.random.randint(-128, 128, size=(64, 32), dtype=np.int8)
|
|
253
|
+
dev.load_layer(weights, v_th=100, leak_shift=4)
|
|
254
|
+
|
|
255
|
+
vmem = np.zeros(32, np.int16)
|
|
256
|
+
for t in range(10):
|
|
257
|
+
spikes = np.random.rand(64) < 0.2
|
|
258
|
+
out = dev.step(spikes) # write inputs, START, wait, read outputs
|
|
259
|
+
expected, vmem = reference_step(spikes, weights, vmem, v_th=100, leak_shift=4)
|
|
260
|
+
assert (out == expected).all() and (dev.read_vmem() == vmem).all()
|
|
261
|
+
print(t, out.sum(), "spikes,", dev.cycles, "cycles")
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Run the Python tests:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
pytest tests/python modules/snn/tests/python
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
## Verification & Quality Assurance
|
|
272
|
+
|
|
273
|
+
Run the full test suite (unit tests, README examples, an interrupt-driven firmware test and the riscv-tests suite):
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
cargo test --workspace
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Run only the riscv-tests suite (per-test results are printed):
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
cargo test --test compliance -- --nocapture
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
The test ELF files in `tests/isa/` are built reproducibly from source with a
|
|
286
|
+
pinned `riscv-tests` revision (requires a RISC-V GCC cross toolchain):
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
scripts/build-riscv-tests.sh
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
RISC-V Architectural Certification Tests (needs a RISC-V GCC; `--qemu` also
|
|
293
|
+
runs every self-checking ELF on QEMU; the Sail-based flow is described in
|
|
294
|
+
[`tests/arch-test/README.md`](tests/arch-test/README.md)):
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
scripts/arch-test.sh local --qemu
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Robustness: `tests/decoder_fuzz.rs` runs every 16-bit encoding, every
|
|
301
|
+
opcode/funct3/funct7 combination and a million random words through the
|
|
302
|
+
decoders and the disassembler, and random programs through the CPU.
|
|
303
|
+
Coverage-guided targets for `cargo-fuzz` are in [`fuzz/`](fuzz/README.md)
|
|
304
|
+
(CI runs them weekly). The disassembler was cross-checked against GNU objdump
|
|
305
|
+
2.46: the only differences are encodings the spec reserves on RV32
|
|
306
|
+
(`slli`/`srli`/`srai` with shamt[5] = 1, `c.addi16sp` with immediate 0),
|
|
307
|
+
which objdump decodes and MRVE32 rejects, and the names of C HINT encodings.
|
|
308
|
+
|
|
309
|
+
Interpreter throughput (MIPS) for a few instruction mixes:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
cargo bench --bench mips
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Run static analysis and linter checks:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
The minimum supported Rust version (MSRV) is **1.88** (checked in CI).
|
|
322
|
+
Changes are listed in [`CHANGELOG.md`](CHANGELOG.md).
|
|
323
|
+
---
|
|
324
|
+
## License
|
|
325
|
+
|
|
326
|
+
Licensed under Apache License, Version 2.0.
|
|
327
|
+
|