OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [docs/] [userguide/] [content.adoc] - Diff between revs 62 and 63

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 62 Rev 63
Let's Get It Started!
Let's Get It Started!
 
 
To make your NEORV32 project run, follow the guides from the upcoming sections. Follow these guides
This user guide uses the NEORV32 project _as is_ from the official `neorv32` repository.
step by step and in the presented order.
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.
 
 
 
[TIP]
 
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. Alternatively, have a look at the `setups` folder,
 
which provides more sophisticated example setups for various FPGAs/FPGA boards and toolchains.
 
 
 
 
:sectnums:
:sectnums:
== Software Toolchain Setup
== Software Toolchain Setup
To compile (and debug) executables for the NEORV32 a RISC-V toolchain is required.
To compile (and debug) executables for the NEORV32 a RISC-V toolchain is required.
There are two possibilities to get this:
There are two possibilities to get this:
 
 
1. Download and _build_ the official RISC-V GNU toolchain yourself
1. Download and _build_ the official RISC-V GNU toolchain yourself.
2. Download and install a prebuilt version of the toolchain; this might also done via the package manager / app store of your OS
2. Download and install a prebuilt version of the toolchain; this might also done via the package manager / app store of your OS
 
 
[TIP]
[NOTE]
The default toolchain prefix for this project is **`riscv32-unknown-elf-`**. Of course you can use any other RISC-V
The default toolchain prefix (`RISCV_PREFIX` variable) for this project is **`riscv32-unknown-elf-`**. Of course you can use any other RISC-V
toolchain (like `riscv64-unknown-elf-`) that is capable to emit code for a `rv32` architecture. Just change the _RISCV_PREFIX_ variable in the application
toolchain (like `riscv64-unknown-elf-`) that is capable to emit code for a `rv32` architecture. Just change `RISCV_PREFIX`
makefile(s) according to your needs or define this variable when invoking the makefile.
according to your needs.
 
 
[IMPORTANT]
 
Keep in mind that – for instance – a rv32imc toolchain only provides library code compiled with
 
compressed (_C_) and `mul`/`div` instructions (_M_)! Hence, this code cannot be executed (without
 
emulation) on an architecture without these extensions!
 
 
 
:sectnums:
:sectnums:
=== Building the Toolchain from Scratch
=== Building the Toolchain from Scratch
To build the toolchain by yourself you can follow the guide from the official https://github.com/riscv/riscv-gnu-toolchain GitHub page.
To build the toolchain by yourself you can follow the guide from the official https://github.com/riscv/riscv-gnu-toolchain GitHub page.
You need to make sure the generated toolchain fits the architecture of the NEORV32 core. To get a toolchain that even supports minimal
You need to make sure the generated toolchain fits the architecture of the NEORV32 core. To get a toolchain that even supports minimal
ISA extension configurations, it is recommend to compile for `rv32i` only. Please note that this minimal ISA also provides further ISA
ISA extension configurations, it is recommend to compile for `rv32i` only. Please note that this minimal ISA also provides further ISA
extensions like `m` or `c`. Of course you can use a `multilib` approach to generate
extensions like `m` or `c`. Of course you can use a `multilib` approach to generate
toolchains for several target ISAs.
toolchains for several target ISAs.
.Configuring GCC build for `rv32i` (minimal ISA)
.Configuring GCC build for `rv32i` (minimal ISA)
[source,bash]
[source,bash]
----
----
riscv-gnu-toolchain$ ./configure --prefix=/opt/riscv --with-arch=rv32i –-with-abi=ilp32
riscv-gnu-toolchain$ ./configure --prefix=/opt/riscv --with-arch=rv32i –-with-abi=ilp32
riscv-gnu-toolchain$ make
riscv-gnu-toolchain$ make
----
----
 
 
 
[IMPORTANT]
 
Keep in mind that – for instance – a toolchain build with `--with-arch=rv32imc` only provides library code compiled with
 
compressed (`C`) and `mul`/`div` instructions (`M`)! Hence, this code cannot be executed (without
 
emulation) on an architecture without these extensions!
 
 
 
 
:sectnums:
:sectnums:
=== Downloading and Installing a Prebuilt Toolchain
=== Downloading and Installing a Prebuilt Toolchain
Alternatively, you can download a prebuilt toolchain.
Alternatively, you can download a prebuilt toolchain.
:sectnums:
:sectnums:
==== Use The Toolchain I have Build
==== Use The Toolchain I have Build
I have compiled a GCC toolchain on a 64-bit x86 Ubuntu (Ubuntu on Windows, actually) and uploaded it to
I have compiled a GCC toolchain on a 64-bit x86 Ubuntu (Ubuntu on Windows, actually) and uploaded it to
GitHub. You can directly download the according toolchain archive as single _zip-file_ within a packed
GitHub. You can directly download the according toolchain archive as single _zip-file_ within a packed
release from https://github.com/stnolting/riscv-gcc-prebuilt.
release from https://github.com/stnolting/riscv-gcc-prebuilt.
Unpack the downloaded toolchain archive and copy the content to a location in your file system (e.g.
Unpack the downloaded toolchain archive and copy the content to a location in your file system (e.g.
`/opt/riscv`). More information about downloading and installing my prebuilt toolchains can be found in
`/opt/riscv`). More information about downloading and installing my prebuilt toolchains can be found in
the repository's README.
the repository's README.
:sectnums:
:sectnums:
==== Use a Third Party Toolchain
==== Use a Third Party Toolchain
Of course you can also use any other prebuilt version of the toolchain. There are a lot  RISC-V GCC packages out there -
Of course you can also use any other prebuilt version of the toolchain. There are a lot  RISC-V GCC packages out there -
even for Windows. On Linux system you might even be able to fetch a toolchain via your distribution's package manager.
even for Windows. On Linux system you might even be able to fetch a toolchain via your distribution's package manager.
[IMPORTANT]
[IMPORTANT]
Make sure the toolchain can (also) emit code for a `rv32i` architecture, uses the `ilp32` or `ilp32e` ABI and **was not build** using
Make sure the toolchain can (also) emit code for a `rv32i` architecture, uses the `ilp32` or `ilp32e` ABI and **was not build** using
CPU extensions that are not supported by the NEORV32 (like `D`).
CPU extensions that are not supported by the NEORV32 (like `D`).
:sectnums:
:sectnums:
=== Installation
=== Installation
Now you have the toolchain binaries. The last step is to add them to your `PATH` environment variable (if you have not
Now you have the toolchain binaries. The last step is to add them to your `PATH` environment variable (if you have not
already done so): make sure to add the _binaries_ folder (`bin`) of your toolchain.
already done so): make sure to add the _binaries_ folder (`bin`) of your toolchain.
[source,bash]
[source,bash]
----
----
$ export PATH:$PATH:/opt/riscv/bin
$ export PATH:$PATH:/opt/riscv/bin
----
----
You should add this command to your `.bashrc` (if you are using bash) to automatically add the RISC-V
You should add this command to your `.bashrc` (if you are using bash) to automatically add the RISC-V
toolchain at every console start.
toolchain at every console start.
:sectnums:
:sectnums:
=== Testing the Installation
=== Testing the Installation
To make sure everything works fine, navigate to an example project in the NEORV32 example folder and
To make sure everything works fine, navigate to an example project in the NEORV32 example folder and
execute the following command:
execute the following command:
[source,bash]
[source,bash]
----
----
neorv32/sw/example/blink_led$ make check
neorv32/sw/example/blink_led$ make check
----
----
This will test all the tools required for the generating NEORV32 executables.
This will test all the tools required for the generating NEORV32 executables.
Everything is working fine if `Toolchain check OK` appears at the end.
Everything is working fine if `Toolchain check OK` appears at the end.
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== General Hardware Setup
== General Hardware Setup
 
 
This guide will setup a NEORV32 project for FPGA implementation (or simulation only) _from scratch_
This guide shows the basics of setting up a NEORV32 project for FPGA implementation (or simulation only)
 
_from scratch_. It uses a _simplified_ test "SoC" setup of the processor to keeps things simple at the beginning.
 
This simple setup is intended for evaluation or as "hello world" project to check out the NEORV32
 
on _your_ FPGA board.
 
 
[TIP]
[TIP]
If you want to use a complete pre-defined setup to start with, check out the
If you want to use a more sophisticated pre-defined setup to start with, check out the
project's `setups` folder (https://github.com/stnolting/neorv32/tree/master/setups),
`setups` folder, which provides example setups for various FPGA, boards and toolchains.
which provides (script-based) demo setups for various FPGA boards and toolchains.
 
 
The NEORV32 project features two minimalistic pre-configured test setups in
 
https://github.com/stnolting/neorv32/blob/master/rtl/test_setups[`rtl/test_setups`].
 
Both test setups only implement very basic processor and CPU features.
 
The main difference between the two setups is the processor boot concept - so how to get a software executable
 
_into_ the processor:
 
 
 
* **`rtl/test_setups/neorv32_testsetup_approm.vhd`**: this setup does not require a connection via UART. The
 
software executable is "installed" into the bitstream to initialize a read-only memory. Use this setup
 
if your FPGA board does _not_ provide a UART interface.
 
* **`rtl/test_setups/neorv32_testsetup_bootloader.vhd`**: this setups uses the UART and the default NEORV32
 
bootloader to upload new software executables. Use this setup if your board _does_ provide a UART interface.
 
 
 
.NEORV32 "hello world" test setup (`rtl/test_setups/neorv32_testsetup_bootloader.vhd`)
 
image::neorv32_test_setup.png[align=center]
 
 
This tutorial uses a _simplified_ test setup of the processor
.External Clock Source
to keeps things simple at the beginning as this setup is intended as
[NOTE]
evaluation or "hello world" project to check out the NEORV32.
These test setups are intended to be directly used as **design top entity**. Of course you can also instantiate them
 
