mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-24 22:27:21 -04:00
✨ added console options to configure/customize build-in bootloader
* updated according sections in data sheet and user guide
This commit is contained in:
parent
2f15bf655c
commit
16cfbb63a0
5 changed files with 1265 additions and 1219 deletions
|
@ -363,7 +363,6 @@ automatic boot sequence and to start the actual bootloader user interface consol
|
|||
BLDV: Mar 23 2021
|
||||
HWV: 0x01050208
|
||||
CLK: 0x05F5E100
|
||||
USER: 0x10000DE0
|
||||
MISA: 0x40901105
|
||||
ZEXT: 0x00000023
|
||||
PROC: 0x0EFF0037
|
||||
|
@ -598,65 +597,101 @@ The RISC-V ISA string (for _MARCH_) follows a certain _canonical_ structure:
|
|||
:sectnums:
|
||||
== Customizing the Internal Bootloader
|
||||
|
||||
You can either customized the default bootloader via provided configuration options or you can write
|
||||
a completely new bootloader that is specialized for your application.
|
||||
The NEORV32 bootloader provides several options to configure and customize it for a certain application setup.
|
||||
This configuration is done by passing _defines_ when compiling the bootloader. Of course you can also
|
||||
modify to bootloader source code to provide a setup that perfectly fits your needs.
|
||||
|
||||
[IMPORTANT]
|
||||
Keep in mind that the maximum size for the bootloader is limited to 32kB.
|
||||
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.
|
||||
|
||||
The most important user-defined configuration options of the default bootloader are available as C-language
|
||||
`#defines` right at the beginning of the bootloader source code (`sw/bootloader/bootloader.c`):
|
||||
[NOTE]
|
||||
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.
|
||||
|
||||
.Cut-out from the bootloader source code `bootloader.c`: configuration parameters
|
||||
[source,c]
|
||||
.Bootloader configuration parameters
|
||||
[cols="<2,^1,^2,<6"]
|
||||
[options="header", grid="rows"]
|
||||
|=======================
|
||||
| Parameter | Default | Legal values | Description
|
||||
4+^| Serial console interface
|
||||
| `UART_EN` | `1` | `0`, `1` | Set to `0` to disable UART0 (no serial console at all)
|
||||
| `UART_BAUD` | `19200` | _any_ | Baud rate of UART0
|
||||
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_PIN` | `0` | `0` ... `31` | `GPIO` output pin used for the high-active status LED
|
||||
4+^| Boot configuration
|
||||
| `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_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
|
||||
| `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_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
|
||||
|=======================
|
||||
|
||||
Each configuration parameter is implemented as C-language `define` that can be manually overridden (_redefined_) when
|
||||
invoking the bootloader's makefile. The according parameter and its new value has to be _appended_
|
||||
(using `+=`) to the makefile'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
|
||||
use the following command (_in_ the bootloader's source folder `sw/bootloader`):
|
||||
|
||||
.Example: customizing, re-compiling and re-installing the bootloader
|
||||
[source,console]
|
||||
----
|
||||
/** UART BAUD rate */
|
||||
#define BAUD_RATE (19200)
|
||||
/** Enable auto-boot sequence if != 0 */
|
||||
#define AUTOBOOT_EN (1)
|
||||
/** Time until the auto-boot sequence starts (in seconds) */
|
||||
#define AUTOBOOT_TIMEOUT 8
|
||||
/** Set to 0 to disable bootloader status LED */
|
||||
#define STATUS_LED_EN (1)
|
||||
/** SPI_DIRECT_BOOT_EN: Define/uncomment to enable SPI direct boot */
|
||||
//#define SPI_DIRECT_BOOT_EN
|
||||
/** Bootloader status LED at GPIO output port */
|
||||
#define STATUS_LED (0)
|
||||
/** SPI flash boot image base address (warning! address might wrap-around!) */
|
||||
#define SPI_FLASH_BOOT_ADR (0x00800000)
|
||||
/** SPI flash chip select line at spi_csn_o */
|
||||
#define SPI_FLASH_CS (0)
|
||||
/** Default SPI flash clock prescaler */
|
||||
#define SPI_FLASH_CLK_PRSC (CLK_PRSC_8)
|
||||
/** SPI flash sector size in bytes (default = 64kb) */
|
||||
#define SPI_FLASH_SECTOR_SIZE (64*1024)
|
||||
/** ASCII char to start fast executable upload process */
|
||||
#define FAST_UPLOAD_CMD '#'
|
||||
$ make USER_FLAGS+=-DUART_BAUD=57600 USER_FLAGS+=-DSTATUS_LED_PIN=20 clean_all bootloader
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
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`).
|
||||
|
||||
:sectnums:
|
||||
=== Re-Compiling and Re-Installing the Bootloader
|
||||
=== Bootloader Boot Configuration
|
||||
|
||||
Whenever you have modified the bootloader's C sources you need to recompile and re-install it and
|
||||
re-synthesize your design afterwards.
|
||||
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
|
||||
reducing boot ROM implementation costs.
|
||||
|
||||
[start=1]
|
||||
.Compile and install the bootloader using the explicit `bootloader` makefile target.
|
||||
[source,bash]
|
||||
----
|
||||
neorv32/sw/bootloader$ make clean_all bootloader
|
||||
----
|
||||
:sectnums!:
|
||||
==== Default Boot Configuration
|
||||
|
||||
.Advanced
|
||||
[NOTE]
|
||||
You can also use the `bootloader` makefile target for any "normal" application. This will install that application
|
||||
directly to the processor's internal boot ROM.
|
||||
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
|
||||
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
|
||||
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
|
||||
(after `AUTO_BOOT_TIMEOUT`) while still providing the option to re-program SPI flash at any time
|
||||
via the UART interface.
|
||||
|
||||
:sectnums!:
|
||||
==== `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
|
||||
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`.
|
||||
|
||||
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`).
|
||||
|
||||
:sectnums!:
|
||||
==== `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.
|
||||
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>>
|
||||
for more information on how to use the on-chip debugger to upload and run executables.
|
||||
|
||||
[NOTE]
|
||||
The bootloader is intended to work regardless of the actual NEORV32 hardware configuration –
|
||||
especially when it comes to CPU ISA extensions. Hence, the bootloader should be compiled using the
|
||||
minimal `rv32i` ISA only.
|
||||
All bootloader boot configuration support uploading new executables via the on-chip debugger.
|
||||
|
||||
[WARNING]
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
@ -667,11 +702,34 @@ minimal `rv32i` ISA only.
|
|||
|
||||
The default processor-internal NEORV32 bootloader supports automatic booting from an external SPI flash.
|
||||
This guide shows how to write an executable to the SPI flash via the bootloader so it can be automatically
|
||||
fetched and executed after processor reset.
|
||||
fetched and executed after processor reset. For example, you can use a section of the FPGA bitstream configuration
|
||||
memory to store an application executable.
|
||||
|
||||
[TIP]
|
||||
The SPI flash requirements are shown in section
|
||||
https://stnolting.github.io/neorv32/#_external_spi_flash_for_booting[External SPI Flash for Booting] of the datasheet.
|
||||
[NOTE]
|
||||
This section assumes the _default_ configuration of the NEORV32 bootloader.
|
||||
See section <<_customizing_the_internal_bootloader>> on how to customize the bootloader and its setting
|
||||
(for example the SPI chip-select port, the SPI clock speed or the flash base address for storing the executable).
|
||||
|
||||
|
||||
:sectnums:
|
||||
=== SPI 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.
|
||||
The SPI flash has to support single-byte read and write, 24-bit addresses and at least the following standard commands:
|
||||
|
||||
* READ `0x03`
|
||||
* READ STATUS `0x05`
|
||||
* WRITE ENABLE `0x06`
|
||||
* PAGE PROGRAM `0x02`
|
||||
* SECTOR ERASE `0xD8`
|
||||
* READ ID `0x9E`
|
||||
|
||||
Compatible (FGPA configuration) SPI flash memories are for example the "Winbond W25Q64FV2 or the "Micron N25Q032A".
|
||||
|
||||
|
||||
:sectnums:
|
||||
=== Programming an Executable
|
||||
|
||||
[start=1]
|
||||
. At first, reset the NEORV32 processor and wait until the bootloader start screen appears in your terminal program.
|
||||
|
@ -711,7 +769,7 @@ to specify the base address of the executable inside the SPI flash.
|
|||
CMD:> u
|
||||
Awaiting neorv32_exe.bin... OK
|
||||
CMD:> p
|
||||
Write 0x000013FC bytes to SPI flash @ 0x00800000? (y/n) y
|
||||
Write 0x000013FC bytes to SPI flash @ 0x08000000? (y/n) y
|
||||
Flashing... OK
|
||||
CMD:>
|
||||
----
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue