Line 143... |
Line 143... |
if you instantiate one of the test setups.
|
if you instantiate one of the test setups.
|
|
|
[start=1]
|
[start=1]
|
. Create a new project with your FPGA EDA tool of choice.
|
. Create a new project with your FPGA EDA tool of choice.
|
. Add all VHDL files from the project's `rtl/core` folder to your project.
|
. Add all VHDL files from the project's `rtl/core` folder to your project.
|
|
|
|
.Internal Memories
|
|
[IMPORTANT]
|
|
For a _general_ first setup (technology-independent) use the _default_ memory architectures for the internal memories
|
|
(IMEM and DMEM). These are located in `rtl/core/mem`, so **make sure to add the files from `rtl/core/mem` to your project, too**. +
|
|
+
|
|
If synthesis cannot efficiently map those default memory descriptions to the available memory resources, you can later replace the
|
|
default memory architectures by optimized platform-specific memory architectures. **Example:** The `setups/radiant/UPduino_v3`
|
|
example setup uses optimized memory primitives. Hence, it does not include the default memory architectures from
|
|
`rtl/core/mem` as these are replaced by device-specific implementations. However, it still has to include the entity
|
|
definitions from `rtl/core`.
|
|
|
|
[start=3]
|
. Make sure to add all the rtl files to a new library called `neorv32`. If your FPGA tools does not
|
. Make sure to add all the rtl files to a new library called `neorv32`. If your FPGA tools does not
|
provide a field to enter the library name, check out the "properties" menu of the added rtl files.
|
provide a field to enter the library name, check out the "properties" menu of the added rtl files.
|
|
|
|
.Compile order
|
|
[NOTE]
|
|
Some tools (like Lattice Radiant) might require a _manual compile order_ of the VHDL source files to identify the dependencies.
|
|
The package file `neorv32_package.vhd` should be analyzed first followed by the memory image files (`neorv32_application_imagevhd`
|
|
and `neorv32_bootloader_image.vhd`) and the entity-only files (`neorv32_*mem.entity.vhd`).
|
|
|
|
[start=4]
|
. The `rtl/core/neorv32_top.vhd` VHDL file is the top entity of the NEORV32 processor, which can be
|
. The `rtl/core/neorv32_top.vhd` VHDL file is the top entity of the NEORV32 processor, which can be
|
instantiated into the "real" project. However, in this tutorial we will use one of the pre-defined
|
instantiated into the "real" project. However, in this tutorial we will use one of the pre-defined
|
test setups from `rtl/test_setups` (see above).
|
test setups from `rtl/test_setups` (see above).
|
|
|
[IMPORTANT]
|
[IMPORTANT]
|
Line 740... |
Line 761... |
|
|
|
|
|
|
// ####################################################################################################################
|
// ####################################################################################################################
|
:sectnums:
|
:sectnums:
|
|
== Adding Custom Hardware Modules
|
|
|
|
In resemblance to the RISC-V ISA, the NEORV32 processor was designed to ease customization and _extensibility_.
|
|
The processor provides several predefined options to add application-specific custom hardware modules and accelerators.
|
|
|
|
|
|
=== Standard (_External_) Interfaces
|
|
|
|
The processor already provides a set of standard interfaces that are intended to connect _chip-external_ devices.
|
|
However, these interfaces can also be used chip-internally. The most suitable interfaces are
|
|
https://stnolting.github.io/neorv32/#_general_purpose_input_and_output_port_gpio[GPIO],
|
|
https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0[UART],
|
|
https://stnolting.github.io/neorv32/#_serial_peripheral_interface_controller_spi[SPI] and
|
|
https://stnolting.github.io/neorv32/#_two_wire_serial_interface_controller_twi[TWI].
|
|
|
|
The SPI and (especially) the GPIO interfaces might be the most straightforward approaches since they
|
|
have a minimal protocol overhead. Device-specific interrupt capabilities can be added using the
|
|
https://stnolting.github.io/neorv32/#_external_interrupt_controller_xirq[External Interrupt Controller (XIRQ)].
|
|
Beyond simplicity, these interface only provide a very limited bandwidth and require more sophisticated
|
|
software handling ("bit-banging" for the GPIO).
|
|
|
|
|
|
=== External Bus Interface
|
|
|
|
The https://stnolting.github.io/neorv32/#_processor_external_memory_interface_wishbone_axi4_lite[External Bus Interface]
|
|
provides the classic approach to connect to custom IP. By default, the bus interface implements the widely adopted
|
|
Wishbone interface standard. However, this project also includes wrappers to bridge to other protocol standards like ARM's
|
|
AXI4-Lite or Intel's Avalon. By using a full-featured bus protocol, complex SoC structures can be implemented (including
|
|
several modules and even multi-core architectures). Many FPGA EDA tools provide graphical editors to build and customize
|
|
whole SoC architectures and even include pre-defined IP libraries.
|
|
|
|
.Example AXI SoC using Xilinx Vivado
|
|
image::neorv32_axi_soc.png[]
|
|
|
|
The bus interface uses a memory-mapped approach. All data transfers are handled by simple load/store operations since the
|
|
external bus interface is mapped into the processor's https://stnolting.github.io/neorv32/#_address_space[address space].
|
|
This allows a very simple still high-bandwidth communications.
|
|
|
|
|
|
=== Stream Link Interface
|
|
|
|
The NEORV32 https://stnolting.github.io/neorv32/#_stream_link_interface_slink[Stream Link Interface] provides
|
|
point-to-point, unidirectional and parallel data channels that can be used to transfer streaming data. In
|
|
contrast to the external bus interface, the streaming data does not provide any kind of "direction" control,
|
|
so it can be seen as "constant address bursts". The stream link interface provides less protocol overhead
|
|
and less latency than the bus interface. Furthermore, FIFOs can be be configured to each direction (RX/TX) to
|
|
allow more CPU-independent operation.
|
|
|
|
|
|
=== Custom Functions Subsystem
|
|
|
|
The https://stnolting.github.io/neorv32/#_custom_functions_subsystem_cfs[NEORV32 Custom Functions Subsystem]
|
|
is as "empty" template for a processor-internal module. It provides 32 32-bit memory-mapped interface
|
|
registers that can be used to communicate with any arbitrary custom design logic. The intentions of this
|
|
subsystem is to provide a simple base, where the user can concentrate on implementing the actual design logic
|
|
rather than taking care of the communication between the CPU/software and the design logic. The interface
|
|
registers are already allocated within the processor's address space and are supported by the software framework
|
|
via low-level hardware access mechanisms. Additionally, the CFS provides a direct pre-defined interrupt channel to
|
|
the CPU, which is also supported by the _NEORV32 runtime environment_.
|
|
|
|
|
|
|
|
|
|
// ####################################################################################################################
|
|
:sectnums:
|
== Customizing the Internal Bootloader
|
== Customizing the Internal Bootloader
|
|
|
The NEORV32 bootloader provides several options to configure and customize it for a certain application setup.
|
The NEORV32 bootloader provides several options to configure and customize it for a certain application setup.
|
This configuration is done by passing _defines_ when compiling the bootloader. Of course you can also
|
This configuration is done by passing _defines_ when compiling the bootloader. Of course you can also
|
modify to bootloader source code to provide a setup that perfectly fits your needs.
|
modify to bootloader source code to provide a setup that perfectly fits your needs.
|
Line 779... |
Line 865... |
| `SPI_BOOT_BASE_ADDR` | `0x08000000` | _any_ 32-bit value | Defines the _base_ address of the executable in external flash
|
| `SPI_BOOT_BASE_ADDR` | `0x08000000` | _any_ 32-bit value | Defines the _base_ address of the executable in external flash
|
|=======================
|
|=======================
|
|
|
Each configuration parameter is implemented as C-language `define` that can be manually overridden (_redefined_) when
|
Each configuration parameter is implemented as C-language `define` that can be manually overridden (_redefined_) when
|
invoking the bootloader's makefile. The according parameter and its new value has to be _appended_
|
invoking the bootloader's makefile. The according parameter and its new value has to be _appended_
|
(using `+=`) to the makefile's `USER_FLAGS` variable. Make sure to use the `-D` prefix here.
|
(using `+=`) to the makefile `USER_FLAGS` variable. Make sure to use the `-D` prefix here.
|
|
|
For example, to configure a UART Baud rate of 57600 and redirecting the status LED to output pin 20
|
For example, to configure a UART Baud rate of 57600 and redirecting the status LED to output pin 20
|
use the following command (_in_ the bootloader's source folder `sw/bootloader`):
|
use the following command (_in_ the bootloader's source folder `sw/bootloader`):
|
|
|
.Example: customizing, re-compiling and re-installing the bootloader
|
.Example: customizing, re-compiling and re-installing the bootloader
|
Line 933... |
Line 1019... |
// ####################################################################################################################
|
// ####################################################################################################################
|
:sectnums:
|
:sectnums:
|
== Packaging the Processor as IP block for Xilinx Vivado Block Designer
|
== Packaging the Processor as IP block for Xilinx Vivado Block Designer
|
|
|
[start=1]
|
[start=1]
|
. Import all the core files from `rtl/core` and assign them to a _new_ design library `neorv32`.
|
. Import all the core files from `rtl/core` (including default internal memory architectures from `rtl/core/mem`)
|
|
and assign them to a _new_ design library `neorv32`.
|
. Instantiate the `rtl/wrappers/neorv32_top_axi4lite.vhd` module.
|
. Instantiate the `rtl/wrappers/neorv32_top_axi4lite.vhd` module.
|
. Then either directly use that module in a new block-design ("Create Block Design", right-click -> "Add Module",
|
. Then either directly use that module in a new block-design ("Create Block Design", right-click -> "Add Module",
|
thats easier for a first try) or package it ("Tools", "Create and Package new IP") for the use in other projects.
|
thats easier for a first try) or package it ("Tools", "Create and Package new IP") for the use in other projects.
|
. Connect your AXI-peripheral directly to the core's AXI4-Interface if you only have one, or to an AXI-Interconnect
|
. Connect your AXI-peripheral directly to the core's AXI4-Interface if you only have one, or to an AXI-Interconnect
|
(from the IP-catalog) if you have multiple peripherals.
|
(from the IP-catalog) if you have multiple peripherals.
|
Line 959... |
Line 1046... |
|
|
// ####################################################################################################################
|
// ####################################################################################################################
|
:sectnums:
|
:sectnums:
|
== Simulating the Processor
|
== 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.
|
|
|
:sectnums:
|
:sectnums:
|
=== Testbench
|
=== Testbench
|
|
|
The NEORV32 project features a simple, plain-VHDL (no third-party libraries) default testbench (`sim/neorv32_tb.simple.vhd`)
|
A plain-VHDL (no third-party libraries) testbench (`sim/simple/neorv32_tb.simple.vhd`) can be used for simulating and
|
that can be used to simulate and test the processor setup. This testbench features a 100MHz clock and enables all optional
|
testing the processor.
|
peripheral and CPU extensions except for the `E` extension and the TRNG IO module (that CANNOT be simulated due to its
|
This testbench features a 100MHz clock and enables all optional peripheral and CPU extensions except for the `E`
|
combinatorial (looped) architecture).
|
extension and the TRNG IO module (that CANNOT be simulated due to its combinatorial (looped) architecture).
|
|
|
The simulation setup is configured via the "User Configuration" section located right at the beginning of
|
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.
|
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
|
Besides the actual NEORV32 Processor, the testbench also simulates "external" components that are connected
|
Line 979... |
Line 1075... |
* an external data memory
|
* an external data memory
|
* an external memory to simulate "external IO devices"
|
* an external memory to simulate "external IO devices"
|
* a memory-mapped registers to trigger the processor's interrupt signals
|
* 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
|
The following table shows the base addresses of these four components and their default configuration and
|
properties (attributes: `r` = read, `w` = write, `e` = execute, `a` = atomic accesses possible, `8` = byte-accessible, `16` =
|
properties:
|
half-word-accessible, `32` = word-accessible).
|
|
|
[NOTE]
|
|
====
|
|
Attributes:
|
|
|
|
* `r` = read
|
|
* `w` = write
|
|
* `e` = execute
|
|
* `a` = atomic accesses possible
|
|
* `8` = byte-accessible
|
|
* `16` = half-word-accessible
|
|
* `32` = word-accessible
|
|
====
|
|
|
.Testbench: processor-external memories
|
.Testbench: processor-external memories
|
[cols="^4,>3,^5,<11"]
|
[cols="^4,>3,^5,<11"]
|
[options="header",grid="rows"]
|
[options="header",grid="rows"]
|
|=======================
|
|=======================
|
Line 993... |
Line 1101... |
| `0x80000000` | `dmem_size_c` | `r/w/e, a, 8/16/32` | external DMEM
|
| `0x80000000` | `dmem_size_c` | `r/w/e, a, 8/16/32` | external DMEM
|
| `0xf0000000` | 64 bytes | `r/w/e, !a, 8/16/32` | external "IO" memory, atomic accesses will fail
|
| `0xf0000000` | 64 bytes | `r/w/e, !a, 8/16/32` | external "IO" memory, atomic accesses will fail
|
| `0xff000000` | 4 bytes | `-/w/-, a, -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts
|
| `0xff000000` | 4 bytes | `-/w/-, a, -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts
|
|=======================
|
|=======================
|
|
|
[NOTE]
|
[IMPORTANT]
|
The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from
|
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).
|
the `rtl/core/neorv32_application_image.vhd` image file).
|
|
|
.UART output during simulation
|
.UART output during simulation
|
[NOTE]
|
[IMPORTANT]
|
Data written to the NEORV32 UART0 / UART1 transmitter is send to a virtual UART receiver implemented
|
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
|
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.
|
(`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
|
**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>>.
|
see section <<_faster_simulation_console_output>>.
|
Line 1011... |
Line 1119... |
:sectnums:
|
:sectnums:
|
=== Faster Simulation Console Output
|
=== Faster Simulation Console Output
|
|
|
When printing data via the UART the communication speed will always be based on the configured BAUD
|
When printing data via the 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**
|
rate. For a simulation this might take some time. To have faster output you can enable the **simulation mode**
|
or UART0/UART1 (see section https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0[Documentation: Primary Universal Asynchronous Receiver and Transmitter (UART0)]).
|
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:
|
|
|
ASCII data send to UART0 will be immediately printed to the simulator console. Additionally, the
|
* `neorv32.uart?.sim_mode.text.out`: ASCII data.
|
ASCII data is logged in a file (`neorv32.uart0.sim_mode.text.out`) in the simulator home folder. All
|
* `neorv32.uart?.sim_mode.data.out`: all written 32-bit dumped as 8-char hexadecimal values.
|
written 32-bit data is also dumped as 8-char hexadecimal value into a file
|
|
(`neorv32.uart0.sim_mode.data.out`) also in the simulator home folder.
|
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.
|
ASCII data send to UART1 will be immediately printed to the simulator console. Additionally, the
|
To enable the simulation mode just compile and install your application and add _UART?_SIM_MODE_ to the compiler's
|
ASCII data is logged in a file (`neorv32.uart1.sim_mode.text.out`) in the simulator home folder. All
|
_USER_FLAGS_ variable (do not forget the `-D` suffix flag):
|
written 32-bit data is also dumped as 8-char hexadecimal value into a file
|
|
(`neorv32.uart1.sim_mode.data.out`) also in the simulator home folder.
|
|
|
|
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 _UART0_SIM_MODE_ for UART0 and/or _UART1_SIM_MODE_ for UART1 to
|
|
the compiler's _USER_FLAGS_ variable (do not forget the `-D` suffix flag):
|
|
|
|
[source, bash]
|
[source, bash]
|
----
|
----
|
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all all
|
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all all
|
----
|
----
|
Line 1042... |
Line 1146... |
The UART simulation output (to file and to screen) outputs "complete lines" at once. A line is
|
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).
|
completed with a line feed (newline, ASCII `\n` = 10).
|
|
|
|
|
:sectnums:
|
:sectnums:
|
=== Simulation using GHDL
|
=== Simulation using a shell script (with GHDL)
|
|
|
To simulate the processor using _GHDL_ navigate to the `sim` folder and run the provided shell script.
|
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.
|
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.
|
For example the simulation time can be set to 20ms using `--stop-time=20ms` as argument.
|
|
|
[source, bash]
|
[source, bash]
|
----
|
----
|
neorv32/sim$ sh ghdl_sim.sh --stop-time=20ms
|
neorv32/sim/simple$ sh ghdl_sim.sh --stop-time=20ms
|
----
|
----
|
|
|
|
|
:sectnums:
|
:sectnums:
|
=== In-Console Application Simulation
|
=== Simulation using Application Makefiles (In-Console with GHDL)
|
|
|
To directly compile and run a program in the console (using the default testbench and 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
|
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
|
(`USER_FLAGS+=-DUART0_SIM_MODE` and/or `USER_FLAGS+=-DUART1_SIM_MODE`) to get
|
faster / direct-to-console UART output.
|
faster / direct-to-console UART output.
|
Line 1071... |
Line 1175... |
Blinking LED demo program
|
Blinking LED demo program
|
----
|
----
|
|
|
|
|
:sectnums:
|
:sectnums:
|
=== Hello World!
|
==== Hello World!
|
|
|
To do a quick test of the NEORV32 make sure to have [GHDL](https://github.com/ghdl/ghdl) and a
|
To do a quick test of the NEORV32 make sure to have https://github.com/ghdl/ghdl[GHDL] and a
|
[RISC-V gcc toolchain](https://github.com/stnolting/riscv-gcc-prebuilt) installed, navigate to the project's
|
[RISC-V gcc toolchain](https://github.com/stnolting/riscv-gcc-prebuilt) installed.
|
`sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE MARCH=-march=rv32imac clean_all sim`:
|
Navigate to the project's `sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE MARCH=-march=rv32imac clean_all sim`:
|
|
|
[TIP]
|
[TIP]
|
The simulator will output some _sanity check_ notes (and warnings or even errors if something is ill-configured)
|
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.
|
right at the beginning of the simulation to give a brief overview of the actual NEORV32 SoC and CPU configurations.
|
|
|
[source, bash]
|
[source, bash]
|
----
|
----
|
stnolting@Einstein:/mnt/n/Projects/neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE MARCH=-march=rv32imac clean_all sim
|
stnolting@Einstein:/mnt/n/Projects/neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE MARCH=-march=rv32imac clean_all sim
|
../../../sw/lib/source/neorv32_uart.c: In function 'neorv32_uart0_setup':
|
../../../sw/lib/source/neorv32_uart.c: In function 'neorv32_uart0_setup':
|
../../../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]
|
../../../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]
|
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!
|
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>
|
| ^~~~~~~
|
| ^~~~~~~
|
Memory utilization:
|
Memory utilization:
|
text data bss dec hex filename
|
text data bss dec hex filename
|
4612 0 120 4732 127c main.elf
|
4612 0 120 4732 127c main.elf <2>
|
Compiling ../../../sw/image_gen/image_gen
|
Compiling ../../../sw/image_gen/image_gen
|
Installing application image to ../../../rtl/core/neorv32_application_image.vhd
|
Installing application image to ../../../rtl/core/neorv32_application_image.vhd <3>
|
Simulating neorv32_application_image.vhd...
|
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).
|
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 runtime args: --stop-time=10ms
|
Using simulation runtime args: --stop-time=10ms <5>
|
../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
|
../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>
|
../rtl/core/neorv32_top.vhd:370:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM).
|
../rtl/core/neorv32_top.vhd:370:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM).
|
../rtl/core/neorv32_top.vhd:394:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing on-chip debugger (OCD).
|
../rtl/core/neorv32_top.vhd:394:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing on-chip debugger (OCD).
|
../rtl/core/neorv32_cpu.vhd:169:3:@0ms:(assertion note): NEORV32 CPU ISA Configuration (MARCH): RV32IMACU_Zbb_Zicsr_Zifencei_Zfinx_Debug
|
../rtl/core/neorv32_cpu.vhd:169:3:@0ms:(assertion note): NEORV32 CPU ISA Configuration (MARCH): RV32IMACU_Zbb_Zicsr_Zifencei_Zfinx_Debug
|
../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.
|
../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.
|
../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).
|
../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).
|
Line 1108... |
Line 1212... |
../rtl/core/neorv32_wishbone.vhd:136:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing STANDARD Wishbone protocol.
|
../rtl/core/neorv32_wishbone.vhd:136:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing STANDARD Wishbone protocol.
|
../rtl/core/neorv32_wishbone.vhd:140:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing auto-timeout (255 cycles).
|
../rtl/core/neorv32_wishbone.vhd:140:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing auto-timeout (255 cycles).
|
../rtl/core/neorv32_wishbone.vhd:144:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing LITTLE-endian byte order.
|
../rtl/core/neorv32_wishbone.vhd:144:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing LITTLE-endian byte order.
|
../rtl/core/neorv32_wishbone.vhd:148:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing registered RX path.
|
../rtl/core/neorv32_wishbone.vhd:148:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing registered RX path.
|
../rtl/core/neorv32_slink.vhd:161:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing 8 RX and 8 TX stream links.
|
../rtl/core/neorv32_slink.vhd:161:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing 8 RX and 8 TX stream links.
|
|
|
##
|
##
|
## ## ## ##
|
## ## ## ##
|
## ## ######### ######## ######## ## ## ######## ######## ## ################
|
## ## ######### ######## ######## ## ## ######## ######## ## ################
|
#### ## ## ## ## ## ## ## ## ## ## ## ## ## #### ####
|
#### ## ## ## ## ## ## ## ## ## ## ## ## ## #### ####
|
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ##
|
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ##
|
Line 1122... |
Line 1226... |
## ## ######### ######## ## ## ## ######## ########## ## ################
|
## ## ######### ######## ## ## ## ######## ########## ## ################
|
## ## ## ##
|
## ## ## ##
|
##
|
##
|
Hello world! :)
|
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:
|
:sectnums:
|
=== Advanced Simulation using VUNIT
|
=== 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 entrypoint for executing the tests is `sim/run.py`.
|
|
|
.WORK IN PROGRESS
|
[source, bash]
|
[WARNING]
|
----
|
This Section Is Under Construction! +
|
# ./sim/run.py -l
|
+
|
neorv32.neorv32_tb.all
|
FIXME!
|
Listed 1 tests
|
|
|
The NEORV32 provides a more sophisticated simulation setup using https://vunit.github.io/[VUNIT].
|
# ./sim/run.py -v
|
The according VUNIT-based testbench is `sim/neorv32_tb.vhd`.
|
Compiling into neorv32: rtl/core/neorv32_uart.vhd passed
|
|
Compiling into neorv32: rtl/core/neorv32_twi.vhd passed
|
**WORK-IN-PROGRESS**
|
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.
|
|
|
|
|
|
|
// ####################################################################################################################
|
// ####################################################################################################################
|
:sectnums:
|
:sectnums:
|
Line 1218... |
Line 1349... |
[NOTE]
|
[NOTE]
|
This tutorial uses `gdb` to **directly upload an executable** to the processor. If you are using the default
|
This tutorial uses `gdb` to **directly upload an executable** to the processor. If you are using the default
|
processor setup _with_ internal instruction memory (IMEM) make sure it is implemented as RAM
|
processor setup _with_ internal instruction memory (IMEM) make sure it is implemented as RAM
|
(_INT_BOOTLOADER_EN_ generic = true).
|
(_INT_BOOTLOADER_EN_ generic = true).
|
|
|
|
[IMPORTANT]
|
|
The on-chip debugger is only implemented if the _ON_CHIP_DEBUGGER_EN_ generic is set _true_. Furthermore, it requires
|
|
the `Zicsr` and `Zifencei` CPU extension to be implemented (top generics _CPU_EXTENSION_RISCV_Zicsr_
|
|
and _CPU_EXTENSION_RISCV_Zifencei_ = true).
|
|
|
|
|
:sectnums:
|
:sectnums:
|
=== Hardware Requirements
|
=== Hardware Requirements
|
|
|
Make sure the on-chip debugger of your NEORV32 setups is implemented (_ON_CHIP_DEBUGGER_EN_ generic = true).
|
Make sure the on-chip debugger of your NEORV32 setups is implemented (_ON_CHIP_DEBUGGER_EN_ generic = true).
|
Line 1298... |
Line 1434... |
Navigate to `sw/example/blink_led` and compile the application:
|
Navigate to `sw/example/blink_led` and compile the application:
|
|
|
.Compile the test application
|
.Compile the test application
|
[source, bash]
|
[source, bash]
|
--------------------------
|
--------------------------
|
.../neorv32/sw/example/blink_led$ make MARCH=-march=rv32i clean_all all
|
.../neorv32/sw/example/blink_led$ make MARCH=-march=rv32i USER_FLAGS+=-g clean_all all
|
--------------------------
|
--------------------------
|
|
|
|
.Adding debug symbols to the executable
|
|
[NOTE]
|
|
`USER_FLAGS+=-g` passes the `-g` flag to the compiler so it adds debug information/symbols
|
|
to the generated ELF file. This is optional but will provide more sophisticated information for debugging
|
|
(like source file line numbers).
|
|
|
This will generate an ELF file `main.elf` that contains all the symbols required for debugging.
|
This will generate an ELF file `main.elf` that contains all the symbols required for debugging.
|
Furthermore, an assembly listing file `main.asm` is generated that we will use to define breakpoints.
|
Furthermore, an assembly listing file `main.asm` is generated that we will use to define breakpoints.
|
|
|
Open another terminal in `sw/example/blink_led` and start `gdb`.
|
Open another terminal in `sw/example/blink_led` and start `gdb`.
|
The GNU debugger is part of the toolchain (see <<_software_toolchain_setup>>).
|
The GNU debugger is part of the toolchain (see <<_software_toolchain_setup>>).
|
Line 1329... |
Line 1471... |
For help, type "help".
|
For help, type "help".
|
Type "apropos word" to search for commands related to "word".
|
Type "apropos word" to search for commands related to "word".
|
(gdb)
|
(gdb)
|
--------------------------
|
--------------------------
|
|
|
Now connect to OpenOCD using the default port 3333 on your local machine.
|
Now connect to OpenOCD using the default port 3333 on your machine.
|
Set the ELF file we want to debug to the recently generated `main.elf` from the `blink_led` example.
|
We will use the previously generated ELF file `main.elf` from the `blink_led` example.
|
Finally, upload the program to the processor.
|
Finally, upload the program to the processor and start debugging.
|
|
|
[NOTE]
|
[NOTE]
|
The executable that is uploaded to the processor is **not** the default NEORV32 executable (`neorv32_exe.bin`) that
|
The executable that is uploaded to the processor is **not** the default NEORV32 executable (`neorv32_exe.bin`) that
|
is used for uploading via the bootloader. Instead, all the required sections (like `.text`) are extracted from `mail.elf`
|
is used for uploading via the bootloader. Instead, all the required sections (like `.text`) are extracted from `mail.elf`
|
by GDB and uploaded via the debugger's indirect memory access.
|
by GDB and uploaded via the debugger's indirect memory access.
|
|
|
.Running GDB
|
.Running GDB
|
[source, bash]
|
[source, bash]
|
--------------------------
|
--------------------------
|
(gdb) target remote localhost:3333 <1>
|
(gdb) target extended-remote localhost:3333 <1>
|
Remote debugging using localhost:3333
|
Remote debugging using localhost:3333
|
warning: No executable has been specified and target does not support
|
warning: No executable has been specified and target does not support
|
determining executable automatically. Try using the "file" command.
|
determining executable automatically. Try using the "file" command.
|
0xffff0c94 in ?? () <2>
|
0xffff0c94 in ?? () <2>
|
(gdb) file main.elf <3>
|
(gdb) file main.elf <3>
|
Line 1403... |
Line 1545... |
--------------------------
|
--------------------------
|
(gdb) b * 0x690
|
(gdb) b * 0x690
|
Breakpoint 1 at 0x690
|
Breakpoint 1 at 0x690
|
--------------------------
|
--------------------------
|
|
|
|
.How do breakpoints work?
|
|
[TIP]
|
|
The NEORV32 on-chip debugger does not provide any hardware breakpoints (RISC-V "trigger modules") that compare an address like the PC
|
|
with a predefined value. Instead, gdb will modify the actual executable in IMEM: the actual instruction at the address
|
|
of the specified breakpoint is replaced by a `break` / `c.break` instruction. Whenever execution reaches this instruction, debug mode is
|
|
re-entered and the debugger restores the original instruction at this address to maintain original program behavior.
|
|
|
Now execute `c` (= continue). The CPU will resume operation until it hits the break-point.
|
Now execute `c` (= continue). The CPU will resume operation until it hits the break-point.
|
By this we can "step" from increment to increment.
|
By this we can "step" from increment to increment.
|
|
|
.Iterating from breakpoint to breakpoint
|
.Iterating from breakpoint to breakpoint
|
[source, bash]
|
[source, bash]
|