248 lines
14 KiB
Plaintext
248 lines
14 KiB
Plaintext
<<<
|
|
:sectnums:
|
|
== Simulating the Processor
|
|
|
|
The NEORV32 project includes a core CPU, built-in peripherals in the Processor Subsystem, and additional peripherals in
|
|
the templates and examples.
|
|
Therefore, there is a wide range of possible testing and verification strategies.
|
|
|
|
On the one hand, a simple smoke testbench allows ensuring that functionality is correct from a software point of view.
|
|
That is used for running the RISC-V architecture tests, in order to guarantee compliance with the ISA specification(s).
|
|
|
|
On the other hand, http://vunit.github.io/[VUnit] and http://vunit.github.io/verification_components/user_guide.html[Verification Components]
|
|
are used for verifying the functionality of the various peripherals from a hardware point of view.
|
|
|
|
.Xilinx Vivado / ISIM
|
|
[IMPORTANT]
|
|
When using Xilinx Vivado (ISIM for simulation) make sure to **turn of** "incremental compilation" (_Project Setting_
|
|
-> _Simulation_ -> _Advanced_ -> _Enable incremental compilation). This will slow down simulation relaunch but will
|
|
ensure that all application images (`*_image.vhd`) are reanalyzed when recompiling the NEORV32 application or bootloader
|
|
|
|
[TIP]
|
|
The processor can check if it is being _simulated_ by checking the SYSINFO _SYSINFO_SOC_IS_SIM_ flag
|
|
(see https://stnolting.github.io/neorv32/#_system_configuration_information_memory_sysinfo).
|
|
Note that this flag is not guaranteed to be set correctly (depending on the HDL toolchain's pragma support).
|
|
|
|
:sectnums:
|
|
=== Testbench
|
|
|
|
A plain-VHDL (no third-party libraries) testbench (`sim/simple/neorv32_tb.simple.vhd`) can be used for simulating and
|
|
testing the processor.
|
|
This testbench features a 100MHz clock and enables all optional peripheral and CPU extensions except for the `E`.
|
|
|
|
[IMPORTANT]
|
|
In the simple testbench several optional extensions are disabled, such as C or E.
|
|
If software is compiled using instructions corresponding to disabled extensions, the whole processor will hang in an eternal exception loop and, therefore, the simulation will timeout.
|
|
The `MARCH` must be a subset of the extensions enabled in the testbench.
|
|
|
|
.True Random Number Generator
|
|
[NOTE]
|
|
The NEORV32 TRNG will be set to "simulation mode" when enabled for simulation (replacing the ring-oscillators
|
|
by pseudo-random LFSRs). See the neoTRNG documentation for more information.
|
|
|
|
The simulation setup is configured via the "User Configuration" section located right at the beginning of
|
|
the testbench's architecture. Each configuration constant provides comments to explain the functionality.
|
|
|
|
Besides the actual NEORV32 Processor, the testbench also simulates "external" components that are connected
|
|
to the processor's external bus/memory interface. These components are:
|
|
|
|
* an external instruction memory (that also allows booting from it)
|
|
* an external data memory
|
|
* an external memory to simulate "external IO devices"
|
|
* a memory-mapped registers to trigger the processor's interrupt signals
|
|
|
|
The following table shows the base addresses of these four components and their default configuration and
|
|
properties:
|
|
|
|
[NOTE]
|
|
====
|
|
Attributes:
|
|
|
|
* `r` = read
|
|
* `w` = write
|
|
* `e` = execute
|
|
* `8` = byte-accessible
|
|
* `16` = half-word-accessible
|
|
* `32` = word-accessible
|
|
====
|
|
|
|
.Testbench: processor-external memories
|
|
[cols="^4,>3,^5,<11"]
|
|
[options="header",grid="rows"]
|
|
|=======================
|
|
| Base address | Size | Attributes | Description
|
|
| `0x00000000` | `imem_size_c` | `r/w/e 8/16/32` | external IMEM (initialized with application image)
|
|
| `0x80000000` | `dmem_size_c` | `r/w/e 8/16/32` | external DMEM
|
|
| `0xf0000000` | 64 bytes | `r/w/e 8/16/32` | external "IO" memory
|
|
| `0xff000000` | 4 bytes | `-/w/- -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts
|
|
|=======================
|
|
|
|
[IMPORTANT]
|
|
The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from
|
|
the `rtl/core/neorv32_application_image.vhd` image file).
|
|
|
|
.UART output during simulation
|
|
[IMPORTANT]
|
|
Data written to the NEORV32 UART0 / UART1 transmitter is send to a virtual UART receiver implemented
|
|
as part of the testbench. Received chars are send to the simulator console and are also stored to a log file
|
|
(`neorv32.testbench_uart0.out` for UART0, `neorv32.testbench_uart1.out` for UART1) inside the simulation's home folder.
|
|
**Please note that printing via the native UART receiver takes a lot of time.** For faster simulation console output
|
|
see section <<_faster_simulation_console_output>>.
|
|
|
|
|
|
:sectnums:
|
|
=== Faster Simulation Console Output
|
|
|
|
When printing data via the physical UART the communication speed will always be based on the configured BAUD
|
|
rate. For a simulation this might take some time. To have faster output you can enable the **simulation mode**
|
|
for UART0/UART1 (see section https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0[Documentation: Primary Universal Asynchronous Receiver and Transmitter (UART0)]).
|
|
|
|
ASCII data sent to UART0|UART1 will be immediately printed to the simulator console and logged to files in the simulator
|
|
execution directory:
|
|
|
|
* `neorv32.uart?.sim_mode.text.out`: ASCII data.
|
|
|
|
You can "automatically" enable the simulation mode of UART0/UART1 when compiling an application.
|
|
In this case, the "real" UART0/UART1 transmitter unit is permanently disabled.
|
|
To enable the simulation mode just compile and install your application and add _UART?_SIM_MODE_ to the compiler's
|
|
_USER_FLAGS_ variable (do not forget the `-D` suffix flag):
|
|
|
|
[source, bash]
|
|
----
|
|
sw/example/demo_blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all all
|
|
----
|
|
|
|
The provided define will change the default UART0/UART1 setup function in order to set the simulation
|
|
mode flag in the according UART's control register.
|
|
|
|
[NOTE]
|
|
The UART simulation output (to file and to screen) outputs "complete lines" at once. A line is
|
|
completed with a line feed (newline, ASCII `\n` = 10).
|
|
|
|
|
|
:sectnums:
|
|
=== Simulation using a shell script (with GHDL)
|
|
|
|
To simulate the processor using _GHDL_ navigate to the `sim/simple/` folder and run the provided shell script.
|
|
Any arguments that are provided while executing this script are passed to GHDL.
|
|
For example the simulation time can be set to 20ms using `--stop-time=20ms` as argument.
|
|
|
|
[source, bash]
|
|
----
|
|
neorv32/sim/simple$ sh ghdl.sh --stop-time=20ms
|
|
----
|
|
|
|
|
|
:sectnums:
|
|
=== Simulation using Application Makefiles (In-Console with GHDL)
|
|
|
|
To directly compile and run a program in the console (using the default testbench and GHDL
|
|
as simulator) you can use the `sim` makefile target. Make sure to use the UART simulation mode
|
|
(`USER_FLAGS+=-DUART0_SIM_MODE` and/or `USER_FLAGS+=-DUART1_SIM_MODE`) to get
|
|
faster / direct-to-console UART output.
|
|
|
|
[source, bash]
|
|
----
|
|
sw/example/demo_blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim
|
|
[...]
|
|
Blinking LED demo program
|
|
----
|
|
|
|
|
|
:sectnums:
|
|
==== Hello World!
|
|
|
|
To do a quick test of the NEORV32 make sure to have https://github.com/ghdl/ghdl[GHDL] and a
|
|
https://github.com/stnolting/riscv-gcc-prebuilt[RISC-V gcc toolchain] installed.
|
|
Navigate to the project's `sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim`:
|
|
|
|
[TIP]
|
|
The simulator will output some _sanity check_ notes (and warnings or even errors if something is ill-configured)
|
|
right at the beginning of the simulation to give a brief overview of the actual NEORV32 SoC and CPU configurations.
|
|
|
|
[source, bash]
|
|
----
|
|
neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim
|
|
../../../sw/lib/source/neorv32_uart.c: In function 'neorv32_uart_setup':
|
|
../../../sw/lib/source/neorv32_uart.c:116:2: warning: #warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulations only! [-Wcpp]
|
|
116 | #warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulations only! <1>
|
|
| ^~~~~~~
|
|
Memory utilization:
|
|
text data bss dec hex filename
|
|
4664 0 116 4780 12ac main.elf <2>
|
|
Compiling ../../../sw/image_gen/image_gen
|
|
Installing application image to ../../../rtl/core/neorv32_application_image.vhd <3>
|
|
Simulating neorv32_application_image.vhd...
|
|
Tip: Compile application with USER_FLAGS+=-DUART[0/1]_SIM_MODE to auto-enable UART[0/1]'s simulation mode (redirect UART output to simulator console). <4>
|
|
Using simulation run arguments: --stop-time=10ms <5>
|
|
../../rtl/core/neorv32_top.vhd:355:5:@0ms:(assertion note): [NEORV32] The NEORV32 RISC-V Processor (version 0x01090504), github.com/stnolting/neorv32 <6>
|
|
../../rtl/core/neorv32_top.vhd:361:5:@0ms:(assertion note): [NEORV32] Processor Configuration: IMEM DMEM I-CACHE D-CACHE WISHBONE GPIO MTIME UART0 UART1 SPI SDI TWI PWM WDT TRNG CFS NEOLED XIRQ GPTMR XIP ONEWIRE DMA SLINK CRC SYSINFO OCD
|
|
../../rtl/core/neorv32_clockgate.vhd:60:3:@0ms:(assertion warning): [NEORV32] Clock gating enabled (using generic clock switch).
|
|
../../rtl/core/neorv32_cpu.vhd:142:3:@0ms:(assertion note): [NEORV32] CPU ISA: rv32imabu_zicsr_zicntr_zicond_zifencei_zfinx_zihpm_zxcfu_sdext_sdtrig_smpmp
|
|
../../rtl/core/neorv32_cpu.vhd:163:3:@0ms:(assertion note): [NEORV32] CPU tuning options: fast_mul fast_shift
|
|
../../rtl/core/neorv32_cpu.vhd:170:3:@0ms:(assertion warning): [NEORV32] Assuming this is a simulation.
|
|
../../rtl/core/neorv32_cpu_cp_bitmanip.vhd:172:3:@0ms:(assertion note): [NEORV32] Implementing bit-manipulation (B) sub-extensions Zba Zbb Zbc Zbs
|
|
../../rtl/core/neorv32_cpu_cp_fpu.vhd:292:3:@0ms:(assertion warning): [NEORV32] The floating-point unit (Zfinx) is still in experimental state.
|
|
../../rtl/core/mem/neorv32_imem.legacy.vhd:72:3:@0ms:(assertion note): [NEORV32] Implementing LEGACY processor-internal IMEM as pre-initialized ROM.
|
|
../../rtl/core/neorv32_wishbone.vhd:117:3:@0ms:(assertion note): [NEORV32] Ext. Bus Interface (WISHBONE) - PIPELINED Wishbone protocol, auto-timeout, LITTLE-endian byte order, registered RX, registered TX
|
|
../../rtl/core/neorv32_trng.vhd:343:3:@0ms:(assertion note): [neoTRNG NOTE] << neoTRNG V3 - A Tiny and Platform-Independent True Random Number Generator >>
|
|
../../rtl/core/neorv32_trng.vhd:545:5:@0ms:(assertion warning): [neoTRNG WARNING] Implementing non-physical pseudo-RNG!
|
|
../../rtl/core/neorv32_trng.vhd:545:5:@0ms:(assertion warning): [neoTRNG WARNING] Implementing non-physical pseudo-RNG!
|
|
../../rtl/core/neorv32_trng.vhd:545:5:@0ms:(assertion warning): [neoTRNG WARNING] Implementing non-physical pseudo-RNG!
|
|
../../rtl/core/neorv32_debug_dm.vhd:227:3:@0ms:(assertion note): [NEORV32] OCD DM compatible to debug spec. version 1.0
|
|
<7>
|
|
## ## ## ##
|
|
## ## ######### ######## ######## ## ## ######## ######## ## ################
|
|
#### ## ## ## ## ## ## ## ## ## ## ## ## ## #### ####
|
|
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ##
|
|
## ## ## ######### ## ## ######### ## ## ##### ## ## #### ###### ####
|
|
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ##
|
|
## #### ## ## ## ## ## ## ## ## ## ## ## #### ####
|
|
## ## ######### ######## ## ## ## ######## ########## ## ################
|
|
## ## ## ##
|
|
Hello world! :)
|
|
----
|
|
<1> Notifier that "simulation mode" of UART0 is enabled (by the `USER_FLAGS+=-DUART0_SIM_MODE` makefile flag). All UART0 output is send to the simulator console.
|
|
<2> Final executable size (`text`) and _static_ data memory requirements (`data`, `bss`).
|
|
<3> The application code is _installed_ as pre-initialized IMEM. This is the default approach for simulation.
|
|
<4> A note regarding UART "simulation mode", but we have already enabled that.
|
|
<5> List of (default) arguments that were send to the simulator. Here: maximum simulation time (10ms).
|
|
<6> "Sanity checks" from the core's VHDL files. These reports give some brief information about the SoC/CPU configuration (-> generics). If there are problems with the current configuration, an ERROR will appear.
|
|
<7> Execution of the actual program starts.
|
|
|
|
|
|
:sectnums:
|
|
=== Advanced Simulation using VUnit
|
|
|
|
https://vunit.github.io/[VUnit] is an open source unit testing framework for VHDL/SystemVerilog.
|
|
It allows continuous and automated testing of HDL code by complementing traditional testing methodologies.
|
|
The motto of VUnit is _"testing early and often"_ through automation.
|
|
|
|
VUnit is composed by a http://vunit.github.io/py/ui.html[Python interface] and multiple optional
|
|
http://vunit.github.io/vhdl_libraries.html[VHDL libraries].
|
|
The Python interface allows declaring sources and simulation options, and it handles the compilation, execution and
|
|
gathering of the results regardless of the simulator used.
|
|
That allows having a single `run.py` script to be used with GHDL, ModelSim/QuestaSim, Riviera PRO, etc.
|
|
On the other hand, the VUnit's VHDL libraries provide utilities for assertions, logging, having virtual queues, handling CSV files, etc.
|
|
The http://vunit.github.io/verification_components/user_guide.html[Verification Component Library] uses those features
|
|
for abstracting away bit-toggling when verifying standard interfaces such as Wishbone, AXI, Avalon, UARTs, etc.
|
|
|
|
Testbench sources in `sim` (such as `sim/neorv32_tb.vhd` and `sim/uart_rx*.vhd`) use VUnit's VHDL libraries for testing
|
|
NEORV32 and peripherals.
|
|
The entry-point for executing the tests is `sim/run.py`.
|
|
|
|
[source, bash]
|
|
----
|
|
# ./sim/run.py -l
|
|
neorv32.neorv32_tb.all
|
|
Listed 1 tests
|
|
|
|
# ./sim/run.py -v
|
|
Compiling into neorv32: rtl/core/neorv32_uart.vhd passed
|
|
Compiling into neorv32: rtl/core/neorv32_twi.vhd passed
|
|
Compiling into neorv32: rtl/core/neorv32_trng.vhd passed
|
|
...
|
|
----
|
|
|
|
See http://vunit.github.io/user_guide.html[VUnit: User Guide] and http://vunit.github.io/cli.html[VUnit: Command Line Interface] for further info about VUnit's features.
|