<<<
:sectnums:
=== Bootloader

The NEORV32 bootloader provides an optional built-in firmware that allows to upload new application firmware at
any time without the need to re-synthesize the FPGA's bitstream. The bootloader is automatically executed after
reset when enabled via the <<_boot_configuration>> `BOOT_MODE_SELECT` generic. The bootloader provides the
following key features:

* interactive user console via UART
* upload executable via UART
* load executable from SPI flash; store executable to SPI flash
* load executable from TWI flash; store executable to TWI flash (_option disabled by default_)
* load executable from SD card (_option disabled by default_)
* automatic boot sequence: automatically boot from TWI/SPI flash / SD card
* highly configurable to adapt to application requirements

.Pre-Built Bootloader Image
[NOTE]
This section refers to the **default** NEORV32 bootloader. The <<_bootloader_rom_bootrom>> image file
already contains the pre-compiled bootloader (`sw/bootloader/bootloader.c`) in its default configuration.

.Minimal Hardware Requirements
[NOTE]
The default bootloader image was compiled for a minimal `rv32e_zicsr_zifencei` ISA configuration and requires a
RAM (DMEM) size of at least 256 bytes. These constraints ensure that the bootloader can be executed on any
CPU/processor configuration. It is recommended to enable at least
<<_primary_universal_asynchronous_receiver_and_transmitter_uart0, UART0>>,
the <<_core_local_interruptor_clint, CLINT>> and the <<_general_purpose_input_and_output_port_gpio, GPIO>> controller.
See <<_customizing_the_internal_bootloader>> for more information.


:sectnums:
==== Bootloader Console

The default bootloader provides a serial console via UART0 for user interaction using the following terminal
settings:

* 19200 Baud, 8 data bits, no parity bit, 1 stop bit (`19200-8-N-1`)
* line breaks: carriage return + newline (`\r\n`)