into another design unit. If your FPGA board only provides _very fast_ external clock sources (like on the FOMU board)
 
you might need to add clock management components (PLLs, DCMs, MMCMs, ...) to the test setup or to the according top entity
 
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. Make sure to _reference_ the
. Add all VHDL files from the project's `rtl/core` folder to your project.
files only – do not copy them.
 
. 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.
. The `rtl/core/neorv32_top.vhd` VHDL file is the top entity of the NEORV32 processor. If you
. The `rtl/core/neorv32_top.vhd` VHDL file is the top entity of the NEORV32 processor, which can be
already have a design, instantiate this unit into your design and proceed.
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).
 
 
[IMPORTANT]
[IMPORTANT]
Make sure to include the `neorv32` package into your design when instantiating the processor: add
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.
`library neorv32;` and `use neorv32.neorv32_package.all;` to your design unit.
[start=5]
[start=5]
. If you do not have a design yet and just want to check out the NEORV32 – no problem! This guide
. Add the pre-defined test setup of choice to the project, too, and select it as _top entity_.
uses a simplified top entity, that encapsulates the actual processor top entity: add the
. The entity of both test setups
`rtl/templates/processor/neorv32_ProcessorTop_Test.vhd` VHDL file to your project, too, and
provide a minimal set of configuration generics, that might have to be adapted to match your FPGA and board:
select it as _top entity_.
 
. This test setup provides a minimal test hardware setup:
 
 
 
.NEORV32 "hello world" test setup
 
image::neorv32_test_setup.png[align=center]
 
 
 
[start=7]
.Test setup entity - configuration generics
. It only implements some very basic processor and CPU features. Also, only the
 
minimum number of signals is propagated to the outer world.
 
. However, a minimal setup-specific configuration of the NEORV32 processor is required to make it run
 
on your FPGA board of choice. Only the absolutely required modifications will be made while
 
keeping the default configuration for the remaining configuration options:
 
 
 
.Cut-out of `neorv32_ProcessorTop_Test.vhd` showing the processor instance and its configuration
 
