i-RISCV Testing

The i-RISCV implementation is verified with multiple, complementary test approaches – from module-level unit tests up to booting an unmodified Linux kernel, plus a fully open-source flow that takes the same RTL to a real ECP5 bitstream. The following approaches are used.

Simulation Test Layers

  • Module-level unit tests (tb/unit/): every RTL module gets a standalone Verilator C++ harness that instantiates only that module, drives its ports directly, and self-checks against hand-computed expected values or independent reference models (e.g. an independently re-implemented RVC decoder model swept over all 49152 encodings, the host CPU’s own IEEE-754 FPU as floating-point oracle). Dedicated builds with deliberately wrong known-answer vectors prove each crypto core’s self-test failure/lockout and recovery paths.
  • Directed full-core assembly tests (tb/tests/asm/): self-contained, hand-written RV64I+Zicsr+Zifencei programs, each exercising one pipeline mechanism end-to-end through the real SoC – single-core (check) and multi-core (check-mc). Every test reports its verdict as a P/F byte over the real UART peripheral, so the console path is exercised by every test’s own plumbing. Where a mechanism’s observable effect is timing rather than architectural state – e.g. WFI’s genuine fetch/issue stall versus a NOP-like retirement – the test measures real elapsed cycles (rdtime) around the instruction and asserts it falls inside the expected bound window, across ordinary wait-and-wake, same-cycle-NOP, and every TW/VTW/U-mode/VS/VU trap scenario.
  • Build-parameter enable/disable matrix (verif/enable_matrix/): independently elaborated builds for every combination of the optional-mechanism *_ENABLE parameters (a 32-way Zvk*/entropy-source permutation plus separate UART and async-reseed legs – 356 runs in all), each running a general regression battery plus state-specific tests – real known-answer vectors when enabled, illegal-instruction proofs when disabled. Deliberate negative-control runs confirm the harness would actually fail if the RTL gating were broken.
  • External NIST ACVP test-vector harness (ACVP Parser): externally supplied NIST ACVP JSON vectors reach the real RTL unmodified through a dedicated C backend – no software reimplementation of any algorithm is involved (SHA-2, SHA-3/SHAKE, AES-256, GCM/GMAC, KMAC256). The backend is compiled and linked against the real RTL today; live external-vector reconciliation is tracked follow-on work.

Conformance and System-Level Testing

  • RISCOF conformance suites (verif/riscof/): RISC-V International’s own official riscv-arch-test suites (I, M, C, D, Zifencei, privilege) run through a RISCOF-based harness with a bind-based monitor – test sources and expected signatures are both produced by RVI, independent of this project; the reference is riscv-arch-test’s own shipped .reference_output files rather than a live golden model. 275 of 283 tests pass; the 8 open privilege misalign-* cases stem from that shipped-reference limitation (this core splits misaligned accesses in hardware, while RVI’s static signatures assume trap-based behavior) and are independently verified by directed tests. Where no official suite exists (V, H, AIA, IOMMU, vector crypto), the project’s own directed tests stand in; all results and open issues are disclosed.
  • Linux boot as a system-level test: an entirely unmodified, stock Linux kernel (v6.6 and v7.2) boots against the whole SoC through both firmware paths, on one and two harts – real, independently developed software with its own timing assumptions, catching classes of bug no directed test reaches (peripheral register-ordering hazards, firmware/CSR ordering issues, asynchronous-interrupt races).
  • Firmware smoke tests: standalone S-mode programs (linux_boot/tools_scripts/run_sbi_smoke.sh {up,smp,dueling}) validate the boot firmware in isolation without paying for a full kernel boot – every implemented SBI extension via real ecalls on one hart; a second real hart started and IPI/fenced on two harts; and a dueling-RFENCE regression for a cross-hart fence deadlock.
  • Differential fuzzing harness: generates randomized-but-legal RV64I+Zicsr/Zifencei instruction streams and runs the same stream through both a golden reference model of Spike and the RTL executed with the Verilator simulator, comparing full architectural state after every retired instruction: all GPRs, PC, and the CSR list. Divergences are delta-minimized into self-checking directed reproducers kept in-tree.

