Projet_SETI_RISC-V/neorv32/docs/datasheet/software_bootloader.adoc

211 lines
11 KiB
Text
Raw Normal View History

2023-03-06 14:48:14 +01:00
:sectnums:
=== Bootloader
[NOTE]
This section refers to the **default** bootloader from the repository. The bootloader can be customized
to target application-specific scenarios using pre-defined options (see User Guide section
https://stnolting.github.io/neorv32/ug/#_customizing_the_internal_bootloader[Customizing the Internal Bootloader]
) or it can be completely rewritten/replaced for custom purpose.
The NEORV32 bootloader (source code `sw/bootloader/bootloader.c`) provides an optional build-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_, which can still be updated at any time.
:sectnums:
==== Bootloader SoC/CPU Requirements
The bootloader relies on certain CPU and SoC extensions and modules to be enabled to allow full functionality.
[cols="<3,<12"]
[grid="none"]
|=======================
| **REQUIRED** | The bootloader is implemented only if the <<_int_bootloader_en>> is _true_ (default). This will automatically select the CPU's <<_indirect_boot>> boot configuration.
| **REQUIRED** | The bootloader requires the privileged architecture CPU extension (<<_zicsr_control_and_status_register_access_privileged_architecture>>) 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.
| _RECOMMENDED_ | For user interaction via UART (like uploading executables) the primary UART (<<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>) has to be implemented.
Without UART0 the auto-boot via SPI is still supported but the bootloader should be customized (see User Guide).
| _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 (for the auto boot feature).
| OPTIONAL | The XIP controller (<<_execute_in_place_module_xip>>) is needed to 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)
* `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 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
[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: Jul 11 2022
HWV: 0x01070307
CID: 0x00000000
CLK: 0x05f5e100
ISA: 0x40901104 + 0xc0000783
SOC: 0x7c5f400f
IMEM: 0x00004000 bytes @0x00000000
DMEM: 0x00002000 bytes @0x80000000
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).
| `CID` | Custom user-defined ID (via the `CUSTOM_ID` register from <<_system_configuration_information_memory_sysinfo>>; defined by the <<_custom_id>> generic).
| `CLK` | Processor clock speed in Hz (via the `CLK` register from <<_system_configuration_information_memory_sysinfo>>; defined by the <<_clock_frequency>> generic).
| `ISA` | CPU extensions (<<_misa>> CSR + <<_mxisa>> CSR).
| `SOC` | Processor configuration (via the `SOC` register from the <<_system_configuration_information_memory_sysinfo>>; mainly defined by the `IO_*` and `MEM_*` configuration generics).
| `IMEM` | IMEM memory base address and size in byte (via the `IMEM_SIZE` and `ISPACE_BASE` registers from the <<_system_configuration_information_memory_sysinfo>>; defined by the <<_mem_int_imem_size>> generic).
| `DMEM` | DMEM memory base address and size in byte (via the `DMEM_SIZE` and `DSPACE_BASE` registers from the <<_system_configuration_information_memory_sysinfo>>; defined by the <<_mem_int_dmem_size>> generic).
|=======================
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: Jul 11 2022
HWV: 0x01070307
CLK: 0x05f5e100
ISA: 0x40901104 + 0xc0000783
SOC: 0x7c5f400f
IMEM: 0x00004000 bytes @0x00000000
DMEM: 0x00002000 bytes @0x80000000
Autoboot in 8s. Press any key to abort.
Aborted. <1>
Available commands:
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.
.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.
.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 processors 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.