[source,vhdl]
[source,vhdl]
----
----
neorv32_top_inst: neorv32_top
  generic (
generic map (
    -- adapt these for your setup --
  -- General --
    CLOCK_FREQUENCY   : natural := 100000000; <1>
  CLOCK_FREQUENCY   => 100000000, -- in Hz # <1>
    MEM_INT_IMEM_SIZE : natural := 16*1024;   <2>
  INT_BOOTLOADER_EN => true,
    MEM_INT_DMEM_SIZE : natural := 8*1024     <3>
  ...
  );
  -- Internal instruction memory --
 
  MEM_INT_IMEM_EN   => true,
 
  MEM_INT_IMEM_SIZE => 16*1024, # <2>
 
  -- Internal data memory --
 
  MEM_INT_DMEM_EN   => true,
 
  MEM_INT_DMEM_SIZE => 8*1024, # <3>
 
  ...
 
----
----
<1> Clock frequency of `clk_i` signal in Hertz
<1> Clock frequency of `clk_i` signal in Hertz
<2> Default size of internal instruction memory: 16kB
<2> Default size of internal instruction memory: 16kB
<3> Default size of internal data memory: 8kB
<3> Default size of internal data memory: 8kB
 
 
[start=9]
[start=7]
. There is one generic that has to be set according to your FPGA board setup: the actual clock frequency
. If you feel like it – or if your FPGA does not provide sufficient resources – you can modify the
of the top's clock input signal (`clk_i`). Use the _CLOCK_FREQUENC_Y generic to specify your clock source's
_memory sizes_ (`MEM_INT_IMEM_SIZE` and `MEM_INT_DMEM_SIZE` – marked with notes "2" and "3"). But as mentioned
frequency in Hertz (Hz) (note "1").
above, let's keep things simple at first and use the standard configuration for now.
. If you feel like it – or if your FPGA does not provide many resources – you can modify the
. There is one generic that _has to be set according to your FPGA board_ setup: the actual clock frequency
**memory sizes** (_MEM_INT_IMEM_SIZE_ and _MEM_INT_DMEM_SIZE_ – marked with notes "2" and "3") or even
of the top's clock input signal (`clk_i`). Use the `CLOCK_FREQUENCY` generic to specify your clock source's
exclude certain ISA extensions and peripheral modules from implementation - but as mentioned above, let's keep things
frequency in Hertz (Hz).
simple at first and use the standard configuration for now.
 
 
 
[NOTE]
[NOTE]
If you have changed the default memory configuration (_MEM_INT_IMEM_SIZE_ and _MEM_INT_DMEM_SIZE_ generics)
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
keep those new sizes in mind – these values are required for setting
up the software framework in the next section <<_general_software_framework_setup>>.
up the software framework in the next section <<_general_software_framework_setup>>.
 
 
[start=11]
[start=9]
. Depending on your FPGA tool of choice, it is time to assign the signals of the test setup top entity to
. Depending on your FPGA tool of choice, it is time to 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:
the according pins of your FPGA board. All the signals can be found in the entity declaration of the
 
corresponding test setup:
 
 
.Entity signals of `neorv32_test_setup.vhd`
.Entity signals of `neorv32_testsetup_approm.vhd`
[source,vhdl]
[source,vhdl]
----
----
entity neorv32_test_setup is
 
  port (
  port (
    -- Global control --
    -- Global control --
    clk_i       : in std_ulogic := '0'; -- global clock, rising edge
    clk_i       : in  std_ulogic; -- global clock, rising edge
    rstn_i      : in std_ulogic := '0'; -- global reset, low-active, async
    rstn_i      : in  std_ulogic; -- global reset, low-active, async
 
    -- GPIO --
 
    gpio_o      : out std_ulogic_vector(7 downto 0) -- parallel output
 
  );
 
----
 
 
 
.Entity signals of `neorv32_testsetup_bootloader.vhd`
 
[source,vhdl]
 
----
 
  port (
 
    -- Global control --
 
    clk_i       : in  std_ulogic; -- global clock, rising edge
 
    rstn_i      : in  std_ulogic; -- global reset, low-active, async
    -- GPIO --
    -- GPIO --
    gpio_o      : out std_ulogic_vector(7 downto 0); -- parallel output
    gpio_o      : out std_ulogic_vector(7 downto 0); -- parallel output
    -- UART0 --
    -- UART0 --
    uart0_txd_o : out std_ulogic; -- UART0 send data
    uart0_txd_o : out std_ulogic; -- UART0 send data
    uart0_rxd_i : in std_ulogic := '0' -- UART0 receive data
    uart0_rxd_i : in  std_ulogic  -- UART0 receive data
);
);
end neorv32_test_setup;
 
----
----
 
 
[start=12]
.Signal Polarity
 
[NOTE]
 
If your FPGA board has inverse polarity for certain input/output you can add `not` gates. Example: The reset signal
 
`rstn_i` is low-active by default; the LEDs connected to `gpio_o` high-active by default.
 
You can do this in your board top if you instantiate the test setup,
 
or _inside_ the test setup if this is your top entity (low-active LEDs example: `gpio_o <= NOT con_gpio_o(7 downto 0);`).
 
 
 
[start=10]
. Attach the clock input `clk_i` to your clock source and connect the reset line `rstn_i` to a button of
. Attach the clock input `clk_i` to your clock source and connect the reset line `rstn_i` to a button of
your FPGA board. Check whether it is low-active or high-active – the reset signal of the processor is
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.
**low-active**, so maybe you need to invert the input signal.
. If possible, connected at least bit `0` of the GPIO output port `gpio_o` to a high-active LED (invert
. If possible, connected _at least_ bit `0` of the GPIO output port `gpio_o` to a LED (see "Signal Polarity" note above).
the signal when your LEDs are low-active). This LED will be used as status LED for the setup.
. Finally, if your are using the UART-based test setup (`neorv32_testsetup_bootloader.vhd`)
. Finally, if your FPGA board provides a serial host interface (USB-to-serial converter) interface,
connect the UART communication signals `uart0_txd_o` and `uart0_rxd_i` to the host interface (e.g. USB-UART converter).
connect the UART communication signals `uart0_txd_o` and `uart0_rxd_i`.
 
. Perform the project HDL compilation (synthesis, mapping, bitstream generation).
. Perform the project HDL compilation (synthesis, mapping, bitstream generation).
. Program the generated bitstream into your FPGA and press the button connected to the reset signal.
. Program the generated bitstream into your FPGA and press the button connected to the reset signal.
. Done! The assigned status LED should be flashing now for some sections before permanently lighting up.
. Done! The LED at `gpio_o(0)` should be flashing now.
 
 
 
[TIP]
 
After the GCC toolchain for compiling RISC-V source code is ready (chapter <<_general_software_framework_setup>>),
 
you can advance to one of these chapters to learn how to get a software executable into your processor setup:
 
* If you are using the `neorv32_testsetup_approm.vhd` setup: See section <<_installing_an_executable_directly_into_memory>>.
 
* If you are using the `neorv32_testsetup_bootloader.vhd` setup: See section <<_uploading_and_starting_of_a_binary_executable_image_via_uart>>.
 
 
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== General Software Framework Setup
== General Software Framework Setup
To allow executables to be _actually executed_ on the NEORV32 Processor the configuration of the software framework
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 enabled
has to be aware to the hardware configuration. This guide focuses on the memory configuration. To enabled
certain CPU ISA festures refer to the <<_enabling_risc_v_cpu_extensions>> section.
certain CPU ISA festures refer to the <<_enabling_risc_v_cpu_extensions>> section.
[TIP]
[TIP]
If you have **not** changed the _default_ memory configuration in section <<_general_hardware_setup>>
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 guide.
you are already done and you can skip the rest of this guide.
[start=1]
[start=1]
. Open the NEORV32 linker script `sw/common/neorv32.ld` with a text editor. Right at the
. Open the NEORV32 linker script `sw/common/neorv32.ld` with a text editor. Right at the
beginning of this script you will find the `MEMORY` configuration listing the different memory section:
beginning of this script you will find the `MEMORY` configuration listing the different memory section:
.Cut-out of the linker script `neorv32.ld`: `ram` memory section configuration
.Cut-out of the linker script `neorv32.ld`: `ram` memory section configuration
[source,c]
[source,c]
----
----
MEMORY
MEMORY
{
{
  ram  (rwx) : ORIGIN = 0x80000000, LENGTH = DEFINED(make_bootloader) ? 512 : 8*1024 # <1>
  ram  (rwx) : ORIGIN = 0x80000000, LENGTH = DEFINED(make_bootloader) ? 512 : 8*1024 # <1>
...
...
----
----
<1> Size of the data memory address space (right-most value) (internal/external DMEM); here 8kB
<1> Size of the data memory address space (right-most value) (internal/external DMEM); here 8kB
[start=2]
[start=2]
. We only need to change the `ram` section, which presents the available data address space.
. We only need to change the `ram` section, which presents the available data address space.
If you have changed the DMEM (_MEM_INT_DMEM_SIZE_ generic) size adapt the `LENGTH` parameter of the `ram`
If you have changed the DMEM (_MEM_INT_DMEM_SIZE_ generic) size adapt the `LENGTH` parameter of the `ram`
section (here: `8*1024`) so it is equal to your DMEM hardware configuration.
section (here: `8*1024`) so it is equal to your DMEM hardware configuration.
[IMPORTANT]
[IMPORTANT]
Make sure you only modify the _right-most_ value (here: 8*1024)! +
Make sure you only modify the _right-most_ value (here: 8*1024)! +
The "`512`" are not relevant for the application.
The "`512`" are not relevant for the application.
[start=3]
[start=3]
. Done! Save your changes and close the linker script.
. Done! Save your changes and close the linker script.
.Advanced: Section base address and size
.Advanced: Section base address and size
[IMPORTANT]
[IMPORTANT]
More information can be found in the datasheet section https://stnolting.github.io/neorv32/#_address_space[Address Space].
More information can be found in the datasheet section https://stnolting.github.io/neorv32/#_address_space[Address Space].
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Application Program Compilation
== Application Program Compilation
This guide shows how to compile an example C-code application into a NEORV32 executable that
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.
can be uploaded via the bootloader or the on-chip debugger.
[IMPORTANT]
[IMPORTANT]
If your FPGA board does not provide such an interface - don't worry!
If your FPGA board does not provide such an interface - don't worry!
Section <<_installing_an_executable_directly_into_memory>> shows how to
Section <<_installing_an_executable_directly_into_memory>> shows how to
run custom programs on your FPGA setup without having a UART.
run custom programs on your FPGA setup without having a UART.
[start=1]
[start=1]
. Open a terminal console and navigate to one of the project's example programs. For instance, navigate to the
. Open a terminal console and navigate to one of the project's example programs. For instance, navigate to the
simple `sw/example_blink_led` example program. This program uses the NEORV32 GPIO module to display
simple `sw/example_blink_led` example program. This program uses the NEORV32 GPIO module to display
an 8-bit counter on the lowest eight bit of the `gpio_o` output port.
an 8-bit counter on the lowest eight bit of the `gpio_o` output port.
. To compile the project and generate an executable simply execute:
. To compile the project and generate an executable simply execute:
[source,bash]
[source,bash]
----
----
neorv32/sw/example/blink_led$ make clean_all exe
neorv32/sw/example/blink_led$ make clean_all exe
----
----
[start=3]
[start=3]
. We are using the `clean_all` taret to make sure everything is re-build.
. We are using the `clean_all` taret to make sure everything is re-build.
. This will compile and link the application sources together with all the included libraries. At the end,
. This will compile and link the application sources together with all the included libraries. At the end,
your application is transformed into an ELF file (`main.elf`). The _NEORV32 image generator_ (in `sw/image_gen`)
your application is transformed into an ELF file (`main.elf`). The _NEORV32 image generator_ (in `sw/image_gen`)
takes this file and creates a final executable. The makefile will show the resulting memory utilization and
takes this file and creates a final executable. The makefile will show the resulting memory utilization and
the executable size:
the executable size:
[source,bash]
[source,bash]
----
----
neorv32/sw/example/blink_led$ make clean_all exe
neorv32/sw/example/blink_led$ make clean_all exe
Memory utilization:
Memory utilization:
   text    data     bss     dec     hex filename
   text    data     bss     dec     hex filename
   3176       0     120    3296     ce0 main.elf
   3176       0     120    3296     ce0 main.elf
Compiling ../../../sw/image_gen/image_gen
Compiling ../../../sw/image_gen/image_gen
Executable (neorv32_exe.bin) size in bytes:
Executable (neorv32_exe.bin) size in bytes:
3188
3188
----
----
[start=5]
[start=5]
. That's it. The `exe` target has created the actual executable `neorv32_exe.bin` in the current folder
. That's it. The `exe` target has created the actual executable `neorv32_exe.bin` in the current folder
that is ready to be uploaded to the processor.
that is ready to be uploaded to the processor.
[TIP]
[TIP]
The compilation process will also create a `main.asm` assembly listing file in the current folder, which
The compilation process will also create a `main.asm` assembly listing file in the current folder, which
shows the actual assembly code of the application.
shows the actual assembly code of the application.
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Uploading and Starting of a Binary Executable Image via UART
== Uploading and Starting of a Binary Executable Image via UART
Follow this guide to use the bootloader to upload an executable via UART.
Follow this guide to use the bootloader to upload an executable via UART.
[NOTE]
[NOTE]
This concept uses the default "Indirect Boot" scenario that uses the bootloader to upload new executables.
This concept uses the default "Indirect Boot" scenario that uses the bootloader to upload new executables.
See datasheet section https://stnolting.github.io/neorv32/#_indirect_boot[Indirect Boot] for more information.
See datasheet section https://stnolting.github.io/neorv32/#_indirect_boot[Indirect Boot] for more information.
[IMPORTANT]
[IMPORTANT]
If your FPGA board does not provide such an interface - don't worry!
If your FPGA board does not provide such an interface - don't worry!
Section <<_installing_an_executable_directly_into_memory>> shows how to
Section <<_installing_an_executable_directly_into_memory>> shows how to
run custom programs on your FPGA setup without having a UART.
run custom programs on your FPGA setup without having a UART.
[start=1]
[start=1]
. Connect the primary UART (UART0) interface of your FPGA board to a serial port of your host computer.
. 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 fore free
. Start a terminal program. In this tutorial, I am using TeraTerm for Windows. You can download it fore free
from https://ttssh2.osdn.jp/index.html.en
from https://ttssh2.osdn.jp/index.html.en
[NOTE]
[NOTE]
_Any_ terminal program that can connect to a serial port should work. However, make sure the program
_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.
can transfer data in _raw_ byte mode without any protocol overhead around it.
[start=3]
[start=3]
. Open a connection to the the serial port your UART is connected to. Configure the terminal setting according to the
. Open a connection to the the serial port your UART is connected to. Configure the terminal setting according to the
following parameters:
following parameters:
* 19200 Baud
* 19200 Baud
* 8 data bits
* 8 data bits
* 1 stop bit
* 1 stop bit
* no parity bits
* no parity bits
* _no_ transmission/flow control protocol
* _no_ transmission/flow control protocol
* receiver (host computer) newline on `\r\n` (carriage return & newline)
* receiver (host computer) newline on `\r\n` (carriage return & newline)
[start=4]
[start=4]
. Also make sure that single chars are send from your computer _without_ any consecutive "new line" or "carriage
. 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
return" commands (this is highly dependent on your terminal application of choice, TeraTerm only
sends the raw chars by default).
sends the raw chars by default).
. Press the NEORV32 reset button to restart the bootloader. The status LED starts blinking and the
. 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
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.
automatic boot sequence and to start the actual bootloader user interface console.
.Bootloader console; aborted auto-boot sequence
.Bootloader console; aborted auto-boot sequence
[source,bash]
[source,bash]
----
----
<< NEORV32 Bootloader >>
<< NEORV32 Bootloader >>
BLDV: Mar 23 2021
BLDV: Mar 23 2021
HWV:  0x01050208
HWV:  0x01050208
CLK:  0x05F5E100
CLK:  0x05F5E100
MISA: 0x40901105
MISA: 0x40901105
ZEXT: 0x00000023
ZEXT: 0x00000023
PROC: 0x0EFF0037
PROC: 0x0EFF0037
IMEM: 0x00004000 bytes @ 0x00000000
IMEM: 0x00004000 bytes @ 0x00000000
DMEM: 0x00002000 bytes @ 0x80000000
DMEM: 0x00002000 bytes @ 0x80000000
Autoboot in 8s. Press key to abort.
Autoboot in 8s. Press key to abort.
Aborted.
Aborted.
Available commands:
Available commands:
h: Help
h: Help
r: Restart
r: Restart
u: Upload
u: Upload
s: Store to flash
s: Store to flash
l: Load from flash
l: Load from flash
e: Execute
e: Execute
CMD:>
CMD:>
----
----
[start=6]
[start=6]
. Execute the "Upload" command by typing `u`. Now the bootloader is waiting for a binary executable to be send.
. Execute the "Upload" command by typing `u`. Now the bootloader is waiting for a binary executable to be send.
[source,bash]
[source,bash]
----
----
CMD:> u
CMD:> u
Awaiting neorv32_exe.bin...
Awaiting neorv32_exe.bin...
----
----
[start=7]
[start=7]
. Use the "send file" option of your terminal program to send a NEORV32 executable (`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).
. 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.
When using TeraTerm, select the "binary" option in the send file dialog.
. If everything went fine, OK will appear in your terminal:
. If everything went fine, OK will appear in your terminal:
[source,bash]
[source,bash]
----
----
CMD:> u
CMD:> u
Awaiting neorv32_exe.bin... OK
Awaiting neorv32_exe.bin... OK
----
----
[start=10]
[start=10]
. The executable is now in the instruction memory of the processor. To execute the program right
. The executable is now in the instruction memory of the processor. To execute the program right
now run the "Execute" command by typing `e`:
now run the "Execute" command by typing `e`:
[source,bash]
[source,bash]
----
----
CMD:> u
CMD:> u
Awaiting neorv32_exe.bin... OK
Awaiting neorv32_exe.bin... OK
CMD:> e
CMD:> e
Booting...
Booting...
Blinking LED demo program
Blinking LED demo program
----
----
[start=11]
[start=11]
. If everything went fine, you should see the LEDs blinking.
. If everything went fine, you should see the LEDs blinking.
[NOTE]
[NOTE]
The bootloader will print error codes if something went wrong.
The bootloader will print error codes if something went wrong.
See section https://stnolting.github.io/neorv32/#_bootloader[Bootloader] of the NEORV32 datasheet for more information.
See section https://stnolting.github.io/neorv32/#_bootloader[Bootloader] of the NEORV32 datasheet for more information.
[TIP]
[TIP]
See section <<_programming_an_external_spi_flash_via_the_bootloader>> to learn how to use an external SPI
See section <<_programming_an_external_spi_flash_via_the_bootloader>> to learn how to use an external SPI
flash for nonvolatile program storage.
flash for nonvolatile program storage.
[TIP]
[TIP]
Executables can also be uploaded via the **on-chip debugger**.
Executables can also be uploaded via the **on-chip debugger**.
See section <<_debugging_with_gdb>> for more information.
See section <<_debugging_with_gdb>> for more information.
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Installing an Executable Directly Into Memory
== 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
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.
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
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
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
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.
the application requires to re-program the FPGA via the bitstream.
[TIP]
[TIP]
See datasheet section https://stnolting.github.io/neorv32/#_direct_boot[Direct Boot] for more information.
See datasheet section https://stnolting.github.io/neorv32/#_direct_boot[Direct Boot] for more information.
Using the IMEM as ROM:
Using the IMEM as ROM:
* for this boot concept the bootloader is no longer required
* 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)
* 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
* make sure that the memory components (like block RAM) the IMEM is mapped to support an initialization via the bitstream
[start=1]
[start=1]
. At first, make sure your processor setup actually implements the internal IMEM: the `MEM_INT_IMEM_EN` generics has to be set to `true`:
. At first, make sure your processor setup actually implements the internal IMEM: the `MEM_INT_IMEM_EN` generics has to be set to `true`:
.Processor top entity configuration - enable internal IMEM
.Processor top entity configuration - enable internal IMEM
[source,vhdl]
[source,vhdl]
----
----
  -- Internal Instruction memory --
  -- Internal Instruction memory --
  MEM_INT_IMEM_EN => true, -- implement processor-internal instruction memory
  MEM_INT_IMEM_EN => true, -- implement processor-internal instruction memory
----
----
[start=2]
[start=2]
. For this setup we do not want the bootloader to be implemented at all. Disable implementation of the bootloader by setting the
. 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 to `false`. This will also modify the processor-internal IMEM so it is initialized with the executable during synthesis.
`INT_BOOTLOADER_EN` generic to `false`. This will also modify the processor-internal IMEM so it is initialized with the executable during synthesis.
.Processor top entity configuration - disable internal bootloader
.Processor top entity configuration - disable internal bootloader
[source,vhdl]
[source,vhdl]
----
----
  -- General --
  -- General --
  INT_BOOTLOADER_EN => false, -- boot configuration: false = boot from int/ext (I)MEM
  INT_BOOTLOADER_EN => false, -- boot configuration: false = boot from int/ext (I)MEM
----
----
[start=3]
[start=3]
. To generate an "initialization image" for the IMEM that contains the actual application, run the `install` target when compiling your application:
. To generate an "initialization image" for the IMEM that contains the actual application, run the `install` target when compiling your application:
[source,bash]
[source,bash]
----
----
neorv32/sw/example/blink_led$ make clean_all install
neorv32/sw/example/blink_led$ make clean_all install
Memory utilization:
Memory utilization:
   text    data     bss     dec     hex filename
   text    data     bss     dec     hex filename
   3176       0     120    3296     ce0 main.elf
   3176       0     120    3296     ce0 main.elf
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
----
----
[start=4]
[start=4]
. The `install` target has compiled all the application sources but instead of creating an executable (`neorv32_exe.bit`) that can be uploaded via the
. 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 image `core/neorv32_application_image.vhd`.
bootloader, it has created a VHDL memory initialization image `core/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.
. 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).
. 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.
. 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:
The synthesis tool / simulator will print asserts to inform about the (IMEM) memory / boot configuration:
[source]
[source]
----
----
NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM).
NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM).
NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (3176 bytes), pre-initialized with application.
NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (3176 bytes), pre-initialized with application.
----
----
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Setup of a New Application Program Project
== Setup of a New Application Program Project
[start=1]
[start=1]
. The easiest way of creating a _new_ software application project is to copy an _existing_ one. This will keep all
. 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/blink_led` to `sw/example/flux_capacitor`.
file dependencies. For example you can copy `sw/example/blink_led` to `sw/example/flux_capacitor`.
. If you want to place you application somewhere outside `sw/example` you need to adapt the application's makefile.
. 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 repo home
In the makefile you will find a variable that keeps the relative or absolute path to the NEORV32 repo home
folder. Just modify this variable according to your new project's home location:
folder. Just modify this variable according to your new project's home location:
[source,makefile]
[source,makefile]
----
----
# Relative or absolute path to the NEORV32 home folder (use default if not set by user)
# Relative or absolute path to the NEORV32 home folder (use default if not set by user)
NEORV32_HOME ?= ../../..
NEORV32_HOME ?= ../../..
----
----
[start=3]
[start=3]
. If your project contains additional source files outside of the project folder, you can add them to
. If your project contains additional source files outside of the project folder, you can add them to
the `APP_SRC` variable:
the `APP_SRC` variable:
[source,makefile]
[source,makefile]
----
----
# User's application sources (add additional files here)
# User's application sources (add additional files here)
APP_SRC = $(wildcard *.c) ../somewhere/some_file.c
APP_SRC = $(wildcard *.c) ../somewhere/some_file.c
----
----
[start=4]
[start=4]
. You also can add a folder containing your application's include files to the
. You also can add a folder containing your application's include files to the
`APP_INC` variable (do not forget the `-I` prefix):
`APP_INC` variable (do not forget the `-I` prefix):
[source,makefile]
[source,makefile]
----
----
# User's application include folders (don't forget the '-I' before each entry)
# User's application include folders (don't forget the '-I' before each entry)
APP_INC = -I . -I ../somewhere/include_stuff_folder
APP_INC = -I . -I ../somewhere/include_stuff_folder
----
----
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Enabling RISC-V CPU Extensions
== Enabling RISC-V CPU Extensions
Whenever you enable/disable a RISC-V CPU extensions via the according `CPU_EXTENSION_RISCV_x` generic, you need to
Whenever you enable/disable a RISC-V CPU extensions via the according `CPU_EXTENSION_RISCV_x` generic, you need to
adapt the toolchain configuration so the compiler can actually generate according code for it.
adapt the toolchain configuration so the compiler can actually generate according code for it.
To do so, open the makefile of your project (for example `sw/example/blink_led/makefile`) and scroll to the
To do so, open the makefile of your project (for example `sw/example/blink_led/makefile`) and scroll to the
"USER CONFIGURATION" section right at the beginning of the file. You need to modify the `MARCH` variable and eventually
"USER CONFIGURATION" section right at the beginning of the file. You need to modify the `MARCH` variable and eventually
the `MABI` variable according to your CPU hardware configuration.
the `MABI` variable according to your CPU hardware configuration.
[source,makefile]
[source,makefile]
----
----
# CPU architecture and ABI
# CPU architecture and ABI
MARCH = -march=rv32i # <1>
MARCH = -march=rv32i # <1>
MABI = -mabi=ilp32 # <2>
MABI = -mabi=ilp32 # <2>
----
----
<1> MARCH = Machine architecture ("ISA string")
<1> MARCH = Machine architecture ("ISA string")
<2> MABI = Machine binary interface
<2> MABI = Machine binary interface
For example, if you enable the RISC-V `C` extension (16-bit compressed instructions) via the `CPU_EXTENSION_RISCV_C`
For example, if you enable the RISC-V `C` extension (16-bit compressed instructions) via the `CPU_EXTENSION_RISCV_C`
generic (set `true`) you need to add the `c` extension also to the `MARCH` ISA string in order to make the compiler
generic (set `true`) you need to add the `c` extension also to the `MARCH` ISA string in order to make the compiler
emit compressed instructions.
emit compressed instructions.
.Privileged Architecture Extensions
.Privileged Architecture Extensions
[IMPORTANT]
[IMPORTANT]
Privileged architecture extensions like `Zicsr` or `Zifencei` are "used" _implicitly_ by the compiler. Hence, according
Privileged architecture extensions like `Zicsr` or `Zifencei` are "used" _implicitly_ by the compiler. Hence, according
instruction will only be generated when "encoded" via inline assembly or when linking according libraries. In this case,
instruction will only be generated when "encoded" via inline assembly or when linking according libraries. In this case,
these instruction will _always_ be emitted (even if the according extension is not specified in `MARCH`). +
these instruction will _always_ be emitted (even if the according extension is not specified in `MARCH`). +
**I recommend to _not_ specify any privileged architecture extensions in `MARCH`.**
**I recommend to _not_ specify any privileged architecture extensions in `MARCH`.**
[WARNING]
[WARNING]
ISA extension enabled in hardware can be a superset of the extensions enabled in software, but not the other way
ISA extension enabled in hardware can be a superset of the extensions enabled in software, but not the other way
around. For example generating compressed instructions for a CPU configuration that has the `c` extension disabled
around. For example generating compressed instructions for a CPU configuration that has the `c` extension disabled
will cause _illegal instruction exceptions_ at runtime.
will cause _illegal instruction exceptions_ at runtime.
You can also override the default `MARCH` and `MABI` configurations from the makefile when invoking the makefile:
You can also override the default `MARCH` and `MABI` configurations from the makefile when invoking the makefile:
[source,bash]
[source,bash]
----
----
$ make MARCH=-march=rv32ic clean_all all
$ make MARCH=-march=rv32ic clean_all all
----
----
[NOTE]
[NOTE]
The RISC-V ISA string for `MARCH` follows a certain _canonical_ structure:
The RISC-V ISA string for `MARCH` follows a certain _canonical_ structure:
`rev32[i/e][m][a][f][d][g][q][c][b][v][n]...` For example `rv32imac` is valid while `rv32icma` is not.
`rev32[i/e][m][a][f][d][g][q][c][b][v][n]...` For example `rv32imac` is valid while `rv32icma` is not.
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
 
== Application-Specific Processor Configuration
 
 
 
Due to the processor's configuration options, which are mainly defined via the top entity VHDL generics, the SoC
 
can be tailored 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.
 
 
 
[NOTE]
 
Please keep in mind that optimizing the design in one direction (like performance) will also effect other potential
 
optimization goals (like area and energy).
 
 
 
=== 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` and
 
