Let’s Get It Started!
This user guide uses the NEORV32 project as is from the official neorv32
repository.
To make your first NEORV32 project run, follow the guides from the upcoming sections. It is recommended to
follow these guides step by step and eventually in the presented order.
This guide uses the minimalistic and platform/toolchain agnostic SoC test setups from
rtl/test_setups for illustration. You can use one of the provided test setups for
your first FPGA tests.For more sophisticated example setups have a look at the neorv32-setups repository, which provides SoC setups for various FPGAs, boards and toolchains. |
Quick Links
-
Toolchain, hardware and general software framework setup
-
compile an application and upload it or making it persistent in internal memory
-
setup a new application project
-
optimizing the core for your application
-
add custom hardware extensions and customizing the bootloader
-
program an external SPI flash for persistent application storage
-
generate an AMD Vivado IP block
-
simulate the processor and build the documentation
-
build SoCs using LiteX
-
in-system debugging of the whole processor
-
NEORV32 in Verilog - an all-Verilog "version" of the processor
-
use the Eclipse IDE to develop and debug code for the NEORV32
1. Software Toolchain Setup
To compile (and debug) executables for the NEORV32 a RISC-V-compatible toolchain is required. By default, the project’s software framework uses the GNU C Compiler RISC-V port "RISC-V GCC". Basically, there are two options to obtain such a toolchain:
-
Download and build the RISC-V GNU toolchain by yourself.
-
Download and install a prebuilt version of the toolchain.
Default GCC Prefix
The default toolchain prefix for this project is riscv-none-elf- (RISCV_PREFIX variable).
|
Toolchain Requirements
Library/ISA Considerations
Note that a toolchain build with --with-arch=rv32imc provides library code (like the C standard library)
compiled entirely using compressed (C ) and mul /div instructions (M ). Hence, this pre-compiled library
code CANNOT be executed (without emulation) on an architecture that does not support these ISA extensions.
|
Building the Toolchain from Scratch
The official RISC-V GCC GitHub repository (https://github.com/riscv-collab/riscv-gnu-toolchain) provides instructions for building the toolchain from scratch:
rv32i
(minimal ISA only in this example)$ git clone https://github.com/riscv/riscv-gnu-toolchain
$ cd riscv-gnu-toolchain
$ riscv-gnu-toolchain$ ./configure --prefix=/opt/riscv --with-arch=rv32i --with-abi=ilp32
$ riscv-gnu-toolchain$ make
Downloading and Installing a Prebuilt Toolchain
Alternatively, a prebuilt toolchain can be used. Some OS package managers provide embedded RISC-V GCC toolchain. However, I can highly recommend the toolchain provided by the X-Pack project (MIT license): https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
Toolchain Installation
To integrate the toolchain of choice into the NEORV32 software framework, the toolchain’s binaries need
to be added to the system path (e.g. PATH
environment variable) so they can be used by a shell. Therefore,
the absolute path to the toolchain’s bin
folder has to be appended to the PATH
variable:
$ export PATH=$PATH:/opt/riscv/bin
bashrc
This command can be added to .bashrc (or similar) to automatically add the RISC-V
toolchain at every console start.
|
To make sure everything works fine, navigate to an example project in the NEORV32 sw/example
folder and
execute the following command:
neorv32/sw/example/demo_blink_led$ make check
This will test all the tools required for generating NEORV32 executables. Everything is working fine if "Toolchain check OK" appears at the end of the log output.
2. General Hardware Setup
This guide shows the basics of setting up a NEORV32 project for simulation or synthesis from scratch. It uses a simple, exemplary test "SoC" setup of the processor to keep things simple at the beginning. This simple setup is intended for a first test / evaluation of the NEORV32.
The NEORV32 project features three minimalistic pre-configured test setups in
rtl/test_setups
.
These test setups only implement very basic processor and CPU features and mainly differ in the actual boot configuration.
rtl/test_setups/neorv32_test_setup_bootloader.vhd
)-
Create a new project with your FPGA/ASIC/simulator EDA tool of choice.
-
Add all VHDL files from the project’s
rtl/core
folder to your project. Make sure to add all these rtl files to a new library calledneorv32
. If your toolchain does not provide a field to enter the library name, check out the "properties" menu of the added rtl files.
Compile Order and File-List Files
Some tools (like Lattice Radiant) might require a manual compile order of the VHDL source files to
identify the dependencies. The rtl folder features file-list files that list all required HDL files in
their recommended compilation order (see https://stnolting.github.io/neorv32/#_file_list_files).
|
-
The
rtl/core/neorv32_top.vhd
VHDL file is the top entity of the NEORV32 processor, which can be instantiated within the actual project. However, in this tutorial we will use one of the pre-defined test setups fromrtl/test_setups
(see above).
Make sure to include the neorv32 package into your design when instantiating the processor: add
library neorv32; and use neorv32.neorv32_package.all; to your design unit.
|
-
Add the pre-defined test setup of choice to the project, too, and select it as top entity.
-
The entity of the test setups provides a minimal set of configuration generics, that might have to be adapted to match your FPGA and board:
generic (
-- adapt these for your setup --
CLOCK_FREQUENCY : natural := 100000000; (1)
MEM_INT_IMEM_SIZE : natural := 16*1024; (2)
MEM_INT_DMEM_SIZE : natural := 8*1024 (3)
);
1 | Clock frequency of clk_i signal in Hertz |
2 | Default size of internal instruction memory: 16kB |
3 | Default size of internal data memory: 8kB |
-
If you want to or if your FPGA does not provide sufficient resources you can modify the memory sizes (
MEM_INT_IMEM_SIZE
andMEM_INT_DMEM_SIZE
). -
There is one generic that has to be set according to your FPGA board setup: the actual clock frequency of the top’s clock input signal (
clk_i
). Use theCLOCK_FREQUENCY
generic to specify your clock source’s frequency in Hertz (Hz).
Memory Layout
If you have changed the default memory configuration (MEM_INT_IMEM_SIZE and MEM_INT_DMEM_SIZE generics)
keep those new sizes in mind - these values are required for setting up the software framework in the next
section General Software Framework Setup.
|
-
Assign the signals of the test setup top entity to the according pins of your FPGA board. All the signals can be found in the entity declaration of the corresponding test setup, e.g.:
neorv32_test_setup_bootloader.vhd
port (
-- Global control --
clk_i : in std_ulogic; -- global clock, rising edge
rstn_i : in std_ulogic; -- global reset, low-active, async
-- GPIO --
gpio_o : out std_ulogic_vector(7 downto 0); -- parallel output
-- UART0 --
uart0_txd_o : out std_ulogic; -- UART0 send data
uart0_rxd_i : in std_ulogic -- UART0 receive data
);
Signal Polarity
If your FPGA board has inverse polarity for certain input/output you need to add inverters. Example: The reset signal
rstn_i is low-active by default; the LEDs connected to gpio_o are high-active by default.
|
-
Attach the clock input
clk_i
to your clock source and connect the reset linerstn_i
to a button of your FPGA board. Check whether it is low-active or high-active - the reset signal of the processor is low-active, so maybe you need to invert the input signal. -
If possible, connected at least bit
0
of the GPIO output portgpio_o
to a LED (see "Signal Polarity" note above). -
If your are using a UART-based test setup connect the UART communication signals
uart0_txd_o
anduart0_rxd_i
to the host interface (e.g. a USB-UART converter). -
If you are using the on-chip debugger setup connect the processor’s JTAG signal
jtag_*
to a suitable JTAG adapter. -
Perform the project HDL compilation (synthesis, mapping, placement, routing, bitstream generation).
-
Program the generated bitstream into your FPGA and press the button connected to the reset signal.
-
Done! The LED(s) connected to
gpio_o
should be flashing now.
3. General Software Framework Setup
To allow executables to be actually executed on the NEORV32 Processor the configuration of the software framework has to be aware to the hardware configuration. This guide focuses on the memory configuration. To enable certain CPU ISA features refer to the [_enabling_risc_v_cpu_extensions] section.
This guide shows how to configure the linker script for a given hardware memory configuration. More information regarding the linker script itself can be found in the according section of the data sheet: https://stnolting.github.io/neorv32/#_linker_script
If you have not changed the default memory configuration in section General Hardware Setup you are already done and you can skip the rest of this section. |
Always keep the processor’s Address Space layout in mind when modifying the linker script |
There are two options to modify the default memory configuration of the linker script:
-
Overriding the Default Configuration (recommended!)
3.1. Modifying the Linker Script
This will modify the linker script itself.
-
Open the NEORV32 linker script
sw/common/neorv32.ld
with a text editor. Right at the beginning of this script you will find theNEORV32 memory configuration
configuration section:
neorv32.ld
/* Default rom/ram (IMEM/DMEM) sizes */
__neorv32_rom_size = DEFINED(__neorv32_rom_size) ? __neorv32_rom_size : 2048M; (1)
__neorv32_ram_size = DEFINED(__neorv32_ram_size) ? __neorv32_ram_size : 8K; (2)
/* Default HEAP size (= 0; no heap at all) */
__neorv32_heap_size = DEFINED(__neorv32_heap_size) ? __neorv32_heap_size : 0; (3)
/* Default section base addresses - do not change this unless the hardware-defined address space layout is changed! */
__neorv32_rom_base = DEFINED(__neorv32_rom_base) ? __neorv32_rom_base : 0x00000000; /* = VHDL package's "ispace_base_c" */ (4)
__neorv32_ram_base = DEFINED(__neorv32_ram_base) ? __neorv32_ram_base : 0x80000000; /* = VHDL package's "dspace_base_c" */ (5)
1 | Default (max) size of the instruction memory address space (right-most value) (internal/external IMEM): 2048MB |
2 | Default size of the data memory address space (right-most value) (internal/external DMEM): 8kB |
3 | Default size of the HEAP (right-most value): 0kB |
4 | Default base address of the instruction memory address space (right-most value): 0x00000000 |
5 | Default base address of the data memory address space (right-most value): 0x80000000 |
-
Only the the
neorv32_ram_size
variable needs to modified! If you have changed the default DMEM (MEM_INT_DMEM_SIZE generic) size then change the right-most parameter (here:8kB
) so it is equal to your DMEM hardware configuration. Theneorv32_rom_size
does not need to be modified even if you have changed the default IMEM size. For more information see https://stnolting.github.io/neorv32/#_linker_script
-
Done! Save your changes and close the linker script.
3.2. Overriding the Default Configuration
This will not change the default linker script at all. Hence, this approach is recommended as it allows a per-project memory configuration without changing the code base.
The RAM and ROM sizes from Modifying the Linker Script (as well as the according base addresses) can also be modified
by overriding the default values when invoking make
. Therefore, the command needs to pass the according
values to the linker using the makefile’s USER_FLAGS
variable.
See section "Application Makefile" of the data sheet for more information regarding the default makefile variables: https://stnolting.github.io/neorv32/#_application_makefile |
$ make USER_FLAGS+="-Wl,--defsym,__neorv32_ram_size=16k -Wl,--defsym,__neorv32_rom_size=32k" clean_all exe
The -Wl
passes the following command/flag to the linker while --defsym
defines a symbol for the linker.
Hence, the default linker script section sizes are overridden. In this example the RAM size (=DMEM) is set to
16kB and the ROM size (=IMEM) is set to 32kB.
When using this approach the customized attributes have to be specified every time the makefile is invoked! You can put the RAM/ROM override commands into the project’s local makefile or define a simple shell script that defines all the setup-related parameters (memory sizes, RISC-V ISA extensions, optimization goal, further tuning flags, etc.). |
4. Application Program Compilation
This guide shows how to compile an example C-code application into a NEORV32 executable that can be uploaded via the bootloader or the on-chip debugger.
-
Open a terminal console and navigate to one of the project’s example programs. For instance, navigate to the simple
sw/example_demo_blink_led
example program. This program uses the NEORV32 GPIO module to display an 8-bit counter on the lowest eight bit of thegpio_o
output port. -
To compile the project and generate an executable simply execute:
neorv32/sw/example/demo_blink_led$ make clean_all exe
-
The
clean_all
target is used (instead of justclean
) to ensure everything is re-build. -
The
exe
target will compile and link the application sources together with all the included libraries. At the end an ELF file (main.elf
) is generated. The NEORV32 image generator (insw/image_gen
) takes this file and creates the final executable (neorv32_exe.bin
). The makefile will show the resulting memory utilization and the executable size:
neorv32/sw/example/demo_blink_led$ make clean_all exe
Memory utilization:
text data bss dec hex filename
1004 0 0 1004 3ec main.elf
Compiling ../../../sw/image_gen/image_gen
Executable (neorv32_exe.bin) size in bytes:
1016
Build Artifacts
All intermediate build artifacts (like object files and binaries) will be places into a (new) project-local
folder named build . The resulting build artifacts (like executable, the main ELF and all memory
initialization/image files) will be placed in the root project folder.
|
-
That’s it. The
exe
target has created the actual executableneorv32_exe.bin
in the current folder that is ready to be uploaded to the processor using the build-in bootloader. Alternatively, the ELF file can be uploaded using the on-chip debugger.
5. Uploading and Starting of a Binary Executable Image via UART
Follow this guide to use the bootloader to upload an executable via UART.
This concept uses the default "Indirect Boot" scenario that uses the bootloader to upload new executables. See datasheet section Indirect Boot for more information. |
If your FPGA board does not provide such an interface - don’t worry! Section Installing an Executable Directly Into Memory shows how to run custom programs on your FPGA setup without having a UART. |
-
Connect the primary UART (UART0) interface of your FPGA board to a serial port of your host computer.
-
Start a terminal program. In this tutorial, I am using TeraTerm for Windows. You can download it for free from https://ttssh2.osdn.jp/index.html.en . On Linux you could use
cutecom
(recommended) orGTKTerm
, which you can get here https://github.com/Jeija/gtkterm.git (or install via your package manager).
Any terminal program that can connect to a serial port should work. However, make sure the program can transfer data in raw byte mode without any protocol overhead around it. Some terminal programs struggle with transmitting files larger than 4kB (see https://github.com/stnolting/neorv32/pull/215). Try a different program if uploading a binary does not work (terminal stall). |
-
Open a connection to the the serial port your UART is connected to. Configure the terminal setting according to the following parameters:
-
19200 Baud
-
8 data bits
-
1 stop bit
-
no parity bits
-
no transmission/flow control protocol
-
newline on
\r\n
(carriage return and line feed)
-
-
Also make sure that single chars are send from your computer without any consecutive "new line" or "carriage return" commands. This is highly dependent on your terminal application of choice, TeraTerm only sends the raw chars by default. In
cutecom
, changeLF
toNone
in the drop-down menu next to the input text box. -
Press the NEORV32 reset button to restart the bootloader. The status LED starts blinking and the bootloader intro screen appears in your console. Hurry up and press any key (hit space!) to abort the automatic boot sequence and to start the actual bootloader user interface console.
<< NEORV32 Bootloader >>
BLDV: Mar 7 2023
HWV: 0x01080107
CID: 0x00000000
CLK: 0x05f5e100
MISA: 0x40901106
XISA: 0xc0000fab
SOC: 0xffff402f
IMEM: 0x00008000
DMEM: 0x00002000
Autoboot in 10s. Press any key to abort.
Aborted.
Available CMDs:
h: Help
r: Restart
u: Upload
s: Store to flash
l: Load from flash
x: Boot from flash (XIP)
e: Execute
CMD:>
-
Execute the "Upload" command by typing
u
. Now the bootloader is waiting for a binary executable to be send.
CMD:> u
Awaiting neorv32_exe.bin...
-
Use the "send file" option of your terminal program to send a NEORV32 executable (
neorv32_exe.bin
). -
Again, make sure to transmit the executable in raw binary mode (no transfer protocol). When using TeraTerm, select the "binary" option in the send file dialog.
-
If everything went fine, OK will appear in your terminal:
Make sure to upload the NEORV32 executable neorv32_exe.bin . Uploading any other file (like main.bin )
will cause an ERR_EXE bootloader error (see https://stnolting.github.io/neorv32/#_bootloader_error_codes).
|
CMD:> u
Awaiting neorv32_exe.bin... OK
-
The executable is now in the instruction memory of the processor. To execute the program right now run the "Execute" command by typing
e
:
CMD:> u
Awaiting neorv32_exe.bin... OK
CMD:> e
Booting...
Blinking LED demo program
-
If everything went fine, you should see the LEDs blinking.
The bootloader will print error codes if something went wrong. See section Bootloader of the NEORV32 datasheet for more information. |
See section Programming an External SPI Flash via the Bootloader to learn how to use an external SPI flash for nonvolatile program storage. |
Executables can also be uploaded via the on-chip debugger. See section Debugging with GDB for more information. |
6. Installing an Executable Directly Into Memory
If you do not want to use the bootloader (or the on-chip debugger) for executable upload or if your setup does not provide a serial interface for that, you can also directly install an application into embedded memory.
This concept uses the "Direct Boot" scenario that implements the processor-internal IMEM as ROM, which is pre-initialized with the application’s executable during synthesis. Hence, it provides non-volatile storage of the executable inside the processor. This storage cannot be altered during runtime and any source code modification of the application requires to re-program the FPGA via the bitstream.
See datasheet section Direct Boot for more information. |
Using the IMEM as ROM:
-
for this boot concept the bootloader is no longer required
-
this concept only works for the internal IMEM (but can be extended to work with external memories coupled via the processor’s bus interface)
-
make sure that the memory components (like block RAM) the IMEM is mapped to support an initialization via the bitstream
-
At first, make sure your processor setup actually implements the internal IMEM: the
MEM_INT_IMEM_EN
generics has to be set totrue
:
-- Internal Instruction memory --
MEM_INT_IMEM_EN => true, -- implement processor-internal instruction memory
-
For this setup we do not want the bootloader to be implemented at all. Disable implementation of the bootloader by setting the
INT_BOOTLOADER_EN
generic tofalse
. This will also modify the processor-internal IMEM so it is initialized with the executable during synthesis.
-- General --
INT_BOOTLOADER_EN => false, -- boot configuration: false = boot from int/ext (I)MEM
-
To generate an "initialization image" for the IMEM that contains the actual application, run the
install
target when compiling your application:
neorv32/sw/example/demo_blink_led$ make clean_all install
Memory utilization:
text data bss dec hex filename
1004 0 0 1004 3ec main.elf
Compiling ../../../sw/image_gen/image_gen
Executable (neorv32_exe.bin) size in bytes:
1016
Installing application image to ../../../rtl/core/neorv32_application_image.vhd
-
The
install
target has compiled all the application sources but instead of creating an executable (neorv32_exe.bit
) that can be uploaded via the bootloader, it has created a VHDL memory initialization imagecore/neorv32_application_image.vhd
. -
This VHDL file is automatically copied to the core’s rtl folder (
rtl/core
) so it will be included for the next synthesis. -
Perform a new synthesis. The IMEM will be build as pre-initialized ROM (inferring embedded memories if possible).
-
Upload your bitstream. Your application code now resides unchangeable in the processor’s IMEM and is directly executed after reset.
The synthesis tool / simulator will print asserts to inform about the (IMEM) memory / boot configuration:
NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM).
NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (1016 bytes), pre-initialized with application.
7. Setup of a New Application Program Project
-
The easiest way of creating a new software application project is to copy an existing one. This will keep all file dependencies. For example you can copy
sw/example/demo_blink_led
tosw/example/flux_capacitor
. -
If you want to place you application somewhere outside
sw/example
you need to adapt the application’s makefile. In the makefile you will find a variable that keeps the relative or absolute path to the NEORV32 repository home folder. Just modify this variable according to your new project’s home location:
# Relative or absolute path to the NEORV32 home folder (use default if not set by user)
NEORV32_HOME ?= ../../..
-
If your project contains additional source files outside of the project folder, you can add them to the
APP_SRC
variable:
# User's application sources (add additional files here)
APP_SRC = $(wildcard *.c) ../somewhere/some_file.c
-
You also can add a folder containing your application’s include files to the
APP_INC
variable (do not forget the-I
prefix):
# User's application include folders (don't forget the '-I' before each entry)
APP_INC = -I . -I ../somewhere/include_stuff_folder
8. Application-Specific Processor Configuration
The processor’s configuration options, which are mainly defined via the top entity VHDL generics, allow to tailor the entire SoC according to the application-specific requirements. Note that this chapter does not focus on optional SoC features like IO/peripheral modules - it rather gives ideas on how to optimize for overall goals like performance and area.
Please keep in mind that optimizing the design in one direction (like performance) will also effect other potential optimization goals (like area and energy). |
8.1. Optimize for Performance
The following points show some concepts to optimize the processor for performance regardless of the costs (i.e. increasing area and energy requirements):
-
Enable all performance-related RISC-V CPU extensions that implement dedicated hardware accelerators instead of emulating operations entirely in software:
M
,C
,Zfinx
-
Enable mapping of compleX CPU operations to dedicated hardware:
FAST_MUL_EN ⇒ true
to use DSP slices for multiplications,FAST_SHIFT_EN ⇒ true
use a fast barrel shifter for shift operations. -
Implement the instruction cache:
ICACHE_EN ⇒ true
-
Use as many internal memory as possible to reduce memory access latency:
MEM_INT_IMEM_EN ⇒ true
andMEM_INT_DMEM_EN ⇒ true
, maximizeMEM_INT_IMEM_SIZE
andMEM_INT_DMEM_SIZE
-
To be continued…
8.2. Optimize for Size
The NEORV32 is a size-optimized processor system that is intended to fit into tiny niches within large SoC designs or to be used a customized microcontroller in really tiny / low-power FPGAs (like Lattice iCE40). Here are some ideas how to make the processor even smaller while maintaining it’s general purpose system concept and maximum RISC-V compatibility.
SoC
-
This is obvious, but exclude all unused optional IO/peripheral modules from synthesis via the processor configuration generics.
-
If an IO module provides an option to configure the number of "channels", constrain this number to the actually required value (e.g. the PWM module
IO_PWM_NUM_CH
or the external interrupt controllerXIRQ_NUM_CH
). -
Disable the instruction cache (
ICACHE_EN ⇒ false
) if the design only uses processor-internal IMEM and DMEM memories. -
To be continued…
CPU
-
Use the embedded RISC-V CPU architecture extension (
CPU_EXTENSION_RISCV_E
) to reduce block RAM utilization. -
The compressed instructions extension (
CPU_EXTENSION_RISCV_C
) requires additional logic for the decoder but also reduces program code size by approximately 30%. -
If not explicitly used/required, exclude the CPU standard counters
[m]instret[h]
(number of instruction) and[m]cycle[h]
(number of cycles) from synthesis by disabling theZicntr
ISA extension (note, this is not RISC-V compliant). -
Map CPU shift operations to a small and iterative shifter unit (
FAST_SHIFT_EN ⇒ false
). -
If you have unused DSP block available, you can map multiplication operations to those slices instead of using LUTs to implement the multiplier (
FAST_MUL_EN ⇒ true
). -
If there is no need to execute division in hardware, use the
Zmmul
extension instead of the full-scaleM
extension. -
Disable CPU extension that are not explicitly used.
-
To be continued…
8.3. Optimize for Clock Speed
The NEORV32 Processor and CPU are designed to provide minimal logic between register stages to keep the critical path as short as possible. When enabling additional extension or modules the impact on the existing logic is also kept at a minimum to prevent timing degrading. If there is a major impact on existing logic (example: many physical memory protection address configuration registers) the VHDL code automatically adds additional register stages to maintain critical path length. Obviously, this increases operation latency.
Enable the "ASIC style" / full-reset register file option (REGFILE_HW_RST ) to obtain maximum clock speed for
the CPU (at the cost of an increased hardware footprint).
|
In order to optimize for a minimal critical path (= maximum clock speed) the following points should be considered:
-
Complex CPU extensions (in terms of hardware requirements) should be avoided (examples: floating-point unit, physical memory protection).
-
Large carry chains (>32-bit) should be avoided (i.e. constrain the HPM counter sizes via
HPM_CNT_WIDTH
). -
If the target FPGA provides sufficient DSP resources, CPU multiplication operations can be mapped to DSP slices (
FAST_MUL_EN ⇒ true
) reducing LUT usage and critical path impact while also increasing overall performance. -
Use the synchronous (registered) RX path configuration of the external bus interface (
XBUS_ASYNC_RX ⇒ false
). -
To be continued…
The short and fixed-length critical path allows to integrate the core into existing clock domains. So no clock domain-crossing and no sub-clock generation is required. However, for very high clock frequencies (this is technology / platform dependent) clock domain crossing becomes crucial for chip-internal connections. |
8.4. Optimize for Energy
There are no dedicated configuration options to optimize the processor for energy (minimal consumption; energy/instruction ratio) yet. However, a reduced processor area (Optimize for Size) will also reduce static energy consumption.
To optimize your setup for low-power applications, you can make use of the CPU sleep mode (wfi
instruction).
Put the CPU to sleep mode whenever possible. If the clock gating feature is enabled (CLOCK_GATING_EN
) the entire
CPU complex will be disconnected from the clock tree while in sleep mode.
Disable all processor modules that are not actually used (exclude them from synthesis if they will be never used; disable a module via it’s control register if the module is not currently used).
Processor-internal clock generator shutdown
If no IO/peripheral module is currently enabled, the processor’s internal clock generator circuit will be
shut down reducing switching activity and thus, dynamic energy consumption.
|
9. 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. A Comparative Summary is given at the end of this section.
Debugging/Testing Custom Hardware Modules
Custom hardware IP modules connected via the external bus interface or integrated as CFU can be debugged "in-system" using the
"bus explorer" example program (sw/example_bus_explorer ). This program provides an interactive console (via UART0)
that allows to perform arbitrary read and write access from/to any memory-mapped register.
|
9.1. 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 GPIO, UART, SPI and 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 could be added using the 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). Hence, it is not recommend to use them for chip-internal communication.
9.2. External Bus Interface
The External Bus Interface provides the classic approach for attaching custom IP. By default, the bus interface implements the widely adopted Wishbone interface standard. This project also includes wrappers to convert to other protocol standards like ARM’s AXI4-Lite or Intel’s Avalon protocols. By using a full-featured bus protocol, complex SoC designs 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.
Custom hardware modules attached to the processor’s bus interface have no limitations regarding their functionality. User-defined interfaces (like DDR memory access) can be implemented and the hardware module can operate completely independent of the CPU.
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 address space. This allows a very simple still high-bandwidth communications. However, high bus traffic may increase access latencies.
9.3. Custom Functions Subsystem
The Custom Functions Subsystem (CFS) is an "empty" template for a memory-mapped, processor-internal module.
The basic idea of this subsystem is to provide a convenient, simple and flexible platform, 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. Note that the CFS does not have direct access to memory. All data (and control instruction) have to be send by the CPU.
The use-cases for the CFS include medium-scale hardware accelerators that need to be tightly-coupled to the CPU. Potential use cases could be DSP modules like CORDIC, cryptographic accelerators or custom interfaces (like IIS).
9.4. Custom Functions Unit
The Custom Functions Unit (CFU) is a functional unit that is integrated right into the CPU’s pipeline. It allows to implement custom RISC-V instructions. This extension option is intended for rather small logic that implements operations, which cannot be emulated in pure software in an efficient way. Since the CFU has direct access to the core’s register file it can operate with minimal data latency.
9.5. Comparative Summary
The following table gives a comparative summary of the most important factors when choosing one of the chip-internal extension options:
-
Custom Functions Unit (CFU) for CPU-internal custom RISC-V instructions
-
Custom Functions Subsystem (CFS) for tightly-coupled processor-internal co-processors
-
External Bus Interface (WISHBONE) for processor-external memory-mapped modules
Custom Functions Unit (CFU) | Custom Functions Subsystem (CFS) | External Bus Interface | |
---|---|---|---|
RTL location |
CPU-internal |
processor-internal |
processor-external |
HW complexity/size |
small |
medium |
large |
CPU-independent operation |
no |
yes |
yes |
CPU interface |
register file access |
memory-mapped |
memory-mapped |
Low-level access mechanism |
custom instructions |
load/store |
load/store |
Access latency |
minimal |
low |
medium to high |
External IO interfaces |
not supported |
yes, but limited |
yes, user-defined |
Exception capability |
yes |
no |
no |
Interrupt capability |
no |
yes |
user-defined |
10. Customizing the Internal Bootloader
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 modify to bootloader source code to provide a setup that perfectly fits your needs.
Each time the bootloader sources are modified, the bootloader has to be re-compiled (and re-installed to the bootloader ROM) and the processor has to be re-synthesized. |
Keep in mind that the maximum size for the bootloader is limited to 8kB and it should be compiled using the
minimal base & privileged ISA rv32i_zicsr_zifencei only to ensure it can work independently of the actual CPU configuration.
|
Parameter | Default | Legal values | Description |
---|---|---|---|
Memory layout |
|||
|
|
any |
Base address / boot address for the executable (see section "Address Space" in the NEORV32 data sheet) |
Serial console interface |
|||
|
|
|
Set to |
|
|
any |
Baud rate of UART0 |
|
|
|
Set to |
Status LED |
|||
|
|
|
Enable bootloader status led ("heart beat") at |
|
|
|
|
Auto-boot configuration |
|||
|
|
any |
Time in seconds after the auto-boot sequence starts (if there is no UART input by the user); set to 0 to disabled auto-boot sequence |
SPI configuration |
|||
|
|
|
Set |
|
|
|
SPI chip select output ( |
|
|
|
SPI flash address size in number of bytes (2=16-bit, 3=24-bit, 4=32-bit) |
|
|
any |
SPI flash sector size in bytes |
|
|
|
SPI clock pre-scaler (dividing main processor clock) |
|
|
any 32-bit value |
Defines the base address of the executable in external flash |
XIP configuration |
|||
|
|
|
Set |
The XIP options re-use the "SPI configuration" options for configuring the XIP’s SPI connection. |
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
(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 GPIO output pin 20 use the following command:
sw/bootloader$ make USER_FLAGS+=-DUART_BAUD=57600 USER_FLAGS+=-DSTATUS_LED_PIN=20 clean_all bootloader
The clean_all target ensure that all libraries are re-compiled. The bootloader target will automatically
compile and install the bootloader to the HDL boot ROM (updating rtl/core/neorv32_bootloader_image.vhd ).
|
10.1. Auto-Boot Configuration
The default bootloader provides a UART-based user interface that allows to upload new executables at any time. Optionally, the executable can also be programmed to an external SPI flash by the bootloader (see section Programming an External SPI Flash via the Bootloader).
The bootloader also provides an automatic boot sequence (auto-boot) which will start copying an executable
from external SPI flash to IMEM using the default SPI configuration. By this, the default bootloader
provides a "non-volatile program storage" mechanism that automatically boots from external SPI flash
(after AUTO_BOOT_TIMEOUT
) while still providing the option to re-program the SPI flash at any time
via the UART console.
11. Programming an External SPI Flash via the Bootloader
The default processor-internal NEORV32 bootloader supports automatic booting from an external SPI flash. This guide shows how to write an executable to the SPI flash via the bootloader so it can be automatically fetched and executed after processor reset. For example, you can use a section of the FPGA bitstream configuration memory to store an application executable.
Customization
This section assumes the default configuration of the NEORV32 bootloader.
See section Customizing the Internal Bootloader on how to customize the bootloader and its setting
(for example the SPI chip-select port, the SPI clock speed or the flash base address for storing the executable).
|
11.1. Programming an Executable
-
At first, reset the NEORV32 processor and wait until the bootloader start screen appears in your terminal program.
-
Abort the auto boot sequence and start the user console by pressing any key.
-
Press u to upload the executable that you want to store to the external flash:
CMD:> u
Awaiting neorv32_exe.bin...
-
Send the binary in raw binary via your terminal program. When the upload is completed and "OK" appears, press
s
to trigger the programming of the flash (do not execute the image via thee
command as this might corrupt the image):
CMD:> u
Awaiting neorv32_exe.bin... OK
CMD:> s
Write 0x000013FC bytes to SPI flash @ 0x02000000? (y/n)
-
The bootloader shows the size of the executable and the base address inside the SPI flash where the executable is going to be stored. A prompt appears: Type
y
to start the programming or typen
to abort.
Section Customizing the Internal Bootloader show the according C-language define that can be modified
to specify the base address of the executable inside the SPI flash.
|
CMD:> u
Awaiting neorv32_exe.bin... OK
CMD:> s
Write 0x000013FC bytes to SPI flash @ 0x02000000? (y/n) y
Flashing... OK
CMD:>
The bootloader stores the executable in little-endian byte-order to the flash. |
-
If "OK" appears in the terminal line, the programming process was successful. Now you can use the auto boot sequence to automatically boot your application from the flash at system start-up without any user interaction.
12. Packaging the Processor as Vivado IP Block
Packaging the entire processor as IP module allows easy integration of the core (or even several cores)
into a block-design-based Vivado project. The NEORV32 repository provides a full-scale TCL script that
automatically packages the processor as Vivado IP block. For this, a specialized wrapper for the processor’s
top entity is provided (rtl/system_integration/neorv32_vivado_ip.vhd
) that features AXI4-Lite (via XBUS)
and AXI4-Stream (via SLINK) compatible interfaces.
General AXI Wrapper
The provided AXI wrapper can also be used for custom (AXI) setups outside of Vivado and/or IP block designs.
|
Besides packaging the HDL modules, the TCL script also generates a simplified customization GUI that allows an easy and intuitive configuration of the processor. The rather complex VHDL configuration generics are renamed and provided with tool tips to make it easier to understand the different configuration options.
The following steps show how to package the processor using the provided TCL script and how to import the generated IP block into the Vivado IP repository.
-
Open the Vivado GUI.
-
In GUI mode select either "Tools → Run TCL Script" to directly execute the script or open the TCL shell ("Window → Tcl Console") to manually invoke the script.
-
Use
cd
in the TCL console to navigate to the project’sneorv32/rtl/system_integration
folder. -
Execute
source neorv32_vivado_ip.tcl
in the TCL console. -
A second Vivado instance will open automatically packaging the IP module. After this process is completed, the second Vivado instance will automatically close again.
-
A new folder
neorv32_vivado_ip_work
is created inneorv32/rtl/system_integration
which contains the IP-packaging Vivado project. -
Inside, the
packaged_ip
folder provides the actual IP module. -
Open your design project in Vivado.
-
Click on "Settings" in the "Project Manager" on the left side.
-
Under "Project Settings" expand the "IP" section and click on "Repository".
-
Click the large plus button and select the previously generated IP folder (
path/to/neorv32/rtl/system_integration/neorv32_vivado_ip_work/packaged_ip
). -
Click "Select" and close the Settings menu with "Apply" and "OK".
-
You will find the NEORV32 in the "User Repository" section of the Vivado IP catalog.
Combinatorial Loops DRC Errors
If the TRNG is enabled it is recommended to add the following commands to the project’s constraints file in order
to prevent DRC errors during bitstream generation.
|
set_property SEVERITY {warning} [get_drc_checks LUTLP-1]
set_property IS_ENABLED FALSE [get_drc_checks LUTLP-1]
set_property ALLOW_COMBINATORIAL_LOOPS TRUE
Re-Packaging the IP Core
For every change that is made right to the hardware (excluding configuration made via the customization GUI!)
the NEORV32 IP module needs to be re-packaged by re-executing the packing script (neorv32_vivado_ip.tcl ).This also applies if an executable installed right into the IMEM (see section Installing an Executable Directly Into Memory) shall be updated. It is not not possible to replace the IMEM image ( neorv32_application_image.vhd ) file
in the packaged_ip folder. For the Vivado design suite, the new program to be executed must be compiled and installed using the
install makefile target. Next, the neorv32_vivado_ip.tcl script has to be executed again. Finally, Vivado will prompt to upgrade
the NEORV32 IP.
|
AMD Vivado / ISIM - Incremental Compilation of Simulation Sources
When using AMD Vivado (ISIM for simulation) make sure to TURN OFF "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.
|
13. 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, VUnit and Verification Components are used for verifying the functionality of the various peripherals from a hardware point of view.
AMD Vivado / ISIM - Incremental Compilation
When using AMD Vivado (ISIM for simulation) make sure to TURN OFF "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.
|
13.1. Testbench
VUnit Testbench
A more sophisticated testbench using VUnit is available in a separate repository:
https://github.com/stnolting/neorv32-vunit
|
A plain-VHDL (no third-party libraries) testbench (sim/neorv32_tb.vhd
) can be used for simulating and
testing the processor. This testbench features a 100MHz clock and enables all optional peripheral and CPU
extensions.
True Random Number Generator
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 architecture. Each configuration constant provides comments to explain the functionality.
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
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.
|
13.2. 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 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):
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.
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).
|
13.3. Simulation using a shell script (with GHDL)
To simulate the processor using GHDL navigate to the sim
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.
neorv32/sim$ sh ghdl.sh --stop-time=20ms
13.4. 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.
sw/example/demo_blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim
[...]
Blinking LED demo program
13.4.1. Hello World!
To do a quick test of the NEORV32 make sure to have GHDL and a
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
:
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_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. |
14. VHDL Development Environment
To navigate and develop the NEORV32 processor VHDL code you can use the free and open source VHDL-LS language server.
The easiest way to get started is to install the VHDL-LS VSCode extension.
The VHDL-LS server requires a vhdl_ls.toml
file which is automatically generated by the sim/run.py
script. See Simulate the processor for further information.
-
Run
sim/run.py
to create the library mapping file -
Install the VHDL-LS VSCode extension
-
Open the root folder of the NEORV32 repository in VSCode
-
Open any VHDL file
15. Building the Documentation
The documentation (datasheet + user guide) is written using asciidoc
. The according source files
can be found in docs/…
. The documentation of the software framework is written in-code using doxygen
.
A makefiles in the project’s docs
directory is provided to build all of the documentation as HTML pages
or as PDF documents.
Pre-rendered PDFs are available online as nightly pre-releases: https://github.com/stnolting/neorv32/releases. The HTML-based documentation is also available online at the project’s GitHub Pages. |
The makefile provides a help target to show all available build options and their according outputs.
neorv32/docs$ make help
asciidoctor
neorv32/docs$ make html
If you don’t have asciidoctor / asciidoctor-pdf installed, you can still generate all the documentation using
a docker container via make container .
|
16. Zephyr RTOS Support
The NEORV32 processor is supported by upstream Zephyr RTOS: https://docs.zephyrproject.org/latest/boards/others/neorv32/doc/index.html
The absolute path to the NEORV32 executable image generator binary (…/neorv32/sw/image_gen ) has to be added to the PATH variable
so the Zephyr build system can generate executables and memory-initialization images.
|
Zephyr OS port provided by GitHub user henrikbrixandersen (see https://github.com/stnolting/neorv32/discussions/172). ❤️ |
17. FreeRTOS Support
A NEORV32-specific port and a simple demo for FreeRTOS (https://github.com/FreeRTOS/FreeRTOS) are available in a separate repository on GitHub: https://github.com/stnolting/neorv32-freertos
18. LiteX SoC Builder Support
LiteX is a SoC builder framework by Enjoy-Digital that allows easy creation of complete system-on-chip designs - including sophisticated interfaces like Ethernet, serial ATA and DDR memory controller. The NEORV32 has been ported to the LiteX framework to be used as central processing unit.
The default microcontroller-like NEORV32 processor is not directly supported as all the peripherals would provide some redundancy. Instead, the LiteX port uses a core complex wrapper that only includes the actual NEORV32 CPU, the instruction cache (optional), the RISC-V machine system timer (optional), the on-chip debugger (optional) and the internal bus infrastructure. The specific implementation of optional modules as well as RISC-V ISA configuration and performance optimization options are controlled by a single CONFIGURATION option wrapped in the LiteX build flow. The external bus interface is used to connect to other LiteX SoC parts.
Core Complex Wrapper
The NEORV32 core complex wrapper used by LiteX for integration can be found in
rtl/system_integration/neorv32_litex_core_complex.vhd .
|
LiteX NEORV32 Documentation
More information can be found in the "NEORV32" section of the LiteX project wiki: https://github.com/enjoy-digital/litex/wiki/CPUs
|
Work-In-Progress 🚧
UG: synthesis - how to create a whole NEORV32 + LiteX SoC for a FPGALiteX: debugger - the NEORV32 on-chip-debugger is not supported by the LiteX port yet LiteX: external interrupt - the "RISC-V machine external interrupt" is not supported by the LiteX port yet |
18.1. LiteX Setup
-
Install LiteX and the RISC-V compiler following the excellent quick start guide: https://github.com/enjoy-digital/litex/wiki#quick-start-guide
-
The NEORV32 port for LiteX uses GHDL and yosys for converting the VHDL files via the GHDL-yosys-plugin. You can download prebuilt packages for example from https://github.com/YosysHQ/fpga-toolchain, which is _no longer maintained. It is superdesed by https://github.com/YosysHQ/fpga-toolchain.
-
EXPERIMENTAL: GHDL provides a synthesis options, which converts a VHDL setup into a plain-Verilog module (not tested on LiteX yet). Check out neorv32-verilog for more information.
GHDL-yosys Plugin
If you would like to use the experimental GHDL Yosys plugin for VHDL on Linux or MacOS, you will need to set
the GHDL_PREFIX environment variable. e.g. export GHDL_PREFIX=<install_dir>/fpga-toolchain/lib/ghdl .
On Windows this is not necessary.If you are using an existing Makefile set up for ghdl-yosys-plugin and see ERROR: This version of yosys is built without plugin support you probably need to remove -m ghdl from your yosys parameters. This is
because the plugin is typically loaded from a separate file but it is provided built into yosys in this
package.- from https://github.com/YosysHQ/fpga-toolchain This means you might have to edit the call to yosys in litex/soc/cores/cpu/neorv32/core.py .
|
-
Add the
bin
folder of the ghdl-yosys-plugin to yourPATH
environment variable. You can test your yosys installation and check for the GHDL plugin:
$ yosys -H
/----------------------------------------------------------------------------\
| |
| yosys -- Yosys Open SYnthesis Suite |
| |
| Copyright (C) 2012 - 2020 Claire Xenia Wolf <claire@yosyshq.com> |
| |
| Permission to use, copy, modify, and/or distribute this software for any |
| purpose with or without fee is hereby granted, provided that the above |
| copyright notice and this permission notice appear in all copies. |
| |
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| |
\----------------------------------------------------------------------------/
Yosys 0.10+12 (open-tool-forge build) (git sha1 356ec7bb, gcc 9.3.0-17ubuntu1~20.04 -Os)
-- Running command `help' --
... (1)
ghdl load VHDL designs using GHDL (2)
...
1 | A long list of plugins… |
2 | This is the plugin we need. |
18.2. LiteX Simulation
Start a simulation right in your console using the NEORV32 as target CPU:
$ litex_sim --cpu-type=neorv32
LiteX will start running its BIOS:
__ _ __ _ __
/ / (_) /____ | |/_/
/ /__/ / __/ -_)> <
/____/_/\__/\__/_/|_|
Build your hardware, easily!
(c) Copyright 2012-2022 Enjoy-Digital
(c) Copyright 2007-2015 M-Labs
BIOS built on Jul 19 2022 12:21:36
BIOS CRC passed (6f76f1e8)
LiteX git sha1: 0654279a
--=============== SoC ==================--
CPU: NEORV32-standard @ 1MHz
BUS: WISHBONE 32-bit @ 4GiB
CSR: 32-bit data
ROM: 128KiB
SRAM: 8KiB
--============== Boot ==================--
Booting from serial...
Press Q or ESC to abort boot completely.
sL5DdSMmkekro
Timeout
No boot medium found
--============= Console ================--
litex> help
LiteX BIOS, available commands:
flush_cpu_dcache - Flush CPU data cache
crc - Compute CRC32 of a part of the address space
ident - Identifier of the system
help - Print this help
serialboot - Boot from Serial (SFL)
reboot - Reboot
boot - Boot from Memory
mem_cmp - Compare memory content
mem_speed - Test memory speed
mem_test - Test memory access
mem_copy - Copy address space
mem_write - Write address space
mem_read - Read address space
mem_list - List available memory regions
litex>
You can use the provided console to execute LiteX commands.
19. Debugging using the On-Chip Debugger
The NEORV32 on-chip debugger ("OCD") allows online in-system debugging via an external JTAG access port from a
host machine. The general flow is independent of the host machine’s operating system. However, this tutorial uses
Windows and Linux (Ubuntu on Windows / WSL) in parallel running the upstream version of OpenOCD and the
RISC-V GNU debugger gdb
.
TLDR
You can start a pre-configured debug session (using default main.elf as executable and
target extended-remote localhost:3333 as GDB connection configuration) by using the GDB makefile target
(i.e. make gdb ).
|
OCD Hardware Implementation
See datasheet section On Chip Debugger (OCD)
for more information regarding the actual hardware.
|
OCD CPU Requirements
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, which are always enabled by the CPU.
|
19.1. Hardware Requirements
Make sure the on-chip debugger of your NEORV32 setup is implemented (ON_CHIP_DEBUGGER_EN
generic = true). 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
(INT_BOOTLOADER_EN
generic = true).
Connect a JTAG adapter to the NEORV32 jtag_*
interface signals. If you do not have a full-scale JTAG adapter, you can
also use a FTDI-based adapter like the "FT2232H-56Q Mini Module", which is a simple and inexpensive FTDI breakout board.
NEORV32 top signal | JTAG signal | Default FTDI port |
---|---|---|
|
TCK |
D0 |
|
TDI |
D1 |
|
TDO |
D2 |
|
TMS |
D3 |
JTAG TAP Reset
The NEORV32 JTAG TAP does not provide a dedicated reset signal ("TRST"). However, the missing TRST is not a problem,
since JTAG-level resets can be triggered using with TMS signaling.
|
19.2. OpenOCD
The NEORV32 on-chip debugger can be accessed using the upstream version of OpenOCD. A pre-configured OpenOCD configuration
file is provided (sw/openocd/openocd_neorv32.cfg
) that allows an easy access to the NEORV32 CPU.
You might need to adapt ftdi vid_pid , ftdi channel and ftdi layout_init in sw/openocd/openocd_neorv32.cfg
according to your interface chip and your operating system.
|
If you want to modify the JTAG clock speed (via adapter speed in sw/openocd/openocd_neorv32.cfg ) make sure to meet
the clock requirements noted in Documentation: Debug Transport Module (DTM).
|
To access the processor using OpenOCD, open a terminal and start OpenOCD with the pre-configured configuration file.
openocd_neorv32.cfg
scriptN:\Projects\neorv32\sw\openocd>openocd -f openocd_neorv32.cfg
Open On-Chip Debugger 0.11.0 (2021-11-18) [https://github.com/sysprogs/openocd]
Licensed under GNU GPL v2
libusb1 09e75e98b4d9ea7909e8837b7a3f00dda4589dc3
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : clock speed 1000 kHz
Info : JTAG tap: neorv32.cpu tap/device found: 0x00000000 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
Info : datacount=1 progbufsize=2
Info : Disabling abstract command reads from CSRs.
Info : Examined RISC-V core; found 1 harts
Info : hart 0: XLEN=32, misa=0x40901107
Info : starting gdb server for neorv32.cpu.0 on 3333
Info : Listening on port 3333 for gdb connections
Target HALTED.
Ready for remote connections.
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
OpenOCD has successfully connected to the NEORV32 on-chip debugger and has examined the CPU (showing the content of
the misa
CSRs). The processor is halted and OpenOCD waits fot gdb
to connect via port 3333.
19.3. Debugging with GDB
GDB + SVD
Together with a third-party plugin the processor’s SVD file can be imported right into GDB to allow comfortable
debugging of peripheral/IO devices (see https://github.com/stnolting/neorv32/discussions/656).
|
This guide uses the simple "blink example" from sw/example/demo_blink_led
as simplified test application to
show the basics of in-system debugging.
At first, the application needs to be compiled. We will use the minimal machine architecture configuration
(rv32i
) here to be independent of the actual processor/CPU configuration.
Navigate to sw/example/demo_blink_led
and compile the application:
.../neorv32/sw/example/demo_blink_led$ make MARCH=rv32i USER_FLAGS+=-g clean_all all
Adding debug symbols to the executable
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 debugging information
(like source file line numbers).
|
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.
Open another terminal in sw/example/demo_blink_led
and start gdb
.
.../neorv32/sw/example/demo_blink_led$ riscv32-unknown-elf-gdb
GNU gdb (GDB) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv32-unknown-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb)
Now connect to OpenOCD using the default port 3333 on your machine.
We will use the previously generated ELF file main.elf
from the demo_blink_led
example.
Finally, upload the program to the processor and start debugging.
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
by GDB and uploaded via the debugger’s indirect memory access.
|
(gdb) target extended-remote localhost:3333 (1)
Remote debugging using localhost:3333
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0xffff0c94 in ?? () (2)
(gdb) file main.elf (3)
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from main.elf...
(gdb) load (4)
Loading section .text, size 0xd0c lma 0x0
Loading section .rodata, size 0x39c lma 0xd0c
Start address 0x00000000, load size 4264
Transfer rate: 43 KB/sec, 2132 bytes/write.
(gdb)
1 | Connect to OpenOCD |
2 | The CPU was still executing code from the bootloader ROM - but that does not matter here |
3 | Select mail.elf from the demo_blink_led example |
4 | Upload the executable |
After the upload, GDB will make the processor jump to the beginning of the uploaded executable
(by default, this is the beginning of the instruction memory at 0x00000000
) skipping the bootloader
and halting the CPU right before executing the demo_blink_led
application.
After gdb has connected to the CPU, it is recommended to disable the CPU’s global interrupt flag
(mstatus.mie , = bit #3) to prevent unintended calls of potentially outdated trap handlers. The global
interrupt flag can be cleared using the following gdb command:
set $mstatus = ($mstatus & ~(1<<3)) . Interrupts can be enabled globally again by the following command:
set $mstatus = ($mstatus | (1<<3)) .
|
19.3.1. Software Breakpoints
The following steps are just a small showcase that illustrate a simple debugging scheme.
While compiling demo_blink_led
, an assembly listing file main.asm
was generated.
Open this file with a text editor to check out what the CPU is going to do when resumed.
The demo_blink_led
example implements a simple counter on the 8 lowest GPIO output ports. The program uses
"busy wait" to have a visible delay between increments. This waiting is done by calling the neorv32_cpu_delay_ms
function. We will add a breakpoint right at the end of this wait function so we can step through the iterations
of the counter.
main.asm
generated from the demo_blink_led
example00000688 <__neorv32_cpu_delay_ms_end>:
688: 01c12083 lw ra,28(sp)
68c: 02010113 addi sp,sp,32
690: 00008067 ret
The very last instruction of the neorv32_cpu_delay_ms
function is ret
(= return)
at hexadecimal 690
in this example. Add this address as breakpoint to GDB.
The address might be different if you use a different version of the software framework or if different ISA options are configured. |
(gdb) b * 0x690 (1)
Breakpoint 1 at 0x690
1 | b is an alias for break , which adds a software breakpoint. |
How do software breakpoints work?
Software breakpoints are used for debugging programs that are accessed from read/write memory (RAM) like IMEM. The debugger
temporarily replaces the instruction word of the instruction, where the breakpoint shall be inserted, by a ebreak / c.ebreak
instruction. Whenever execution reaches this instruction, debug mode is entered and the debugger restores the original
instruction at this address to maintain original program behavior.When debugging programs executed from ROM hardware-assisted breakpoints using the core’s trigger module have to be used. See section Hardware Breakpoints for more information. |
Now execute c
(= continue). The CPU will resume operation until it hits the break-point.
By this we can move from one counter increment to another.
Breakpoint 1 at 0x690
(gdb) c
Continuing.
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
(gdb) c
Continuing.
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
(gdb) c
Continuing.
Hardcoded EBREAK Instructions In The Program Code
If your original application code uses the BREAK instruction (for example for some OS calls/signaling) this
instruction will cause an enter to debug mode when executed. These situation cannot be continued using gdb’s
c nor can they be "stepped-over" using the single-step command s . You need to declare the ebreak instruction
as breakpoint to be able to resume operation after executing it. See https://sourceware.org/pipermail/gdb/2021-January/049125.html
|
19.3.2. Hardware Breakpoints
Hardware-assisted breakpoints using the CPU’s trigger module are required when debugging code that is executed from read-only memory (ROM) as GDB cannot temporarily replace instructions by BREAK instructions.
From a user point of view hardware breakpoints behave like software breakpoints. GDB provides a command to setup a hardware-assisted breakpoint:
(gdb) hb * 0x690 (1)
Breakpoint 1 at 0x690
1 | hb is an alias for hbreak , which adds a hardware breakpoint. |
The CPU’s trigger module only provides a single instruction address match type trigger. Hence, only
a single hb hardware-assisted breakpoint can be used.
|
19.4. Segger Embedded Studio
Software for the NEORV32 processor can also be developed and debugged in-system using Segger Embedded Studio and a Segger J-Link probe. The following links provide further information as well as an excellent tutorial.
-
Segger Embedded Studio: https://www.segger.com/products/development-tools/embedded-studio
-
Segger notes regarding NEORV32: https://wiki.segger.com/J-Link_NEORV32
-
Excellent tutorial: https://www.emb4fun.com/riscv/ses4rv/index.html
20. NEORV32 in Verilog
If you are more of a Verilog fan or if your EDA toolchain does not support VHDL or mixed-language designs
you can use an all-Verilog version of the processor provided by the
neorv32-verilog
repository.
Note that this is not a manual re-implementation of the core in Verilog but rather an automated conversion. |
GHDL’s synthesis feature is used to convert a pre-configured NEORV32 setup - including all peripherals, memories and memory images - into a single, unoptimized plain-Verilog module file without any (technology-specific) primitives.
GHDL Synthesis
More information regarding GHDL’s synthesis option can be found at https://ghdl.github.io/ghdl/using/Synthesis.html.
|
An intermediate VHDL wrapper is provided that can be used to configure the processor (using VHDL generics) and to customize the interface ports. After conversion, a single Verilog file is generated that contains the whole NEORV32 processor. The original processor module hierarchy is preserved as well as most (all?) signal names, which allows easy inspection and debugging of simulation waveforms and synthesis results.
module neorv32_verilog_wrapper
(input clk_i,
input rstn_i,
input uart0_rxd_i,
output uart0_txd_o);
The generated Verilog code has been simulated and verified with Icarus Verilog (simulation) and AMD Vivado (simulation and synthesis).
For detailed information check out the neorv32-verilog repository at https://github.com/stnolting/neorv32-verilog.
|
21. Eclipse IDE
Eclipse (https://www.eclipse.org/) is an interactive development environment that can be used to develop, debug and profile application code for the NEORV32 RISC-V Processor. This chapter shows how to import the provided example setup from the NEORV32 project repository. Additionally, all the required steps to create a compatible project from scratch are illustrated in this chapter.
This is a Makefile-Based Project!
Note that the provided Eclipse project as well as the setup tutorial in this section implement a makefile-based project.
Hence, the makefile in the example folder (that includes the main NEORV32 makefile) is used for building the application
instead of the Eclipse-managed build. Therefore, all compiler options, include folder, source files, etc. have to be
defined within the project’s makefile.
|
21.1. Eclipse Prerequisites
The following tools are required:
-
Eclipse IDE (Eclipse IDE for Embedded C/C++ Developers): https://www.eclipse.org/downloads/
-
Precompiled RISC-V GCC toolchain: e.g. https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
-
Precompiled OpenOCD binaries: e.g. https://github.com/xpack-dev-tools/openocd-xpack
-
Build tools like make: e.g. https://github.com/xpack-dev-tools/windows-build-tools-xpack
XPack Windows Build Tools
The NEORV32 makefile relies on the basename command which is not part of the default XPack
Windows Build Tools. However, you can just open the bin folder, copy busybox.exe and rename
that copy to basename.exe .
|
21.2. Import The Provided Eclipse Example Project
A pre-configured Eclipse project is available in neorv32/sw/example/eclipse
.
To import it:
-
Open Eclipse.
-
Click on File > Import, expand General and select Projects from Folder or Archive.
-
Click Next.
-
Click on Directory and select the provided example project folder (see directory above).
-
Click Finish.
NEORV32 Folder and File Paths
The provided example project uses relative paths for including all the NEORV32-specific files and folders
(in the Eclipse configuration files). Note that these paths need to be adjusted when moving this example setup
to a different location (makefile, NEORV32 sources, etc.).
|
Executables Configuration
Make sure to adjust the binaries / installation folders of the RISC-V GCC toolchain
and OpenOCD according to your installation. See the following chapter for more information.
|
Makefile Adjustment
Make sure to adjust the variables inside the project’s makefile to match your processor
configuration (memory sizes, CPU ISA configuration, etc.).
|
21.3. Setup a new Eclipse Project from Scratch
This chapter shows all the steps required to create an Eclipse project for the NEORV32 entirely from scratch.
This is an early version! ;)
The provided Eclipse project as well as the tutorial from this chapter are in a very early stage.
This setup was build and tested on Windows.
Feel free to open a new issue or pull request to improve this setup.
|
21.3.1. Create a new Project
-
Select File > New > Project.
-
Expand C/C** and select **C project.
-
In the C++ Project wizard:
-
Enter a Project name.
-
Uncheck the box next to Use default location and specify a location using Browse where you want to create the project.
-
From the Project type list expand Makefile project and select Empty Project.
-
Select RISC-V Cross GCC from the Toolchain list on the right side.
-
Click Next.
-
Skip the next page using the default configuration by clicking Next.
-
-
In the GNU RISC-V Cross Toolchain wizard configure the Toolchain name and Toolchain path according to your RISC-V GCC installation.
-
Example:
Toolchain name: xPack GNU RISC-V Embedded GCC (riscv-none-elf-gcc)
-
Example:
Toolchain path: C:\Program Files (x86)\xpack-riscv-none-elf-gcc-13.2.0-2\bin
-
-
Click Finish.
If you need to reconfigure the RISC-V GCC binaries and/or paths:
-
right-click on the project in the left view, select Properties
-
expand MCU and select RISC-V Toolchain Paths
-
adjust the Toolchain folder and the Toolchain name if required
-
Click Apply.
21.3.2. Add Initial Files
Start a simple project by adding two initial files. Further files can be added later. Only the makefile is really relevant here.
-
Add a new file by right-clicking on the project and select New > File and enter
main.c
in the filename box. -
Add another new file by right-clicking on the project and select New > File and enter
makefile
in the filename -
Copy the makefile of an existing NEORV32 example program and paste it to the new (empty) makefile.
21.3.3. Add Build Targets (optional)
This step adds some of the targets of the NEORV32 makefile for easy access. This step is optional.
-
In the project explorer right-click on the project and select Build Target > Create….
-
Add “all” as Target name (keep all the default checked boxes).
-
Repeat these steps for all further targets that you wish to add (e..g
clean_all
,exe
,elf
).
Clean-All Target
Adding the clean_all target is highly recommended. Executing this target once after importing the project ensures
that there are no (incompatible) artifacts left from previous builds.
|
Available Target
See the NEORV32 data sheet for a list and description of all available makefile targets:
https://stnolting.github.io/neorv32/#_makefile_targets
|
21.4. Configure Build Tools
This step is only required if your system does not provide any build tools (like make
) by default.
-
In the project explorer right-click on the project and select Properties.
-
Expand MCU and click on Build Tools Path.
-
Configure the Build tools folder.
-
Example:
Build tools folder: C:/xpack/xpack-windows-build-tools-4.4.1-2/bin
-
-
Click Apply and Close.
21.5. Adjust Default Build Configuration (optional)
This will simplify the auto-build by replacing the default make all
command by make elf
. Thus, only
the required main.elf
file gets generated instead of all executable files (like HDL and memory image files).
-
In the project explorer right-click on the project and select Properties.
-
Select C/C++ Build and click on the Behavior Tab.
-
Update the default targets in the Workbench Build Behavior box:
-
Build on resource save:
elf
(only build the ELF file) -
Build (Incremental build):
elf
(only build the ELF file) -
Clean:
clean
(only remove project-local build artifacts)
-
-
Click Apply and Close.
21.5.1. Add NEORV32 Software Framework
-
In the project explorer right-click on the project and select Properties.
-
Expand C/C++ General, click on Paths and Symbols and highlight Assembly under Languages.
-
In the Include tab click Add…
-
Check the box in front of Add to all languages and click on File System… and select the NEORV32 library include folder (
path/to/neorv32/sw/lib/include
). -
Click OK.
-
-
In the Include tab click Add….
-
Check the box in front of Add to all languages and click on File System… and select the NEORV32 commons folder (
path/to/neorv32/sw/common
). -
Click OK.
-
-
Click on the Source Location tab and click Link Folder…*.
-
Check the box in front of Link to folder in the system and click the Browse button.
-
Select the source folder of the NEORV32 software framework (
path/to/neorv32/sw/lib/source
). -
Click OK.
-
-
Click Apply and Close.
21.5.2. Setup OpenOCD
-
In the project explorer right-click on the project and select Properties.
-
Expand MCU and select OpenOCD Path.
-
Configure the Executable and Folder according to your openOCD installation.
-
Example:
Executable: openocd.exe
-
Example:
Folder: C:\OpenOCD\bin
-
Click Apply and Close.
-
-
In the top bar of Eclipse click on the tiny arrow right next to the Debug bug icon and select Debug Configurations.
-
Double-click on GDB OpenOCD Debugging; several menu tabs will open on the right.
-
In the Main tab add
main.elf
to the C/C++ Application box. -
In the Debugger tab add the NEORV32 OpenOCD script with a
-f
in front of it- -
Example:
Config options: -f ../../openocd/openocd_neorv32.cfg
-
In the Startup tab uncheck he box in front of Initial Reset and add
monitor reset halt
to the box below. -
In the "Common" tab mark Shared file to store the run-configuration right in the project folder instead of the workspace(optional).
-
In the SVD Path tab add the NEORV32 SVD file (
path/to/neorv32/sw/svd/neorv32.svd
).
-
-
Click Apply and then Close.
Default Debug Configuration
When you start debugging the first time you might need to select the provided debug configuration:
GDB OpenOCD Debugging > eclipse_example Default
|
Debug Symbols
For debugging the ELF has to compiled to contain according debug symbols.
Debug symbols are enabled by the project’s local makefile: USER_FLAGS += -ggdb -gdwarf-3
(this configuration seems to work best for Eclipse - at least for me).
|
If you need to reconfigure OpenOCD binaries and/or paths:
-
right-click on the project in the left view, select Properties
-
expand MCU and select OpenOCD Path
-
adjust the Folder and the Executable name if required
-
Click Apply.
21.5.3. Setup Serial Terminal
A serial terminal can be added to Eclipse by installing it as a plugin. I recommend "TM Terminal" which is already installed in some Eclipse bundles.
Open a TM Terminal serial console:
-
Click on Window > Show View > Terminal to open the terminal.
-
A Terminal tab appears on the bottom. Click the tiny screen button on the right (or press Ctrl+Alt+Shift) to open the terminal configuration.
-
Select Serial Terminal in Choose Terminal and configure the settings according to the processor’s UART configuration.
Installing TM Terminal from the Eclipse market place:
-
Click on Help > Eclipse Marketplace….
-
Enter "TM Terminal" to the Find line and hit enter.
-
Select TM Terminal from the list and install it.
-
After installation restart Eclipse.
21.6. Eclipse Setup References
-
Eclipse help: https://help.eclipse.org/latest/index.jsp
-
Importing an existing project into Eclipse: https://help.eclipse.org/latest/index.jsp?topic=%2Forg.eclipse.cdt.doc.user%2Fgetting_started%2Fcdt_w_import.htm
-
Eclipse OpenOCD Plug-In: https://eclipse-embed-cdt.github.io/debug/openocd/
22. Legal
About
The NEORV32 RISC-V Processor
https://github.com/stnolting/neorv32
Stephan Nolting, M.Sc.
🇪🇺 European Union
stnolting@gmail.com
License
BSD 3-Clause License
Copyright (c) NEORV32 contributors. Copyright (c) 2020 - 2024, Stephan Nolting. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-
Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SPDX Identifier
SPDX-License-Identifier: BSD-3-Clause
|
Proprietary Notice
-
"GitHub" is a subsidiary of Microsoft Corporation.
-
"Vivado" and "Artix" are trademarks of AMD Inc.
-
"AXI", "AXI", "AXI4-Lite", "AXI4-Stream", "AHB", "AHB3" and "AHB3-Lite" are trademarks of Arm Holdings plc.
-
"ModelSim" is a trademark of Mentor Graphics – A Siemens Business.
-
"Quartus [Prime]" and "Cyclone" are trademarks of Intel Corporation.
-
"iCE40", "UltraPlus" and "Radiant" are trademarks of Lattice Semiconductor Corporation.
-
"GateMate" is a trademark of Cologne Chip AG.
-
"Windows" is a trademark of Microsoft Corporation.
-
"Tera Term" copyright by T. Teranishi.
-
"NeoPixel" is a trademark of Adafruit Industries.
-
"Segger Embedded Studio" and "J-Link" are trademarks of Segger Microcontroller Systems GmbH.
-
Images/figures made with Microsoft Power Point.
-
Timing diagrams made with WaveDrom Editor.
-
Documentation made with
asciidoctor
.
All further/unreferenced projects/products/brands belong to their according copyright holders. No copyright infringement intended.
Disclaimer
This project is released under the BSD 3-Clause license. NO COPYRIGHT INFRINGEMENT INTENDED. Other implied or used projects/sources might have different licensing – see their according documentation for more information.
Limitation of Liability for External Links
This document contains links to the websites of third parties ("external links"). As the content of these websites is not under our control, we cannot assume any liability for such external content. In all cases, the provider of information of the linked websites is liable for the content and accuracy of the information provided. At the point in time when the links were placed, no infringements of the law were recognizable to us. As soon as an infringement of the law becomes known to us, we will immediately remove the link in question.
Citing
This is an open-source project that is free of charge. Use this project in any way you like (as long as it complies to the permissive license). Please cite it appropriately. 👍 |
Contributors & Community 🤝
Please add as many contributors as possible to the author field.This project would not be where it is without them. |
DOI
This project provides a digital object identifier provided by zenodo:
|
Acknowledgments
A big shout-out to the community and all the contributors, who helped improving this project! This project would not be where it is without them. ❤️
RISC-V - instruction sets want to be free!
Continuous integration provided by GitHub Actions and powered by GHDL.