NEORV32 Core Verification using RISCOF
This repository is a port of the "RISCOF RISC-V Architectural Test Framework" to test the NEORV32 RISC-V Processor for compatibility to the RISC-V user and privileged ISA specifications. The Sail RISC-V model is used as reference model. Currently, the following tests are supported:
rv32i_m\B- bit-manipulation (
rv32i_m\C- compressed instructions
rv32i_m\I- base integer ISA
rv32i_m\M- hardware multiplication and division
rv32i_m\privilege- privileged machine architecture
rv32i_m\Zifencei- instruction stream synchronization
Several tools and submodules are required to run this port of the architecture test framework. The repository's GitHub workflow takes care of installing all the required packages.
- neorv32 submodule - the device under test (DUT)
- riscv-arch-test submodule - architecture test cases
- RISC-V GCC toolchain - for compiling native
- Sail RISC-V - the reference model (pre-built binary in the
- RISCOF - the architecture test framework
- GHDL - the awesome VHDL simulator for simulating the DUT
The framework (running all tests) is invoked via a single shell script
run.sh that returns 0 if all tests were executed
successfully and 1 if there were any errors. The exit code of this script is used to determine the overall success
of the GitHub action and thus, defines the workflow's badge status.
The RISCOF config.ini is used to configure
the plugins to be used: the device-under-test ("DUT") and the reference model ("REF").
The ISA, debug and platform specifications, which define target specific configurations like available ISA
extensions, platform modules like MTIME and ISA spec. versions, are defined via
YAML files in the DUT's
According to the plugin, each plugin folder also provides low-level environment files like linker scripts (to generate an executable matching the target's memory layout) and platform-specific code (for example to initialize the target and to dump test results).
The official RISC-V architecture tests repository provides test cases for all (ratified) RISC-V ISA extensions (user and privilege ISA). Each test case tests a single instruction or core feature and is compiled into a plugin-specific executable using a prebuilt RISC-V GCC toolchain.
The "golden" reference data is generated using the Sail RISC-V Model and compared to the results of the DUT. The final test report is available as CSS-flavored HTML file via the GitHib actions artifact.
sim folder provides a simple testbench and
shell scripts to simulate the NEORV32 processor using GHDL. The testbench provides generics to configure the
DUT's RISC-V ISA extensions and also to pass a plain ASCII HEX file, which represents the actual executable
to be executed ("memory initialization file") that is generated by the folder's makefile from a test-specific
ELF file.The makefile uses the default software framework from the NEORV32 submodule (more specific: the image
generator) to generate a memory initialization file from a compiled ELF file.
Each memory module implements a physical memory size of 512kB resulting in a total memory size of 2MB (the
largest test case executable comes from the
I/jal test case with approx. 1.7MB). This "splitting" is required as GHDL has
problems handling large objects (see ghdl/ghdl#1592).
The testbench also provides a "trigger mechanism" to quit the current simulation using VHDL08's
statement. Quitting the simulation is triggered by writing
0xCAFECAFE to address
is implemented (software) by the DUT's plugin environment module. A maximum simulation timeout of 2ms is
provided to terminate faulty simulations that might end up in an infinite loop.
The simulation scripts and the makefile for generating the memory initialization file are invoked from DUT-
specific Python script in the DUT's plugin folder
This Python script makes extensive use of shell commands to move and execute files and scripts
(my Python skills are still quite limited
The current version of the Sail RISC-V model does not support a target-specific configuration of the
core's events that update the
mtval trap value CSR: the NEORV32 writes zero to this CSR when encountering an
(breakpoint) exception while the original Sail model writes the address of the triggering
mtval. However, constraining platform-specific events that write (or not) to
mtval is explicitly
allowed by the RISC-V ISA specification
To circumvent this, a patch
is applied to the default
riscv-arch-test submodule, which adds code to set the
mtval portion of the test
signature to all-zero if a breakpoint exception occurs.
This is only relevant for the
C/cebreak-01.S test cases.
This "hack" might be abandoned with future versions of RISCOF/sail.