`MEM_INT_DMEM_EN => true`, maximize `MEM_INT_IMEM_SIZE` and `MEM_INT_DMEM_SIZE`
 
* Increase the CPU's instruction prefetch buffer size: `CPU_IPB_ENTRIES`
 
* _To be continued..._
 
 
 
 
 
=== 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 controller `XIRQ_NUM_CH`).
 
* Reduce the FIFO sizes of implemented modules (e.g. `SLINK_TX_FIFO`).
 
* 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, constrain the CPU's counter sizes: `CPU_CNT_WIDTH` for `[m]instret[h]`
 
(number of instruction) and `[m]cycle[h]` (number of cycles) counters. You can even remove these counters
 
by setting `CPU_CNT_WIDTH => 0` if they are not used at all (note, this is not RISC-V compliant).
 
* Reduce the CPU's prefetch buffer size (`CPU_IPB_ENTRIES`).
 
* 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-scale
 
`M` extension.
 
* Disable CPU extension that are not explicitly used (`A`, `U`, `Zfinx`).
 
* _To be continued..._
 
 
 
=== 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.
 
 
 
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 (constrain CPU counter sizes: e.g. `CPU_CNT_WIDTH => 32` and `HPM_NUM_CNTS => 32`).
 
* 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 memory interface (`MEM_EXT_ASYNC_RX => false`).
 
