224 lines
11 KiB
Plaintext
224 lines
11 KiB
Plaintext
:sectnums:
|
||
=== Bootloader
|
||
|
||
.Pre-Built Bootloader Image
|
||
[IMPORTANT]
|
||
This section refers to the **default** NEORV32 bootloader. A pre-compiled memory image for the processor-internal
|
||
<<_bootloader_rom_bootrom>> is available in the project's +rtl+ folder: `rtl/core/neorv32_bootloader_image.vhd`.
|
||
This image is automatically inserted into the boot ROM when synthesizing the processor with the bootloader being
|
||
enabled. **Note that the default bootloader image was compiled for a minimal `rv32i` + priv. ISA!**
|
||
|
||
The NEORV32 bootloader (`sw/bootloader/bootloader.c`) provides an optional built-in firmware that
|
||
allows to upload new application executables at _any time_ without the need to re-synthesize the FPGA's bitstream.
|
||
A UART connection is used to provide a simple text-based user interface that allows to upload executables.
|
||
|
||
Furthermore, the bootloader provides options to store an executable to a processor-external SPI flash.
|
||
An "auto boot" feature can optionally fetch this executable right after reset if there is no user interaction
|
||
via UART. This allows to build processor setups with _non-volatile application storage_ while maintaining the option
|
||
to update the application software at any timer.
|
||
|
||
|
||
:sectnums:
|
||
==== Bootloader SoC/CPU Requirements
|
||
|
||
The bootloader requires certain CPU and SoC extensions and modules to be enabled in order to operate correctly.
|
||
|
||
[cols="^2,<8"]
|
||
[grid="none"]
|
||
|=======================
|
||
| **REQUIRED** | The bootloader is implemented only if the `INT_BOOTLOADER_EN` top generic is `true`. This will automatically select the CPU's <<_indirect_boot>> boot configuration.
|
||
| **REQUIRED** | The bootloader requires the privileged architecture CPU extension (<<_zicsr_isa_extension>>) to be enabled.
|
||
| **REQUIRED** | At least 512 bytes of data memory (processor-internal DMEM or processor-external DMEM) are required for the bootloader's stack and global variables.
|
||
| _RECOMMENDED_ | For user interaction via the <<_bootloader_console>> (like uploading executables) the primary UART (<<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>) is required.
|
||
| _RECOMMENDED_ | The default bootloader uses bit 0 of the <<_general_purpose_input_and_output_port_gpio>> output port to drive a high-active "heart beat" status LED.
|
||
| _RECOMMENDED_ | The <<_machine_system_timer_mtime>> is used to control blinking of the status LED and also to automatically trigger the <<_auto_boot_sequence>>.
|
||
| OPTIONAL | The SPI controller (<<_serial_peripheral_interface_controller_spi>>) is needed to store/load executable from external flash using the <<_auto_boot_sequence>>.
|
||
| OPTIONAL | The XIP controller (<<_execute_in_place_module_xip>>) is needed to boot/execute code directly from a pre-programmed SPI flash.
|
||
|=======================
|
||
|
||
|
||
:sectnums:
|
||
==== Bootloader Flash Requirements
|
||
|
||
The bootloader can access an SPI-compatible flash via the processor's top entity SPI port. By default, the flash
|
||
chip-select line is driven by `spi_csn_o(0)` and the SPI clock uses 1/8 of the processor's main clock as clock frequency.
|
||
The SPI flash has to support single-byte read and write operations, 24-bit addresses and at least the following standard commands:
|
||
|
||
* `0x02`: Program page (write byte)
|
||
* `0x03`: Read data (byte)
|
||
* `0x04`: Write disable (for volatile status register)
|
||
* `0x05`: Read (first) status register
|
||
* `0x06`: Write enable (for volatile status register)
|
||
* `0xAB`: Wake-up from sleep mode (optional)
|
||
* `0xD8`: Block erase (64kB)
|
||
|
||
.Custom Configuration
|
||
[TIP]
|
||
Most properties (like chip select line, flash address width, SPI clock frequency, ...) of the default bootloader can be reconfigured
|
||
without the need to change the source code. Custom configuration can be made using command line switches (defines) when recompiling
|
||
the bootloader. See the User Guide https://stnolting.github.io/neorv32/ug/#_customizing_the_internal_bootloader for more information.
|
||
|
||
|
||
:sectnums:
|
||
==== Bootloader Console
|
||
|
||
To interact with the bootloader, connect the primary UART (UART0) signals (`uart0_txd_o` and `uart0_rxd_o`) of the processor's top
|
||
entity via a serial port (-adapter) to your computer (hardware flow control is not used so the according interface signals can be
|
||
ignored), configure your terminal program using the following settings and perform a reset of the processor.
|
||
|
||
Terminal console settings (`19200-8-N-1`):
|
||
|
||
* 19200 Baud
|
||
* 8 data bits
|
||
* no parity bit
|
||
* 1 stop bit
|
||
* newline on `\r\n` (carriage return, newline)
|
||
* no transfer protocol / control flow protocol - just raw bytes
|
||
|
||
.Terminal Program
|
||
[IMPORTANT]
|
||
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 (e.g. XMODEM). Some terminal programs struggle with
|
||
transmitting files larger than 4kB (see https://github.com/stnolting/neorv32/pull/215). Try a different terminal program
|
||
if uploading of a binary does not work.
|
||
|
||
The bootloader uses the LSB of the top entity's `gpio_o` output port as high-active status LED. All other
|
||
output pins are set to low level and won't be altered. After reset, the status LED will start blinking at 2Hz and the
|
||
following intro screen shows up:
|
||
|
||
[source]
|
||
----
|
||
<< NEORV32 Bootloader >>
|
||
|
||
BLDV: Mar 7 2023
|
||
HWV: 0x01080107
|
||
CLK: 0x05f5e100
|
||
MISA: 0x40901106
|
||
XISA: 0xc0000fab
|
||
SOC: 0xffff402f
|
||
IMEM: 0x00008000
|
||
DMEM: 0x00002000
|
||
|
||
Autoboot in 8s. Press any key to abort.
|
||
----
|
||
|
||
The start-up screen gives some brief information about the bootloader and several system configuration parameters:
|
||
|
||
[cols="<2,<15"]
|
||
[grid="none"]
|
||
|=======================
|
||
| `BLDV` | Bootloader version (built date).
|
||
| `HWV` | Processor hardware version (the <<_mimpid>> CSR); in BCD format; example: `0x01040606` = v1.4.6.6).
|
||
| `CLK` | Processor clock speed in Hz (via the `CLK` register from the <<_system_configuration_information_memory_sysinfo>>.
|
||
| `MISA` | RISC-V CPU extensions (<<_misa>> CSR).
|
||
| `XISA` | NEORV32-specific CPU extensions (<<_mxisa>> CSR).
|
||
| `SOC` | Processor configuration (via the `SOC` register from the <<_system_configuration_information_memory_sysinfo>>.
|
||
| `IMEM` | Internal IMEM size in byte (via the `MEM` register from the <<_system_configuration_information_memory_sysinfo>>.
|
||
| `DMEM` | Internal DMEM size in byte (via the `MEM` register from the <<_system_configuration_information_memory_sysinfo>>.
|
||
|=======================
|
||
|
||
Now you have 8 seconds to press _any_ key. Otherwise, the bootloader starts the <<_auto_boot_sequence>>. When
|
||
you press any key within the 8 seconds, the actual bootloader user console starts:
|
||
|
||
[source]
|
||
----
|
||
<< NEORV32 Bootloader >>
|
||
|
||
BLDV: Mar 7 2023
|
||
HWV: 0x01080107
|
||
CLK: 0x05f5e100
|
||
MISA: 0x40901106
|
||
XISA: 0xc0000fab
|
||
SOC: 0xffff402f
|
||
IMEM: 0x00008000
|
||
DMEM: 0x00002000
|
||
|
||
Autoboot in 8s. Press any key to abort. <1>
|
||
Aborted.
|
||
|
||
Available CMDs:
|
||
h: Help
|
||
r: Restart
|
||
u: Upload
|
||
s: Store to flash
|
||
l: Load from flash
|
||
x: Boot from flash (XIP)
|
||
e: Execute
|
||
CMD:>
|
||
----
|
||
<1> Auto boot sequence aborted due to user console input.
|
||
|
||
The auto boot countdown is stopped and the bootloader's user console is ready to receive one of the following commands:
|
||
|
||
* `h`: Show the help text (again)
|
||
* `r`: Restart the bootloader and the auto-boot sequence
|
||
* `u`: Upload new program executable (`neorv32_exe.bin`) via UART into the instruction memory
|
||
* `s`: Store executable to SPI flash at `spi_csn_o(0)` (little-endian byte order)
|
||
* `l`: Load executable from SPI flash at `spi_csn_o(0)` (little-endian byte order)
|
||
* `x`: Boot program directly from flash via XIP (requires a pre-programmed image)
|
||
* `e`: Start the application, which is currently stored in the instruction memory (IMEM)
|
||
|
||
A new executable can be uploaded via UART by executing the `u` command. After that, the executable can be directly
|
||
executed via the `e` command. To store the recently uploaded executable to an attached SPI flash press `s`. To
|
||
directly load an executable from the SPI flash press `l`. The bootloader and the auto-boot sequence can be
|
||
manually restarted via the `r` command.
|
||
|
||
.Executable Upload
|
||
[IMPORTANT]
|
||
Make sure to upload the NEORV32 executable `neorv32_exe.bin`. Uploading any other file (like `main.bin`)
|
||
will cause an `ERR_EXE` bootloader error (see <<_bootloader_error_codes>>).
|
||
|
||
.Booting via XIP
|
||
[NOTE]
|
||
The bootloader allows to execute an application right from flash using the <<_execute_in_place_module_xip>> module.
|
||
This requires a pre-programmed flash. The bootloader's "store" option can **not** be used to program an XIP image.
|
||
|
||
.SPI Flash Power Down Mode
|
||
[NOTE]
|
||
The bootloader will issue a "wake-up" command prior to using the SPI flash to ensure it is not
|
||
in sleep mode / power-down mode (see https://github.com/stnolting/neorv32/pull/552).
|
||
|
||
.Default Configuration
|
||
[TIP]
|
||
More information regarding the default SPI, GPIO, XIP, etc. configuration can be found in the User Guide
|
||
section https://stnolting.github.io/neorv32/ug/#_customizing_the_internal_bootloader.
|
||
|
||
.SPI Flash Programming
|
||
[TIP]
|
||
For detailed information on using an SPI flash for application storage see User Guide section
|
||
https://stnolting.github.io/neorv32/ug/#_programming_an_external_spi_flash_via_the_bootloader[Programming an External SPI Flash via the Bootloader].
|
||
|
||
|
||
:sectnums:
|
||
==== Auto Boot Sequence
|
||
|
||
When you reset the NEORV32 processor, the bootloader waits 8 seconds for a UART console input before it
|
||
starts the automatic boot sequence. This sequence tries to fetch a valid boot image from the external SPI
|
||
flash, connected to SPI chip select `spi_csn_o(0)`. If a valid boot image is found that can be successfully
|
||
transferred into the instruction memory, it is automatically started. If no SPI flash is detected or if there
|
||
is no valid boot image found, and error code will be shown.
|
||
|
||
|
||
:sectnums:
|
||
==== Bootloader Error Codes
|
||
|
||
If something goes wrong during bootloader operation an error code and a short message is shown. In this case the processor
|
||
is halted, the bootloader status LED is permanently activated and the processor has to be reset manually.
|
||
|
||
[TIP]
|
||
In many cases the error source is just _temporary_ (like some HF spike during an UART upload). Just try again.
|
||
|
||
[cols="<2,<8"]
|
||
[grid="rows"]
|
||
|=======================
|
||
| **`ERR_EXE`** | If you try to transfer an invalid executable (via UART or from the external SPI flash), this error message shows up. There might be a transfer protocol configuration error in the terminal program or maybe just the wrong file was selected. Also, if no SPI flash was found during an auto-boot attempt, this message will be displayed.
|
||
| **`ERR_SIZE`** | Your program is way too big for the internal processor’s instructions memory. Increase the memory size or reduce your application code.
|
||
| **`ERR_CHKS`** | This indicates a checksum error. Something went wrong during the transfer of the program image (upload via UART or loading from the external SPI flash). If the error was caused by a UART upload, just try it again. When the error was generated during a flash access, the stored image might be corrupted.
|
||
| **`ERR_FLSH`** | This error occurs if the attached SPI flash cannot be accessed. Make sure you have the right type of flash and that it is properly connected to the NEORV32 SPI port using chip select #0.
|
||
| **`ERR_EXC`** | The bootloader encountered an unexpected exception during operation. This might be caused when it tries to access peripherals that were not implemented during synthesis. Example: executing commands `l` or `s` (SPI flash operations) without the SPI module being implemented.
|
||
|=======================
|
||
|
||
[TIP]
|
||
If an unexpected exception has been raised the bootloader prints hexadecimal debug information showing
|
||
the <<_mcause>>, <<_mepc>> and <<_mtval>> CSR values.
|