1 |
69 |
zero_gravi |
<<<
|
2 |
|
|
:sectnums:
|
3 |
|
|
== Simulating the Processor
|
4 |
|
|
|
5 |
|
|
The NEORV32 project includes a core CPU, built-in peripherals in the Processor Subsystem, and additional peripherals in
|
6 |
|
|
the templates and examples.
|
7 |
|
|
Therefore, there is a wide range of possible testing and verification strategies.
|
8 |
|
|
|
9 |
|
|
On the one hand, a simple smoke testbench allows ensuring that functionality is correct from a software point of view.
|
10 |
|
|
That is used for running the RISC-V architecture tests, in order to guarantee compliance with the ISA specification(s).
|
11 |
|
|
|
12 |
|
|
On the other hand, http://vunit.github.io/[VUnit] and http://vunit.github.io/verification_components/user_guide.html[Verification Components]
|
13 |
|
|
are used for verifying the functionality of the various peripherals from a hardware point of view.
|
14 |
|
|
|
15 |
|
|
[TIP]
|
16 |
|
|
The processor can check if it is being simulated by checking the SYSINFO _SYSINFO_SOC_IS_SIM_ flag
|
17 |
|
|
(see https://stnolting.github.io/neorv32/#_system_configuration_information_memory_sysinfo).
|
18 |
|
|
Note that this flag is not guaranteed to be set correctly (depending on the HDL toolchain's pragma support).
|
19 |
|
|
|
20 |
|
|
:sectnums:
|
21 |
|
|
=== Testbench
|
22 |
|
|
|
23 |
|
|
A plain-VHDL (no third-party libraries) testbench (`sim/simple/neorv32_tb.simple.vhd`) can be used for simulating and
|
24 |
|
|
testing the processor.
|
25 |
|
|
This testbench features a 100MHz clock and enables all optional peripheral and CPU extensions except for the `E`
|
26 |
|
|
extension and the TRNG IO module (that CANNOT be simulated due to its combinatorial (looped) architecture).
|
27 |
|
|
|
28 |
|
|
The simulation setup is configured via the "User Configuration" section located right at the beginning of
|
29 |
|
|
the testbench's architecture. Each configuration constant provides comments to explain the functionality.
|
30 |
|
|
|
31 |
|
|
Besides the actual NEORV32 Processor, the testbench also simulates "external" components that are connected
|
32 |
|
|
to the processor's external bus/memory interface. These components are:
|
33 |
|
|
|
34 |
|
|
* an external instruction memory (that also allows booting from it)
|
35 |
|
|
* an external data memory
|
36 |
|
|
* an external memory to simulate "external IO devices"
|
37 |
|
|
* a memory-mapped registers to trigger the processor's interrupt signals
|
38 |
|
|
|
39 |
|
|
The following table shows the base addresses of these four components and their default configuration and
|
40 |
|
|
properties:
|
41 |
|
|
|
42 |
|
|
[NOTE]
|
43 |
|
|
====
|
44 |
|
|
Attributes:
|
45 |
|
|
|
46 |
|
|
* `r` = read
|
47 |
|
|
* `w` = write
|
48 |
|
|
* `e` = execute
|
49 |
|
|
* `a` = atomic accesses possible
|
50 |
|
|
* `8` = byte-accessible
|
51 |
|
|
* `16` = half-word-accessible
|
52 |
|
|
* `32` = word-accessible
|
53 |
|
|
====
|
54 |
|
|
|
55 |
|
|
.Testbench: processor-external memories
|
56 |
|
|
[cols="^4,>3,^5,<11"]
|
57 |
|
|
[options="header",grid="rows"]
|
58 |
|
|
|=======================
|
59 |
|
|
| Base address | Size | Attributes | Description
|
60 |
|
|
| `0x00000000` | `imem_size_c` | `r/w/e, a, 8/16/32` | external IMEM (initialized with application image)
|
61 |
|
|
| `0x80000000` | `dmem_size_c` | `r/w/e, a, 8/16/32` | external DMEM
|
62 |
|
|
| `0xf0000000` | 64 bytes | `r/w/e, !a, 8/16/32` | external "IO" memory, atomic accesses will fail
|
63 |
|
|
| `0xff000000` | 4 bytes | `-/w/-, a, -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts
|
64 |
|
|
|=======================
|
65 |
|
|
|
66 |
|
|
[IMPORTANT]
|
67 |
|
|
The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from
|
68 |
|
|
the `rtl/core/neorv32_application_image.vhd` image file).
|
69 |
|
|
|
70 |
|
|
.UART output during simulation
|
71 |
|
|
[IMPORTANT]
|
72 |
|
|
Data written to the NEORV32 UART0 / UART1 transmitter is send to a virtual UART receiver implemented
|
73 |
|
|
as part of the testbench. Received chars are send to the simulator console and are also stored to a log file
|
74 |
|
|
(`neorv32.testbench_uart0.out` for UART0, `neorv32.testbench_uart1.out` for UART1) inside the simulation's home folder.
|
75 |
|
|
**Please note that printing via the native UART receiver takes a lot of time.** For faster simulation console output
|
76 |
|
|
see section <<_faster_simulation_console_output>>.
|
77 |
|
|
|
78 |
|
|
|
79 |
|
|
:sectnums:
|
80 |
|
|
=== Faster Simulation Console Output
|
81 |
|
|
|
82 |
|
|
When printing data via the UART the communication speed will always be based on the configured BAUD
|
83 |
|
|
rate. For a simulation this might take some time. To have faster output you can enable the **simulation mode**
|
84 |
|
|
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)]).
|
85 |
|
|
|
86 |
|
|
ASCII data sent to UART0|UART1 will be immediately printed to the simulator console and logged to files in the simulator
|
87 |
|
|
execution directory:
|
88 |
|
|
|
89 |
|
|
* `neorv32.uart?.sim_mode.text.out`: ASCII data.
|
90 |
|
|
* `neorv32.uart?.sim_mode.data.out`: all written 32-bit dumped as 8-char hexadecimal values.
|
91 |
|
|
|
92 |
|
|
You can "automatically" enable the simulation mode of UART0/UART1 when compiling an application.
|
93 |
|
|
In this case, the "real" UART0/UART1 transmitter unit is permanently disabled.
|
94 |
|
|
To enable the simulation mode just compile and install your application and add _UART?_SIM_MODE_ to the compiler's
|
95 |
|
|
_USER_FLAGS_ variable (do not forget the `-D` suffix flag):
|
96 |
|
|
|
97 |
|
|
[source, bash]
|
98 |
|
|
----
|
99 |
|
|
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all all
|
100 |
|
|
----
|
101 |
|
|
|
102 |
|
|
The provided define will change the default UART0/UART1 setup function in order to set the simulation
|
103 |
|
|
mode flag in the according UART's control register.
|
104 |
|
|
|
105 |
|
|
[NOTE]
|
106 |
|
|
The UART simulation output (to file and to screen) outputs "complete lines" at once. A line is
|
107 |
|
|
completed with a line feed (newline, ASCII `\n` = 10).
|
108 |
|
|
|
109 |
|
|
|
110 |
|
|
:sectnums:
|
111 |
|
|
=== Simulation using a shell script (with GHDL)
|
112 |
|
|
|
113 |
|
|
To simulate the processor using _GHDL_ navigate to the `sim/simple/` folder and run the provided shell script.
|
114 |
|
|
Any arguments that are provided while executing this script are passed to GHDL.
|
115 |
|
|
For example the simulation time can be set to 20ms using `--stop-time=20ms` as argument.
|
116 |
|
|
|
117 |
|
|
[source, bash]
|
118 |
|
|
----
|
119 |
|
|
neorv32/sim/simple$ sh ghdl_sim.sh --stop-time=20ms
|
120 |
|
|
----
|
121 |
|
|
|
122 |
|
|
|
123 |
|
|
:sectnums:
|
124 |
|
|
=== Simulation using Application Makefiles (In-Console with GHDL)
|
125 |
|
|
|
126 |
|
|
To directly compile and run a program in the console (using the default testbench and GHDL
|
127 |
|
|
as simulator) you can use the `sim` makefile target. Make sure to use the UART simulation mode
|
128 |
|
|
(`USER_FLAGS+=-DUART0_SIM_MODE` and/or `USER_FLAGS+=-DUART1_SIM_MODE`) to get
|
129 |
|
|
faster / direct-to-console UART output.
|
130 |
|
|
|
131 |
|
|
[source, bash]
|
132 |
|
|
----
|
133 |
|
|
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim
|
134 |
|
|
[...]
|
135 |
|
|
Blinking LED demo program
|
136 |
|
|
----
|
137 |
|
|
|
138 |
|
|
|
139 |
|
|
:sectnums:
|
140 |
|
|
==== Hello World!
|
141 |
|
|
|
142 |
|
|
To do a quick test of the NEORV32 make sure to have https://github.com/ghdl/ghdl[GHDL] and a
|
143 |
|
|
https://github.com/stnolting/riscv-gcc-prebuilt[RISC-V gcc toolchain] installed.
|
144 |
|
|
Navigate to the project's `sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE MARCH=rv32imac clean_all sim`:
|
145 |
|
|
|
146 |
|
|
[TIP]
|
147 |
|
|
The simulator will output some _sanity check_ notes (and warnings or even errors if something is ill-configured)
|
148 |
|
|
right at the beginning of the simulation to give a brief overview of the actual NEORV32 SoC and CPU configurations.
|
149 |
|
|
|
150 |
|
|
[source, bash]
|
151 |
|
|
----
|
152 |
|
|
stnolting@Einstein:/mnt/n/Projects/neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE MARCH=rv32imac clean_all sim
|
153 |
|
|
../../../sw/lib/source/neorv32_uart.c: In function 'neorv32_uart0_setup':
|
154 |
|
|
../../../sw/lib/source/neorv32_uart.c:301:4: 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]
|
155 |
|
|
301 | #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>
|
156 |
|
|
| ^~~~~~~
|
157 |
|
|
Memory utilization:
|
158 |
|
|
text data bss dec hex filename
|
159 |
|
|
4612 0 120 4732 127c main.elf <2>
|
160 |
|
|
Compiling ../../../sw/image_gen/image_gen
|
161 |
|
|
Installing application image to ../../../rtl/core/neorv32_application_image.vhd <3>
|
162 |
|
|
Simulating neorv32_application_image.vhd...
|
163 |
|
|
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>
|
164 |
|
|
Using simulation runtime args: --stop-time=10ms <5>
|
165 |
|
|
../rtl/core/neorv32_top.vhd:347:3:@0ms:(assertion note): NEORV32 PROCESSOR IO Configuration: GPIO MTIME UART0 UART1 SPI TWI PWM WDT CFS SLINK NEOLED XIRQ <6>
|
166 |
|
|
../rtl/core/neorv32_top.vhd:370:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM).
|
167 |
|
|
../rtl/core/neorv32_top.vhd:394:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing on-chip debugger (OCD).
|
168 |
|
|
../rtl/core/neorv32_cpu.vhd:169:3:@0ms:(assertion note): NEORV32 CPU ISA Configuration (MARCH): RV32IMACU_Zbb_Zicsr_Zifencei_Zfinx_Debug
|
169 |
|
|
../rtl/core/neorv32_cpu.vhd:189:3:@0ms:(assertion note): NEORV32 CPU CONFIG NOTE: Implementing NO dedicated hardware reset for uncritical registers (default, might reduce area). Set package constant = TRUE to configure a DEFINED reset value for all CPU registers.
|
170 |
|
|
../rtl/core/neorv32_imem.vhd:107:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (16384 bytes), pre-initialized with application (4612 bytes).
|
171 |
|
|
../rtl/core/neorv32_dmem.vhd:89:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal DMEM (RAM, 8192 bytes).
|
172 |
|
|
../rtl/core/neorv32_wishbone.vhd:136:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing STANDARD Wishbone protocol.
|
173 |
|
|
../rtl/core/neorv32_wishbone.vhd:140:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing auto-timeout (255 cycles).
|
174 |
|
|
../rtl/core/neorv32_wishbone.vhd:144:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing LITTLE-endian byte order.
|
175 |
|
|
../rtl/core/neorv32_wishbone.vhd:148:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing registered RX path.
|
176 |
|
|
../rtl/core/neorv32_slink.vhd:161:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing 8 RX and 8 TX stream links.
|
177 |
|
|
<7>
|
178 |
|
|
##
|
179 |
|
|
## ## ## ##
|
180 |
|
|
## ## ######### ######## ######## ## ## ######## ######## ## ################
|
181 |
|
|
#### ## ## ## ## ## ## ## ## ## ## ## ## ## #### ####
|
182 |
|
|
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ##
|
183 |
|
|
## ## ## ######### ## ## ######### ## ## ##### ## ## #### ###### ####
|
184 |
|
|
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ##
|
185 |
|
|
## #### ## ## ## ## ## ## ## ## ## ## ## #### ####
|
186 |
|
|
## ## ######### ######## ## ## ## ######## ########## ## ################
|
187 |
|
|
## ## ## ##
|
188 |
|
|
##
|
189 |
|
|
Hello world! :)
|
190 |
|
|
----
|
191 |
|
|
<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.
|
192 |
|
|
<2> Final executable size (`text`) and _static_ data memory requirements (`data`, `bss`).
|
193 |
|
|
<3> The application code is _installed_ as pre-initialized IMEM. This is the default approach for simulation.
|
194 |
|
|
<4> A note regarding UART "simulation mode", but we have already enabled that.
|
195 |
|
|
<5> List of (default) arguments that were send to the simulator. Here: maximum simulation time (10ms).
|
196 |
|
|
<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.
|
197 |
|
|
<7> Execution of the actual program starts.
|
198 |
|
|
|
199 |
|
|
|
200 |
|
|
:sectnums:
|
201 |
|
|
=== Advanced Simulation using VUnit
|
202 |
|
|
|
203 |
|
|
https://vunit.github.io/[VUnit] is an open source unit testing framework for VHDL/SystemVerilog.
|
204 |
|
|
It allows continuous and automated testing of HDL code by complementing traditional testing methodologies.
|
205 |
|
|
The motto of VUnit is _"testing early and often"_ through automation.
|
206 |
|
|
|
207 |
|
|
VUnit is composed by a http://vunit.github.io/py/ui.html[Python interface] and multiple optional
|
208 |
|
|
http://vunit.github.io/vhdl_libraries.html[VHDL libraries].
|
209 |
|
|
The Python interface allows declaring sources and simulation options, and it handles the compilation, execution and
|
210 |
|
|
gathering of the results regardless of the simulator used.
|
211 |
|
|
That allows having a single `run.py` script to be used with GHDL, ModelSim/QuestaSim, Riviera PRO, etc.
|
212 |
|
|
On the other hand, the VUnit's VHDL libraries provide utilities for assertions, logging, having virtual queues, handling CSV files, etc.
|
213 |
|
|
The http://vunit.github.io/verification_components/user_guide.html[Verification Component Library] uses those features
|
214 |
|
|
for abstracting away bit-toggling when verifying standard interfaces such as Wishbone, AXI, Avalon, UARTs, etc.
|
215 |
|
|
|
216 |
|
|
Testbench sources in `sim` (such as `sim/neorv32_tb.vhd` and `sim/uart_rx*.vhd`) use VUnit's VHDL libraries for testing
|
217 |
|
|
NEORV32 and peripherals.
|
218 |
|
|
The entry-point for executing the tests is `sim/run.py`.
|
219 |
|
|
|
220 |
|
|
[source, bash]
|
221 |
|
|
----
|
222 |
|
|
# ./sim/run.py -l
|
223 |
|
|
neorv32.neorv32_tb.all
|
224 |
|
|
Listed 1 tests
|
225 |
|
|
|
226 |
|
|
# ./sim/run.py -v
|
227 |
|
|
Compiling into neorv32: rtl/core/neorv32_uart.vhd passed
|
228 |
|
|
Compiling into neorv32: rtl/core/neorv32_twi.vhd passed
|
229 |
|
|
Compiling into neorv32: rtl/core/neorv32_trng.vhd passed
|
230 |
|
|
...
|
231 |
|
|
----
|
232 |
|
|
|
233 |
|
|
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.
|