* _To be continued..._
 
 
 
[NOTE]
 
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.
 
 
 
 
 
=== 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. Disable all processor modules that are not actually used (exclude them
 
from synthesis if the will be _never_ used; disable the module via it's control register if the module is not
 
_currently_ used). When is sleep mode, you can keep a timer module running (MTIME or the watch dog) to wake up
 
the CPU again. Since the wake up is triggered by _any_ interrupt, the external interrupt controller can also
 
be used to wake up the CPU again. By this, all timers (and all other modules) can be deactivated as well.
 
 
 
.Processor-internal clock generator shutdown
 
[TIP]
 
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.
 
 
 
 
 
 
 
 
 
// ####################################################################################################################
 
: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.
[IMPORTANT]
[IMPORTANT]
Each time the bootloader sources are modified, the bootloader has to be re-compiled (and re-installed to the
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.
bootloader ROM) and the processor has to be re-synthesized.
[NOTE]
[NOTE]
Keep in mind that the maximum size for the bootloader is limited to 32kB and should be compiled using the
Keep in mind that the maximum size for the bootloader is limited to 32kB and should be compiled using the
base ISA `rv32i` only to ensure it can work independently of the actual CPU configuration.
base ISA `rv32i` only to ensure it can work independently of the actual CPU configuration.
.Bootloader configuration parameters
.Bootloader configuration parameters
[cols="<2,^1,^2,<6"]
[cols="<2,^1,^2,<6"]
[options="header", grid="rows"]
[options="header", grid="rows"]
|=======================
|=======================
| Parameter | Default | Legal values | Description
| Parameter | Default | Legal values | Description
4+^| Serial console interface
4+^| Serial console interface
| `UART_EN`   | `1` | `0`, `1` | Set to `0` to disable UART0 (no serial console at all)
| `UART_EN`   | `1` | `0`, `1` | Set to `0` to disable UART0 (no serial console at all)
| `UART_BAUD` | `19200` | _any_ | Baud rate of UART0
| `UART_BAUD` | `19200` | _any_ | Baud rate of UART0
4+^| Status LED
4+^| Status LED
| `STATUS_LED_EN`  | `1` | `0`, `1` | Enable bootloader status led ("heart beat") at `GPIO` output port pin #`STATUS_LED_PIN` when `1`
| `STATUS_LED_EN`  | `1` | `0`, `1` | Enable bootloader status led ("heart beat") at `GPIO` output port pin #`STATUS_LED_PIN` when `1`
| `STATUS_LED_PIN` | `0` | `0` ... `31` | `GPIO` output pin used for the high-active status LED
| `STATUS_LED_PIN` | `0` | `0` ... `31` | `GPIO` output pin used for the high-active status LED
4+^| Boot configuration
4+^| Boot configuration
| `AUTO_BOOT_SPI_EN`  | `0` | `0`, `1` | Set `1` to enable immediate boot from external SPI flash
| `AUTO_BOOT_SPI_EN`  | `0` | `0`, `1` | Set `1` to enable immediate boot from external SPI flash
| `AUTO_BOOT_OCD_EN`  | `0` | `0`, `1` | Set `1` to enable boot via on-chip debugger (OCD)
| `AUTO_BOOT_OCD_EN`  | `0` | `0`, `1` | Set `1` to enable boot via on-chip debugger (OCD)
| `AUTO_BOOT_TIMEOUT` | `8` | _any_ | Time in seconds after the auto-boot sequence starts (if there is no UART input by user); set to 0 to disabled auto-boot sequence
| `AUTO_BOOT_TIMEOUT` | `8` | _any_ | Time in seconds after the auto-boot sequence starts (if there is no UART input by user); set to 0 to disabled auto-boot sequence
4+^| SPI configuration
4+^| SPI configuration
 