Hazard-Family Regressions and Assertion Safety Nets

  • Interrupt-vs-commit-race regressions: real CLINT timer interrupts phase-swept across the commit windows of every multi-cycle unit (AMO, CBO.ZERO, misaligned split stores, vector stores, cold page-table walks), with poison-value consumers and negative-control reverts proving each test genuinely discriminates
  • Cross-hart synchronization regressions: two harts free-running unsynchronized AMO and LR/SC increment races against a shared counter (the final count must be exactly 2N), plus PLIC in-service-latch coverage – every other shared, multi-hart-reachable resource audited safe by construction
  • SVA assertion safety net: assert property blocks checked under Verilator’s --assert in every simulation build point guard the whole hazard family; one property cross-checks an independently maintained enumeration of privilege/interrupt/translation-relevant CSR writes against the redirect-handling list, so a future edit that drops a category fires deterministically instead of waiting for a probabilistic directed test to hit its exact race cycle

Side-Channel and Non-Functional Audits

  • Constant-time (cycle-count) audits: each cryptographic core and vector-crypto unit is audited that execution latency never depends on the value of keys or data – only on public control signals – measured across different contents at fixed operation shapes; the hardware entropy source receives the same treatment.
  • Speculative-execution resistance: a citation-backed argument (the Spectre/Meltdown disclosure papers are archived in docs/specifications/) that no mis-speculated instruction can leave an observable footprint, plus predictor-state erasure on every privilege-domain crossing – verified at unit and directed-test level.

Entropy-Source Statistical Validation

  • Stochastic-model regression (scripts/entropy/): pure-Python statistical tests of the noise-source entropy models (closed-form checks, capture-format round-trips, chi-square machinery, restart-homogeneity, worst-case min-entropy accounting).
  • Captured-data analysis: real noise-source data – from simulation and from real silicon via the FPGA harness – is captured over UART and analyzed against the stochastic model to determine entropy rate.
  • Compliance analysis: SP 800-90C (RBG2(P)/RBG3(RS)) and AIS 20/31 v3.0 (DRG.4+PTG.2 / PTG.3) compliance is documented requirement-by-requirement, with all disclosed gaps listed.

Real-Hardware (FPGA) Testing

A fully open-source flow (yosys read_slang + synth_ecp5 -> nextpnr-ecp5 -> ecppack -> openFPGALoader) targets the ULX3S (Lattice ECP5):

  • The directed assembly tests are reused unchanged – baked into boot RAM and reporting P/F over the real serial line
  • Board-only bring-up checks (heartbeat LED, reset/serial mirrors) that cannot be expressed in simulation at all
  • Entropy-source capture from genuine silicon jitter/metastability – data whose value is real physical noise rather than a pass/fail verdict

Current status: full-hierarchy elaboration through read_slang succeeds with zero errors (one synthesis-compatibility guard added to the RAM init path); a complete synth_ecp5 + place-and-route run is still being finalized – yosys reports logic-loop warnings localized to the FPU’s variable-shift idioms, working hypothesis a false positive pending nextpnr’s independent timing graph. No physical board has been attached yet: on-hardware execution remains a reproducible procedure for anyone with a ULX3S, not an observed result.

Waveform Inspection and CI Integration

  • Any test can produce FST waveforms viewable in Surfer (scripts/gen_waves.sh, per-module make wave-* targets) for signal-level debugging.
  • Per-feature CI runs the unit tests, single-core and multi-core directed sweeps, the enable/disable smoke matrix, the SBI firmware smoke tests, and a small Linux boot run; at the end of a development cycle the full permutation matrix, RISCOF suites, the differential fuzz campaign, and a full Linux boot are added.