.Terminal Program
[TIP]
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). Note that some terminal programs struggle
with transmitting files larger than 4kB (see https://github.com/stnolting/neorv32/pull/215).
**For Windows I can recommend TeraTerm (GUI) and SimplySerial (Window terminal). For Linux I can recommend `picocom`.**

By default the bootloader uses the LSB of the GPIO output port (`gpio_o(0)`) for a high-active status LED.
If the GPIO's direction control feature is implemented, only pin 0 is configured as output; the remaining pins
are configured as inputs. All other output pins are set to low. After reset, the status LED will start blinking
at 2Hz and the <<_auto_boot_sequence>> is started. This auto-boot sequence can be skipped within 8s by pressing any key.

.Default Bootloader Console
[source]
----
NEORV32 Bootloader
build: Jul 18 2026 <1>

Auto-boot in 8s. Press any key to abort. <2>
Aborted. <3>

Type 'h' for help.
CMD:> <4>
----
<1> Bootloader version (compile date).
<2> Start of auto-boot sequence.
<3> Auto-boot sequence aborted due to user console input.
<4> Command prompt.

To see a list of all available commands press `h` to see the help menu:

.Bootloader Help Menu
[source]
----
CMD:> h
Available CMDs:
h: Help                <1>
i: System info         <2>
r: Restart             <3>
u: Upload via UART     <4>
t: TWI flash - load    <5>
w: TWI flash - program <6>
l: SPI flash - load    <7>
s: SPI flash - program <8>
c: SD card - load      <9>
e: Start executable    <10>
x: Exit                <11>
CMD:>
----
<1> Show "Available CMDs" help text again.
<2> Show hardware configuration information.
<3> Restart bootloader and auto-boot sequence.
<4> Upload new executable (`neorv32_exe.bin`) via UART.
<5> Load executable from TWI flash (_this option is disabled by default_).
<6> Store executable to TWI flash (_this option is disabled by default_).
<7> Load executable from SPI flash.
<8> Program previously-uploaded executable to SPI flash.
<9> Load executable from SD card (_this option is disabled by default_).
<10> Start the (up)loaded executable.
<11> Raise a breakpoint exception: If a debugger is connected this will transfer control to the debugger.
If no debugger is connected this will print an exception error (<<_bootloader_error_codes>>)
shutting down the processor.

.Unavailable Commands
[NOTE]
Note that not all options are enabled in the default bootloader configuration in order to keep the bootloader
ROM size below 4kB. However, these options can be enabled in `config.h` (see <<_customizing_the_internal_bootloader>>).

Available commands can be executed by typing the according letter. For example, when executing the `i` command
the general system configuration is printed:

.System Configuration Information (Example)
[source]
----
CMD:> i
HWV:  0x01130207 <1>
CLK:  0x05F5E100 <2>
MISA: 0x40901104 <3>
XISA: 0x00000000_0x10000F93 <4>
SOC:  0x18BF80FF <5>
MISC: 0x59011010 <6>
CMD:>
----
<1> Processor hardware version in BCD format (<<_mimpid>> CSR).
<2> Processor clock speed in Hz (`CLK` register of <<_system_configuration_information_memory_sysinfo>>.
<3> RISC-V CPU extensions (<<_misa>> CSR).
<4> Additional RISC-V CPU (sub-)extensions (high & low words of <<_mxisah>> CSRs).
<5> Processor configuration (`SOC` register of <<_system_configuration_information_memory_sysinfo>>.
<6> Miscellaneous memory and SoC configuration (`MISC` register of <<_system_configuration_information_memory_sysinfo>>.


:sectnums:
==== Bootloader Image Format

In order to keep the bootloader as small as possible, complete ELF parsing was omitted. Therefore, a
compiled ELF cannot be loaded directly into the processor via the bootloader. Instead, the image generator
(see <<_executable_image_formats>>) is used to create a simplified executable file for the bootloader that
contains all the necessary information from the ELF and can be processed by the bootloader with little overhead.

After the executable has been compiled, the image generator extracts the relevant sections and combines them into
an image that corresponds to the <<_rom_layout>> of the processor configuration. This image is preceded by a simple
header containing information for transmission as well as for relocation and booting. The header consists of
four individual 32-bit words, which, like the actual image, are stored in low-endian byte order.

.Bootloader Executable Header
[source,c]
----
// bootloader executable header, little-Endian
typedef struct __attribute__((packed,aligned(4))) {
  uint32_t signature; // = 0x214F454E ("NEO!")
  uint32_t base_addr; // executable base address & entry point
  uint32_t size;      // size in bytes
  uint32_t checksum;  // sum-complement checksum
} exe_header_t;
----

The first word represents the signature (`0x214F454E`, "NEO!" as string representation). Based on this, the bootloader
can recognize a valid executable that also matches the bootloader version.

The next word defines the base address of the image. The bootloader stores the received image starting at this address.
This allows the bootloader to store different programs at different memory addresses, for example. The base address is
ultimately defined by the <<_linker_script>> using the `__neorv32_rom_base` symbol. This also corresponds to the entry
point of the program that is executed during bootup.

The next word is the size of the image in bytes. The size of the generated executable is always a multiple of 4.

The last word represents a checksum that ensures the transfer and integrity of the executable. To keep the bootloader
simple, a simple "sum complement" checksum is used here.

.Exemplary Header
[source,bash]
----
neorv32/sw/example/processor_check$ xxd -e -l 32 neorv32_exe.bin
00000000: 214f454e 00000000 00007078 2af7f9c6   NEO!....xp.....*
----


:sectnums:
==== Auto Boot Sequence

After reset, the bootloader waits 8 seconds for UART console input before it starts the automatic boot sequence.
Depending on the configuration (<<_customizing_the_internal_bootloader>>) the bootloader will try to fetch a valid
executable from different sources:

[start=1]
. **TWI boot**: Try to load an executable from TWI flash (default device ID is `0xA0`); if enabled.
. **SPI boot**: Try to load an executable from SPI flash (default SPI chip select line is `spi_csn_o(0)`); if enabled.
. **SD boot**: Try to load file `boot.bin` from SD flash (default SPI chip select line is `spi_csn_o(1)`); if enabled.
. **Direct boot**: Directly execute the code at a pre-configured address; if enabled.

If a valid boot image is loaded it will be immediately started. If no valid executable can be fetched the interactive
bootloader console is started.


:sectnums:
==== Uploading an Executable

[start=1]
. Connect the primary UART (UART0) interface of the processor to a serial port of your host computer.
. Start a serial terminal program.
. Open a connection to the the serial port your UART is connected to.
. Press the NEORV32 reset button to restart the bootloader. The status LED starts blinking and the
bootloader intro screen appears in the console. Press any key to abort the automatic boot sequence
and to start the actual bootloader user interface console.
. Execute the "Upload" command by typing `u`. Now the bootloader is waiting for a binary executable to be send:
`Awaiting neorv32_exe.bin...`
. Use the "send file" option of your terminal program to send a valid NEORV32 executable (`neorv32_exe.bin`).
Make sure the terminal sends the executable in raw binary mode.
. If everything went fine, `Awaiting neorv32_exe.bin... OK` is printed in the terminal.
. The executable is now in the instruction memory of the processor. To execute the program right
now run the "start executable" command by typing `e`.

.Uploading via `make upload` right from the console
[TIP]
The <<_application_makefile>> provides an "`upload`" target that allows you to transfer a compiled executable directly
to the bootloader via UART right from the console. This script handles the communication with the bootloader and is
based on a simple shell helper script `neorv32/sw/image_gen/uart_upload.sh`. Example:
`neorv32/sw/example/demo_blink_led$ make UART_TTY=/dev/ttyUSB1 upload`.
The serial interface device is defined by `UART_TTY` .

.UART Overflow Detection and Hardware Flow Control
[NOTE]
The bootloader **does not check for UART RX overflows** during transmissions. However, such an error during
transmission will most likely result in a checksum error, so the error will certainly be detected anyway.
For setups that use very high custom baud rates values and/or provide very high main memory latency (e.g.
external serial RAM), it is recommended to enable the UART RTS/CTS hardware flow control.
See <<_customizing_the_internal_bootloader>> for more information.

:sectnums:
==== Programming an SPI or TWI 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. If the TWI flash option is enabled, an according command for
programming the TWI flash is available.

[start=1]
. Reset the NEORV32 processor and wait until the bootloader start screen appears.
. Abort the auto boot sequence and start the user console by pressing any key.
. Press `u` to upload the executable that shall be programmed to the flash.
. Send the binary via the terminal program. When the upload is completed and "OK"
appears, press `s` to trigger the SPI flash programming:

[source]
----
CMD:> u
Awaiting neorv32_exe.bin... OK
CMD:> s
Write 0x00001614 bytes to SPI flash @0x00400000 (y/n)?
----

[start=5]
. The bootloader shows the size of the executable and the base address of the SPI flash where the
executable will be stored. A prompt appears: type `y` to start the programming or type `n` to abort.

[source]
----
CMD:> u
Awaiting neorv32_exe.bin... OK
CMD:> s
Write 0x00001614 bytes to SPI flash @0x00400000 (y/n)?
Flashing... OK
CMD:>
----

[start=6]
. Note that flash programming can take some time (depending on the TWI/SPI clock configuration in `config.h`).
If "OK" appears, the programming process was successful and the flash can be used for the auto-boot sequence.


:sectnums:
==== Booting from SD Card

The SD card is accessed in SPI mode. The card has to be formatted using the **FAT32** file system with
a sector size of at least 512 bytes. The executable has to be placed in the card's root directory.
By default the bootloader will fetch the `boot.bin` file, which is just a renamed copy of the
default `neorv32_exe.bin` file that is generated by the application compilation flow. The name of the
SD card's boot file can be changed to a custom file name (see <<_customizing_the_internal_bootloader>>),
but it has to use the 8.3 DOS format (max 8 character for the name plus dot plus 3 characters suffix).

SD-card and FAT32 support is provided by the great **Petit FatFs** library by Elm-Chan:
https://elm-chan.org/fsw/ff/00index_p.html


:sectnums:
==== Customizing the Internal Bootloader

The NEORV32 bootloader provides several options to configure it for a custom setup. It configured via set of
C-language `defines` in `sw/bootloader/config.h`. All defines provide default value that can be edited or
overridden by Makefile directives.

.Bootloader Configuration Parameters
[cols="<2,^1,^2,<6"]
[options="header", grid="rows"]
|=======================
| Parameter | Default | Legal values | Description
4+<| **Additional includes**
| -                       | - | - | Add further `#include` statements right at the beginning of the file.
4+<| **Serial console** - requires <<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>
| `UART_EN`               | `1`     | `0,1` | Set to `1` to enable the serial console.
| `UART_BAUD`             | `19200` | any   | Baud rate of UART0.
| `UART_HWFC`             | `0`     | `0,1` | Enable RTS/CTS hardware flow control. Recommended for very high baud rates / high memory latency.
4+<| **Status LED** - requires <<_general_purpose_input_and_output_port_gpio>>
| `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. Note that if the GPIO module's direction control feature is enabled only this pin is configured as output.
4+<| **Serial memory** - requires <<_serial_memory_controller_smc>>
| `SMC_EN`                | `0` | `0,1` | Enable initialization of <<_serial_memory_controller_smc>>.
| `SMC_SETUP_ARGS`        | ... | ...   | List of configuration arguments for SMC setup function (`neorv32_smc_setup(...)`).
4+<| **Auto-boot** - requires <<_core_local_interruptor_clint>>
| `AUTO_BOOT_EN`          | `1`  | `0,1` | Auto-boot enabled when `1`.
| `AUTO_BOOT_TIMEOUT`     | `8`  | any   | Timeout in seconds after which the auto-boot sequence starts (if there is no UART input by the user).
4+<| **Direct-boot**
| `DIRECT_BOOT_EN`        | `0`          | `0,1`  | Enable direct-boot option when `1`.
| `DIRECT_BOOT_ADDR`      | `0x00000000` | 32-bit | Direct boot address of executable; can be used to directly execute from pre-initialized memory.
4+<| **TWI flash** - requires <<_two_wire_serial_interface_controller_twi>>
| `TWI_FLASH_EN`          | `0`             | `0,1`     | Set to `1` to enable the TWI flash (boot) options.
| `TWI_FLASH_PROG_EN`     | `1`             | `0,1`     | Set to `1` to enable programming the TWI flash from the bootloader menu.
| `TWI_FLASH_CLK_PRSC`    | `CLK_PRSC_1024` | `CLK_PRSC_2` `CLK_PRSC_4` `CLK_PRSC_8` `CLK_PRSC_64` `CLK_PRSC_128` `CLK_PRSC_1024` `CLK_PRSC_2024` `CLK_PRSC_4096` | TWI clock prescaler.
| `TWI_FLASH_CLK_DIV`     | `0`             | `0..15`   | TWI clock divider value.
| `TWI_FLASH_ID`          | `0xA0`          | any       | 8-bit TWI device address (with R/W bit cleared).
| `TWI_FLASH_BASE_ADDR`   | `0x00000000`    | 32-bit    | Defines the TWI flash base address for the executable.
| `TWI_FLASH_ADDR_BYTES`  | `2`             | `1,2,3,4` | Number of TWI flash address bytes.
4+<| **SPI flash** - requires <<_serial_peripheral_interface_controller_spi>>
| `SPI_FLASH_EN`          | `1`           | `0,1`     | Set to `1` to enable the SPI flash (boot) options.
| `SPI_FLASH_PROG_EN`     | `1`           | `0,1`     | Set to `1` to enable programming the SPI flash from the bootloader menu.
| `SPI_FLASH_CS`          | `0`           | `0..7`    | SPI chip select line (port `spi_csn_o`) for selecting the SPI flash.
| `SPI_FLASH_CLK_PRSC`    | `CLK_PRSC_64` | `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 prescaler.
| `SPI_FLASH_CLK_DIV`     | `0`           | `0..15`   | SPI clock divider value.
| `SPI_FLASH_BASE_ADDR`   | `0x00400000`  | 32-bit    | Defines the SPI flash base address for the executable.
| `SPI_FLASH_ADDR_BYTES`  | `3`           | `1,2,3,4` | SPI flash address size in number of bytes.
| `SPI_FLASH_SECTOR_SIZE` | `16*1024`     | any       | Number of SPI flash address bytes.
4+<| **SPI SD card** - requires <<_serial_peripheral_interface_controller_spi>>
| `SPI_SDCARD_EN`         | `0`           | `0,1`          | Set to `1` to enable booting from SD card.
| `SPI_SDCARD_CS`         | `1`           | `0..7`         | SPI chip select line (port `spi_csn_o`) for selecting the SD card.
| `SPI_SDCARD_CLK_PRSC`   | `CLK_PRSC_64` | `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 prescaler.
| `SPI_SDCARD_CLK_DIV`    | `0`           | `0..15`        | SPI clock divider value.
| `SPI_SDCARD_FILE`       | `"boot.bin"`  | 8.3 DOS format | File name of the boot image. Has to be located in the root directory.
4+<| **Branding**
| `THEME_INTRO`           | `"NEORV32 Bootloader"` | any string | Intro text that is shown in the bootloader console.
| `THEME_EXE`             | `"neorv32_exe.bin"`    | any string | Name of executable that is shown in the upload menu.
4+<| **Custom Code**
| `USER_CODE_INIT`        | `(void)0` (_empty statement_) | any code | User-defined initialization code (wrapped in a macro) that is executed right after the bootloader's hardware initialization.
|=======================


:sectnums:
==== Bootloader Error Codes

[cols="<2,<8"]
[grid="rows"]
|=======================
| **`ERROR_DEVICE`**    | A device-accessing function returned an error code. Make sure that the device is properly
connected and that all required processor modules/interface are actually enabled (by the according <<_processor_top_entity_generics>>).
This error can also occur if there was an RX overflow on the UART (if overflow detection is enabled). In this case, either UART hardware
flow control should be enabled or the baud rate should be reduced; both adjustments require recompiling the bootloader.
| **`ERROR_SIGNATURE`** | The signature that indicates a valid NEORV32 executable of the accessed executable is incorrect.
This can be caused by a temporary transmission error or by an invalid or corrupted executable.
| **`ERROR_CHECKSUM`**  | The checksum of the loaded executable is incorrect. This can be caused by a temporary transmission
error or by an invalid or corrupted executable.
| **`ERROR_EXCEPTION`** | An unexpected exception has occurred. This can be caused by an invalid bootloader configuration (non-available
processor modules, memory layout, ...). For debugging purpose the error message will also display the content of the <<_mcause>>, <<_mepc>>
and <<_mtval>> CSRs. Example: `ERROR_EXCEPTION 0x00000003 0xffe00cb4 0x00000000`
|=======================