| `SPI_EN`                | `1` | `0`, `1` | Set `1` to enable the usage of the SPI module (including load/store executables from/to SPI flash options)
| `SPI_FLASH_CS`          | `0` | `0` ... `7` | SPI chip select output (`spi_csn_o`) for selecting flash
| `SPI_FLASH_CS`          | `0` | `0` ... `7` | SPI chip select output (`spi_csn_o`) for selecting flash
| `SPI_FLASH_SECTOR_SIZE` | `65536` | _any_ | SPI flash sector size in bytes
| `SPI_FLASH_SECTOR_SIZE` | `65536` | _any_ | SPI flash sector size in bytes
| `SPI_FLASH_CLK_PRSC`    | `CLK_PRSC_8`  | `CLK_PRSC_2` `CLK_PRSC_4` `CLK_PRSC_8` `CLK_PRSC_64` `CLK_PRSC_128` `CLK_PRSC_1024` `CLK_PRSC_2024` `CLK_PRSC_4096` | SPI clock pre-scaler (dividing main processor clock)
| `SPI_FLASH_CLK_PRSC`    | `CLK_PRSC_8`  | `CLK_PRSC_2` `CLK_PRSC_4` `CLK_PRSC_8` `CLK_PRSC_64` `CLK_PRSC_128` `CLK_PRSC_1024` `CLK_PRSC_2024` `CLK_PRSC_4096` | SPI clock pre-scaler (dividing main processor clock)
| `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's `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
[source,console]
[source,console]
----
----
$ make USER_FLAGS+=-DUART_BAUD=57600 USER_FLAGS+=-DSTATUS_LED_PIN=20 clean_all bootloader
$ make USER_FLAGS+=-DUART_BAUD=57600 USER_FLAGS+=-DSTATUS_LED_PIN=20 clean_all bootloader
----
----
[NOTE]
[NOTE]
The `clean_all` target ensure that all libraries are re-compiled. The `bootloader` target will automatically
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`).
compile and install the bootloader to the HDL boot ROM (updating `rtl/core/neorv32_bootloader_image.vhd`).
:sectnums:
:sectnums:
=== Bootloader Boot Configuration
=== Bootloader Boot Configuration
The bootloader provides several _boot configurations_ that define where the actual application's executable
The bootloader provides several _boot configurations_ that define where the actual application's executable
shall be fetched from. Note that the non-default boot configurations provide a smaller memory footprint
shall be fetched from. Note that the non-default boot configurations provide a smaller memory footprint
reducing boot ROM implementation costs.
reducing boot ROM implementation costs.
:sectnums!:
:sectnums!:
==== Default Boot Configuration
==== Default Boot Configuration
The _default_ bootloader configuration provides a UART-based user interface that allows to upload new executables
The _default_ bootloader configuration 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
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>>).
section <<_programming_an_external_spi_flash_via_the_bootloader>>).
This configuration also provides an _automatic boot sequence_ (auto-boot) which will start fetching an executable
This configuration also provides an _automatic boot sequence_ (auto-boot) which will start fetching an executable
from external SPI flash using the default SPI configuration. By this, the default bootloader configuration
from external SPI flash using the default SPI configuration. By this, the default bootloader configuration
provides a "non volatile program storage" mechanism that automatically boot from external SPI flash
provides a "non volatile program storage" mechanism that automatically boot from external SPI flash
(after `AUTO_BOOT_TIMEOUT`) while still providing the option to re-program SPI flash at any time
(after `AUTO_BOOT_TIMEOUT`) while still providing the option to re-program SPI flash at any time
via the UART interface.
via the UART interface.
:sectnums!:
:sectnums!:
==== `AUTO_BOOT_SPI_EN`
==== `AUTO_BOOT_SPI_EN`
The automatic boot from SPI flash (enabled when `AUTO_BOOT_SPI_EN` is `1`) will fetch an executable from an external
The automatic boot from SPI flash (enabled when `AUTO_BOOT_SPI_EN` is `1`) will fetch an executable from an external
SPI flash (using the according _SPI configuration_) right after reset. The bootloader will start fetching
SPI flash (using the according _SPI configuration_) right after reset. The bootloader will start fetching
the image at SPI flash base address `SPI_BOOT_BASE_ADDR`.
the image at SPI flash base address `SPI_BOOT_BASE_ADDR`.
Note that there is _no_ UART console to interact with the bootloader. However, this boot configuration will
Note that there is _no_ UART console to interact with the bootloader. However, this boot configuration will
output minimal status messages via UART (if `UART_EN` is `1`).
output minimal status messages via UART (if `UART_EN` is `1`).
:sectnums!:
:sectnums!:
==== `AUTO_BOOT_OCD_EN`
==== `AUTO_BOOT_OCD_EN`
If `AUTO_BOOT_OCD_EN` is `1` the bootloader is implemented as minimal "halt loop" to be used with the on-chip debugger.
If `AUTO_BOOT_OCD_EN` is `1` the bootloader is implemented as minimal "halt loop" to be used with the on-chip debugger.
After initializing the hardware, the CPU waits in this endless loop until the on-chip debugger takes control over
After initializing the hardware, the CPU waits in this endless loop until the on-chip debugger takes control over
the core (to upload and run the actual executable). See section <<_debugging_using_the_on_chip_debugger>>
the core (to upload and run the actual executable). See section <<_debugging_using_the_on_chip_debugger>>
for more information on how to use the on-chip debugger to upload and run executables.
for more information on how to use the on-chip debugger to upload and run executables.
[NOTE]
[NOTE]
All bootloader boot configuration support uploading new executables via the on-chip debugger.
All bootloader boot configuration support uploading new executables via the on-chip debugger.
[WARNING]
[WARNING]
Note that this boot configuration does not load any executable at all! Hence,
Note that this boot configuration does not load any executable at all! Hence,
this boot configuration is intended to be used with the on-chip debugger only.
this boot configuration is intended to be used with the on-chip debugger only.
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Programming an External SPI Flash via the Bootloader
== Programming an External SPI Flash via the Bootloader
The default processor-internal NEORV32 bootloader supports automatic booting from an external SPI flash.
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
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
fetched and executed after processor reset. For example, you can use a section of the FPGA bitstream configuration
memory to store an application executable.
memory to store an application executable.
[NOTE]
[NOTE]
This section assumes the _default_ configuration of the NEORV32 bootloader.
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
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).
(for example the SPI chip-select port, the SPI clock speed or the flash base address for storing the executable).
:sectnums:
:sectnums:
=== SPI Flash
=== SPI Flash
The bootloader can access an SPI compatible flash via the processor top entity's SPI port. By default, the flash
The bootloader can access an SPI compatible flash via the processor top entity's SPI port. By default, the flash
chip-select line is to `spi_csn_o(0)` and uses 1/8 of the processor's main clock as clock frequency.
chip-select line is to `spi_csn_o(0)` and uses 1/8 of the processor's main clock as clock frequency.
The SPI flash has to support single-byte read and write, 24-bit addresses and at least the following standard commands:
The SPI flash has to support single-byte read and write, 24-bit addresses and at least the following standard commands:
* READ `0x03`
* READ `0x03`
* READ STATUS `0x05`
* READ STATUS `0x05`
* WRITE ENABLE `0x06`
* WRITE ENABLE `0x06`
* PAGE PROGRAM `0x02`
* PAGE PROGRAM `0x02`
* SECTOR ERASE `0xD8`
* SECTOR ERASE `0xD8`
* READ ID `0x9E`
* READ ID `0x9E`
Compatible (FGPA configuration) SPI flash memories are for example the "Winbond W25Q64FV2 or the "Micron N25Q032A".
Compatible (FGPA configuration) SPI flash memories are for example the "Winbond W25Q64FV2 or the "Micron N25Q032A".
:sectnums:
:sectnums:
=== Programming an Executable
=== Programming an Executable
[start=1]
[start=1]
. At first, reset the NEORV32 processor and wait until the bootloader start screen appears in your terminal program.
. 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.
. 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:
. Press u to upload the executable that you want to store to the external flash:
[source]
[source]
----
----
CMD:> u
CMD:> u
Awaiting neorv32_exe.bin...
Awaiting neorv32_exe.bin...
----
----
[start=4]
[start=4]
. Send the binary in raw binary via your terminal program. When the upload is completed and "OK"
. Send the binary in raw binary via your terminal program. When the upload is completed and "OK"
appears, press `p` to trigger the programming of the flash (do not execute the image via the `e`
appears, press `p` to trigger the programming of the flash (do not execute the image via the `e`
command as this might corrupt the image):
command as this might corrupt the image):
[source]
[source]
----
----
CMD:> u
CMD:> u
Awaiting neorv32_exe.bin... OK
Awaiting neorv32_exe.bin... OK
CMD:> p
CMD:> p
Write 0x000013FC bytes to SPI flash @ 0x00800000? (y/n)
Write 0x000013FC bytes to SPI flash @ 0x00800000? (y/n)
----
----
[start=5]
[start=5]
. The bootloader shows the size of the executable and the base address inside the SPI flash where the
. 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 type `n` to
executable is going to be stored. A prompt appears: Type `y` to start the programming or type `n` to
abort.
abort.
[TIP]
[TIP]
Section <<_customizing_the_internal_bootloader>> show the according C-language `define` that can be modified
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.
to specify the base address of the executable inside the SPI flash.
[source]
[source]
----
----
CMD:> u
CMD:> u
Awaiting neorv32_exe.bin... OK
Awaiting neorv32_exe.bin... OK
CMD:> p
CMD:> p
Write 0x000013FC bytes to SPI flash @ 0x08000000? (y/n) y
Write 0x000013FC bytes to SPI flash @ 0x08000000? (y/n) y
Flashing... OK
Flashing... OK
CMD:>
CMD:>
----
----
[start=6]
[start=6]
. If "OK" appears in the terminal line, the programming process was successful. Now you can use the
. 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
auto boot sequence to automatically boot your application from the flash at system start-up without
any user interaction.
any user interaction.
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
: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` 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.
. Connect ALL the `ACLK` and `ARESETN` pins of all peripherals and interconnects to the processor's clock and reset
. Connect ALL the `ACLK` and `ARESETN` pins of all peripherals and interconnects to the processor's clock and reset
signals to have a _unified_ clock and reset domain (easier for a first setup).
signals to have a _unified_ clock and reset domain (easier for a first setup).
. Open the "Address Editor" tab and let Vivado assign the base-addresses for the AXI-peripherals (you can modify them
. Open the "Address Editor" tab and let Vivado assign the base-addresses for the AXI-peripherals (you can modify them
according to your needs).
according to your needs).
. For all FPGA-external signals (like UART signals) make all the connections you need "external"
. For all FPGA-external signals (like UART signals) make all the connections you need "external"
(right-click on the signal/pin -> "Make External").
(right-click on the signal/pin -> "Make External").
. Save everything, let VIVADO create a HDL-Wrapper for the block-design and choose this as your _Top Level Design_.
. Save everything, let VIVADO create a HDL-Wrapper for the block-design and choose this as your _Top Level Design_.
. Define your constraints and generate your bitstream.
. Define your constraints and generate your bitstream.
[NOTE]
[NOTE]
Guide provided by GitHub user https://github.com/AWenzel83[`AWenzel83`] from
Guide provided by GitHub user https://github.com/AWenzel83[`AWenzel83`] from
https://github.com/stnolting/neorv32/discussions/52#discussioncomment-819013
https://github.com/stnolting/neorv32/discussions/52#discussioncomment-819013
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Simulating the Processor
== Simulating the Processor
 
 
.WORK IN PROGRESS
 
[WARNING]
 
This Section Is Under Construction! +
 
 +
 
FIXME!
 
 
 
:sectnums:
:sectnums:
=== Testbench
=== Testbench
 
 
The NEORV32 project features a simple default testbench (`sim/neorv32_tb.simple.vhd`) that can be used to simulate
The NEORV32 project features a simple, plain-VHDL (no third-party libraries) default testbench (`sim/neorv32_tb.simple.vhd`)
and test the processor setup. This testbench features a 100MHz clock and enables all optional peripheral and
that can be used to simulate and test the processor setup. This testbench features a 100MHz clock and enables all optional
CPU extensions except for the `E` extension and the TRNG IO module (that CANNOT be simulated due to its
peripheral and CPU extensions except for the `E` extension and the TRNG IO module (that CANNOT be simulated due to its
combinatorial (looped) oscillator architecture).
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
to the processor's external bus/memory interface. These components are:
to the processor's external bus/memory interface. These components are:
* an external instruction memory (that also allows booting from it)
* an external instruction memory (that also allows booting from it)
* 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 (attributes: `r` = read, `w` = write, `e` = execute, `a` = atomic accesses possible, `8` = byte-accessible, `16` =
half-word-accessible, `32` = word-accessible).
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"]
|=======================
|=======================
| Base address | Size          | Attributes           | Description
| Base address | Size          | Attributes           | Description
| `0x00000000` | `imem_size_c` | `r/w/e,  a, 8/16/32` | external IMEM (initialized with application image)
| `0x00000000` | `imem_size_c` | `r/w/e,  a, 8/16/32` | external IMEM (initialized with application image)
| `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
|=======================
|=======================
 
 
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). Make sure to use the `all` target of the
 
makefile to install your application as VHDL image after compilation:
 
 
 
[source, bash]
 
----
 
sw/example/blink_led$ make clean_all all
 
----
 
 
 
.Simulation-Optimized CPU/Processors Modules
 
[NOTE]
[NOTE]
The `sim/rtl_modules` folder provides simulation-optimized versions of certain CPU/processor modules.
The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from
These alternatives can be used to replace the default CPU/processor HDL files to allow faster/easier/more
the `rtl/core/neorv32_application_image.vhd` image file).
efficient simulation. **These files are not intended for synthesis!**
 
 
 
**Simulation Console Output**
 
 
 
 
.UART output during simulation
 
[NOTE]
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 simulator 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
 
see section <<_faster_simulation_console_output>>.
 
 
: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)]).
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)]).
ASCII data send to UART0 will be immediately printed to the simulator console. Additionally, the
ASCII data send to UART0 will be immediately printed to the simulator console. Additionally, the
ASCII data is logged in a file (`neorv32.uart0.sim_mode.text.out`) in the simulator home folder. All
ASCII data is logged in a file (`neorv32.uart0.sim_mode.text.out`) in the simulator home folder. All
written 32-bit data is also dumped as 8-char hexadecimal value into a file
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.
(`neorv32.uart0.sim_mode.data.out`) also in the simulator home folder.
ASCII data send to UART1 will be immediately printed to the simulator console. Additionally, the
ASCII data send to UART1 will be immediately printed to the simulator console. Additionally, the
ASCII data is logged in a file (`neorv32.uart1.sim_mode.text.out`) in the simulator home folder. All
ASCII data is logged in a file (`neorv32.uart1.sim_mode.text.out`) in the simulator home folder. All
written 32-bit data is also dumped as 8-char hexadecimal value into a file
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.
(`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
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
"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
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):
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
----
----
 
 
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 provided define will change the default UART0/UART1 setup function in order to set the simulation
 
mode flag in the according UART's control register.
 
 
[NOTE]
[NOTE]
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 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` 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$ sh ghdl_sim.sh --stop-time=20ms
----
----
 
 
 
 
 
:sectnums:
 
=== In-Console Application Simulation
 
 
 
To directly compile and run a program in the console (using the default testbench and GHDL
 
as simulator) you can use the `sim` makefile target. Make sure to use the UART simulation mode
 
(`USER_FLAGS+=-DUART0_SIM_MODE` and/or `USER_FLAGS+=-DUART1_SIM_MODE`) to get
 
faster / direct-to-console UART output.
 
 
 
[source, bash]
 
----
 
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim
 
[...]
 
Blinking LED demo program
 
----
 
 
 
 
 
:sectnums:
 
=== Hello World!
 
 
 
To do a quick test of the NEORV32 make sure to have [GHDL](https://github.com/ghdl/ghdl) and a
 
[RISC-V gcc toolchain](https://github.com/stnolting/riscv-gcc-prebuilt) installed, 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]
 
The simulator will output some _sanity check_ notes (and warnings or even errors if something is ill-configured)
 
right at the beginning of the simulation to give a brief overview of the actual NEORV32 SoC and CPU configurations.
 
 
 
[source, bash]
 
----
 
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: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!
 
      |    ^~~~~~~
 
Memory utilization:
 
   text    data     bss     dec     hex filename
 
   4612       0     120    4732    127c main.elf
 
Compiling ../../../sw/image_gen/image_gen
 
Installing application image to ../../../rtl/core/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).
 
Using simulation runtime args: --stop-time=10ms
 
../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: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_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_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_dmem.vhd:89:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal DMEM (RAM, 8192 bytes).
 
../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: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_slink.vhd:161:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing 8 RX and 8 TX stream links.
 
 
 
                                                                                       ##
 
                                                                                       ##         ##   ##   ##
 
 ##     ##   #########   ########    ########   ##      ##   ########    ########      ##       ################
 
####    ##  ##          ##      ##  ##      ##  ##      ##  ##      ##  ##      ##     ##     ####            ####
 
## ##   ##  ##          ##      ##  ##      ##  ##      ##          ##         ##      ##       ##   ######   ##
 
##  ##  ##  #########   ##      ##  #########   ##      ##      #####        ##        ##     ####   ######   ####
 
##   ## ##  ##          ##      ##  ##    ##     ##    ##           ##     ##          ##       ##   ######   ##
 
##    ####  ##          ##      ##  ##     ##     ##  ##    ##      ##   ##            ##     ####            ####
 
##     ##    #########   ########   ##      ##      ##       ########   ##########     ##       ################
 
                                                                                       ##         ##   ##   ##
 
                                                                                       ##
 
Hello world! :)
 
----
 
 
 
 
 
:sectnums:
 
=== Advanced Simulation using VUNIT
 
 
 
.WORK IN PROGRESS
 
[WARNING]
 
This Section Is Under Construction! +
 
 +
 
FIXME!
 
 
 
The NEORV32 provides a more sophisticated simulation setup using https://vunit.github.io/[VUNIT].
 
The according VUNIT-based testbench is `sim/neorv32_tb.vhd`.
 
 
 
**WORK-IN-PROGRESS**
 
 
 
 
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Building the Documentation
== Building the Documentation
The documentation (datasheet + user guide) is written using `asciidoc`. The according source files
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`.
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
A makefiles in the project's `docs` directory is provided to build all of the documentation as HTML pages
or as PDF documents.
or as PDF documents.
[TIP]
[TIP]
Pre-rendered PDFs are available online as _nightly pre-releases_: https://github.com/stnolting/neorv32/releases.
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 https://stnolting.github.io/neorv32/[GitHub Pages].
The HTML-based documentation is also available online at the project's https://stnolting.github.io/neorv32/[GitHub Pages].
The makefile provides a help target to show all available build options and their according outputs.
The makefile provides a help target to show all available build options and their according outputs.
[source,bash]
[source,bash]
----
----
neorv32/docs$ make help
neorv32/docs$ make help
----
----
.Example: Generate HTML documentation (data sheet) using `asciidoctor`
.Example: Generate HTML documentation (data sheet) using `asciidoctor`
[source,bash]
[source,bash]
----
----
neorv32/docs$ make html
neorv32/docs$ make html
----
----
[TIP]
[TIP]
If you don't have `asciidoctor` / `asciidoctor-pdf` installed, you can still generate all the documentation using
If you don't have `asciidoctor` / `asciidoctor-pdf` installed, you can still generate all the documentation using
a _docker container_ via `make container`.
a _docker container_ via `make container`.
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== FreeRTOS Support
== FreeRTOS Support
A NEORV32-specific port and a simple demo for FreeRTOS (https://github.com/FreeRTOS/FreeRTOS) are
A NEORV32-specific port and a simple demo for FreeRTOS (https://github.com/FreeRTOS/FreeRTOS) are
available in the `sw/example/demo_freeRTOS` folder. See the according documentation (`sw/example/demo_freeRTOS/README.md`)
available in the `sw/example/demo_freeRTOS` folder. See the according documentation (`sw/example/demo_freeRTOS/README.md`)
for more information.
for more information.
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== RISC-V Architecture Test Framework
== RISC-V Architecture Test Framework
The NEORV32 Processor passes the according tests provided by the official RISC-V Architecture Test Suite
The NEORV32 Processor passes the according tests provided by the official RISC-V Architecture Test Suite
(V2.0+), which is available online at GitHub: https://github.com/riscv/riscv-arch-test
(V2.0+), which is available online at GitHub: https://github.com/riscv/riscv-arch-test
All files required for executing the test framework on a simulated instance of the processor (including port
All files required for executing the test framework on a simulated instance of the processor (including port
files) are located in the `sw/isa-test` folder of the NEORV32 repository. The test framework is executed via the
files) are located in the `sw/isa-test` folder of the NEORV32 repository. The test framework is executed via the
`sim/run_riscv_arch_test.sh` script. Take a look at the provided `sim/README.md`
`sim/run_riscv_arch_test.sh` script. Take a look at the provided `sim/README.md`
(https://github.com/stnolting/neorv32/tree/master/sim[online at GitHub])
(https://github.com/stnolting/neorv32/tree/master/sim[online at GitHub])
file for more information on how to run the tests and how testing is conducted in detail.
file for more information on how to run the tests and how testing is conducted in detail.
<<<
<<<
// ####################################################################################################################
// ####################################################################################################################
:sectnums:
:sectnums:
== Debugging using the On-Chip Debugger
== Debugging using the On-Chip Debugger
The NEORV32 on-chip debugger allows _online_ in-system debugging via an external JTAG access port from a
The NEORV32 on-chip debugger 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
host machine. The general flow is independent of the host machine's operating system. However, this tutorial uses
Windows and Linux (Ubuntu on Windows) in parallel.
Windows and Linux (Ubuntu on Windows) in parallel.
[TIP]
[TIP]
See datasheet section https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd[On Chip Debugger (OCD)]
See datasheet section https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd[On Chip Debugger (OCD)]
for more information.
for more information.
[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).
: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).
Connect a JTAG adapter to the NEORV32 `jtag_*` interface signals. If you do not have a full-scale JTAG adapter, you can
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.
also use a FTDI-based adapter like the "FT2232H-56Q Mini Module", which is a simple and inexpensive FTDI breakout board.
.JTAG pin mapping
.JTAG pin mapping
[cols="^3,^2,^2"]
[cols="^3,^2,^2"]
[options="header",grid="rows"]
[options="header",grid="rows"]
|=======================
|=======================
| NEORV32 top signal | JTAG signal | FTDI port
| NEORV32 top signal | JTAG signal | FTDI port
| `jtag_tck_i`       | TCK         | D0
| `jtag_tck_i`       | TCK         | D0
| `jtag_tdi_i`       | TDI         | D1
| `jtag_tdi_i`       | TDI         | D1
| `jtag_tdo_o`       | TDO         | D2
| `jtag_tdo_o`       | TDO         | D2
| `jtag_tms_i`       | TMS         | D3
| `jtag_tms_i`       | TMS         | D3
| `jtag_trst_i`      | TRST        | D4
| `jtag_trst_i`      | TRST        | D4
|=======================
|=======================
[TIP]
[TIP]
The low-active JTAG _test reset_ (TRST) signals is _optional_ as a reset can also be triggered via the TAP controller.
The low-active JTAG _test reset_ (TRST) signals is _optional_ as a reset can also be triggered via the TAP controller.
If TRST is not used make sure to pull the signal _high_.
If TRST is not used make sure to pull the signal _high_.
:sectnums:
:sectnums:
=== OpenOCD
=== OpenOCD
The NEORV32 on-chip debugger can be accessed using the https://github.com/riscv/riscv-openocd[RISC-V port of OpenOCD].
The NEORV32 on-chip debugger can be accessed using the https://github.com/riscv/riscv-openocd[RISC-V port of OpenOCD].
Prebuilt binaries can be obtained - for example - from https://www.sifive.com/software[SiFive]. A pre-configured
Prebuilt binaries can be obtained - for example - from https://www.sifive.com/software[SiFive]. A pre-configured
OpenOCD configuration file (`sw/openocd/openocd_neorv32.cfg`) is available that allows easy access to the NEORV32 CPU.
OpenOCD configuration file (`sw/openocd/openocd_neorv32.cfg`) is available that allows easy access to the NEORV32 CPU.
[NOTE]
[NOTE]
You might need to adapt `ftdi_vid_pid`, `ftdi_channel` and `ftdi_layout_init` in `sw/openocd/openocd_neorv32.cfg`
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.
according to your interface chip and your operating system.
[TIP]
[TIP]
If you want to modify the JTAG clock speed (via `adapter speed` in `sw/openocd/openocd_neorv32.cfg`) make sure to meet
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 https://stnolting.github.io/neorv32/#_debug_module_dm[Documentation: Debug Transport Module (DTM)].
the clock requirements noted in https://stnolting.github.io/neorv32/#_debug_module_dm[Documentation: Debug Transport Module (DTM)].
To access the processor using OpenOCD, open a terminal and start OpenOCD with the pre-configured configuration file.
To access the processor using OpenOCD, open a terminal and start OpenOCD with the pre-configured configuration file.
.Connecting via OpenOCD (on Windows)
.Connecting via OpenOCD (on Windows)
[source, bash]
[source, bash]
--------------------------
--------------------------
N:\Projects\neorv32\sw\openocd>openocd -f openocd_neorv32.cfg
N:\Projects\neorv32\sw\openocd>openocd -f openocd_neorv32.cfg
Open On-Chip Debugger 0.11.0-rc1+dev (SiFive OpenOCD 0.10.0-2020.12.1)
Open On-Chip Debugger 0.11.0-rc1+dev (SiFive OpenOCD 0.10.0-2020.12.1)
Licensed under GNU GPL v2
Licensed under GNU GPL v2
For bug reports:
For bug reports:
        https://github.com/sifive/freedom-tools/issues
        https://github.com/sifive/freedom-tools/issues
1
1
Info : Listening on port 6666 for tcl connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 1000 kHz
Info : clock speed 1000 kHz
Info : JTAG tap: neorv32.cpu tap/device found: 0x0cafe001 (mfg: 0x000 (), part: 0xcafe, ver: 0x0)
Info : JTAG tap: neorv32.cpu tap/device found: 0x0cafe001 (mfg: 0x000 (), part: 0xcafe, ver: 0x0)
Info : datacount=1 progbufsize=2
Info : datacount=1 progbufsize=2
Info : Disabling abstract command reads from CSRs.
Info : Disabling abstract command reads from CSRs.
Info : Examined RISC-V core; found 1 harts
Info : Examined RISC-V core; found 1 harts
Info :  hart 0: XLEN=32, misa=0x40801105
Info :  hart 0: XLEN=32, misa=0x40801105
Info : starting gdb server for neorv32.cpu.0 on 3333
Info : starting gdb server for neorv32.cpu.0 on 3333
Info : Listening on port 3333 for gdb connections
Info : Listening on port 3333 for gdb connections
--------------------------
--------------------------
OpenOCD has successfully connected to the NEORV32 on-chip debugger and has examined the CPU (showing the content of
OpenOCD has successfully connected to the NEORV32 on-chip debugger and has examined the CPU (showing the content of
the `misa` CSRs). Now you can use `gdb` to connect via port 3333.
the `misa` CSRs). Now you can use `gdb` to connect via port 3333.
:sectnums:
:sectnums:
=== Debugging with GDB
=== Debugging with GDB
This guide uses the simple "blink example" from `sw/example/blink_led` as simplified test application to
This guide uses the simple "blink example" from `sw/example/blink_led` as simplified test application to
show the basics of in-system debugging.
show the basics of in-system debugging.
At first, the application needs to be compiled. We will use the minimal machine architecture configuration
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.
(`rv32i`) here to be independent of the actual processor/CPU configuration.
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 clean_all all
--------------------------
--------------------------
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>>).
.Starting GDB (on Linux (Ubuntu on Windows))
.Starting GDB (on Linux (Ubuntu on Windows))
[source, bash]
[source, bash]
--------------------------
--------------------------
.../neorv32/sw/example/blink_led$ riscv32-unknown-elf-gdb
.../neorv32/sw/example/blink_led$ riscv32-unknown-elf-gdb
GNU gdb (GDB) 10.1
GNU gdb (GDB) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv32-unknown-elf".
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv32-unknown-elf".
Type "show configuration" for configuration details.
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
For bug reporting instructions, please see:
.
.
Find the GDB manual and other documentation resources online at:
Find the GDB manual and other documentation resources online at:
    .
    .
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 local machine.
Set the ELF file we want to debug to the recently generated `main.elf` from the `blink_led` example.
Set the ELF file we want to debug to the recently generated `main.elf` from the `blink_led` example.
Finally, upload the program to the processor.
Finally, upload the program to the processor.
[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 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>
A program is being debugged already.
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Are you sure you want to change the file? (y or n) y
Reading symbols from main.elf...
Reading symbols from main.elf...
(gdb) load <4>
(gdb) load <4>
Loading section .text, size 0xd0c lma 0x0
Loading section .text, size 0xd0c lma 0x0
Loading section .rodata, size 0x39c lma 0xd0c
Loading section .rodata, size 0x39c lma 0xd0c
Start address 0x00000000, load size 4264
Start address 0x00000000, load size 4264
Transfer rate: 43 KB/sec, 2132 bytes/write.
Transfer rate: 43 KB/sec, 2132 bytes/write.
(gdb)
(gdb)
--------------------------
--------------------------
<1> Connect to OpenOCD
<1> Connect to OpenOCD
<2> The CPU was still executing code from the bootloader ROM - but that does not matter here
<2> The CPU was still executing code from the bootloader ROM - but that does not matter here
<3> Select `mail.elf` from the `blink_led` example
<3> Select `mail.elf` from the `blink_led` example
<4> Upload the executable
<4> Upload the executable
After the upload, GDB will make the processor jump to the beginning of the uploaded 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
(by default, this is the beginning of the instruction memory at `0x00000000`) skipping the bootloader
and halting the CPU right before executing the `blink_led` application.
and halting the CPU right before executing the `blink_led` application.
:sectnums:
:sectnums:
==== Breakpoint Example
==== Breakpoint Example
The following steps are just a small showcase that illustrate a simple debugging scheme.
The following steps are just a small showcase that illustrate a simple debugging scheme.
While compiling `blink_led`, an assembly listing file `main.asm` was generated.
While compiling `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.
Open this file with a text editor to check out what the CPU is going to do when resumed.
The `blink_led` example implements a simple counter on the 8 lowest GPIO output ports. The program uses
The `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`
"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
function. We will add a _breakpoint_ right at the end of this wait function so we can step through the iterations
of the counter.
of the counter.
.Cut-out from `main.asm` generated from the `blink_led` example
.Cut-out from `main.asm` generated from the `blink_led` example
[source, assembly]
[source, assembly]
--------------------------
--------------------------
00000688 <__neorv32_cpu_delay_ms_end>:
00000688 <__neorv32_cpu_delay_ms_end>:
 688:   01c12083                lw      ra,28(sp)
 688:   01c12083                lw      ra,28(sp)
 68c:   02010113                addi    sp,sp,32
 68c:   02010113                addi    sp,sp,32
 690:   00008067                ret
 690:   00008067                ret
--------------------------
--------------------------
The very last instruction of the `neorv32_cpu_delay_ms` function is `ret` (= return)
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.
at hexadecimal `690` in this example. Add this address as _breakpoint_ to GDB.
[NOTE]
[NOTE]
The address might be different if you use a different version of the software framework or
The address might be different if you use a different version of the software framework or
if different ISA options are configured.
if different ISA options are configured.
.Adding a GDB breakpoint
.Adding a GDB breakpoint
[source, bash]
[source, bash]
--------------------------
--------------------------
(gdb) b * 0x690
(gdb) b * 0x690
Breakpoint 1 at 0x690
Breakpoint 1 at 0x690
--------------------------
--------------------------
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]
--------------------------
--------------------------
Breakpoint 1 at 0x690
Breakpoint 1 at 0x690
(gdb) c
(gdb) c
Continuing.
Continuing.
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
(gdb) c
(gdb) c
Continuing.
Continuing.
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
(gdb) c
(gdb) c
Continuing.
Continuing.
--------------------------
--------------------------
include::../legal.adoc[]
include::../legal.adoc[]
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.