Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework bootloader's SPI flash access #321

Merged
merged 10 commits into from
May 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mimpid = 0x01040312 => 01.04.03.12 => Version 01.04.03.12 => v1.4.3.12

| Date (*dd.mm.yyyy*) | Version | Comment |
|:----------:|:-------:|:--------|
| 29.05.2022 | 1.7.1.10 | rework **bootloader's** "SPI flash presence detection"; added new option (`SPI_FLASH_ADDR_BYTES`) to customize the bootloader SPI flash address width (16-, 24- or 32-bit); [#321](https://github.com/stnolting/neorv32/pull/321) |
| 29.05.2022 | 1.7.1.9 | :bug: fixed bug in **CPU trap logic**: collision of synchronous and asynchronous exceptions; [#327](https://github.com/stnolting/neorv32/pull/327) |
| 19.05.2022 | 1.7.1.8 | :bug: fixed bug in **XIP** address conversion logic: sub-word read accesses (half-word, byte) returned wrong data; [#320](https://github.com/stnolting/neorv32/pull/320) |
| 17.05.2022 | 1.7.1.7 | :sparkles: add optional/configurable data FIFO to **TRNG**; new top generic `IO_TRNG_FIFO`; [#316](https://github.com/stnolting/neorv32/pull/316) |
Expand Down
98 changes: 61 additions & 37 deletions docs/datasheet/software_bootloader.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,65 @@

[NOTE]
This section refers to the **default** bootloader from the repository. The bootloader can be customized
to target application-specific scenarios. See User Guide section
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]
for more information.
) 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 without the need to re-synthesize the FPGA's bitstream.
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 program 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 setup with
non-volatile application storage, which can still be updated at any time.
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.

The bootloader is implemented if the <<_int_bootloader_en>> generic is _true_ (default). This will automatically
select the CPU's <<_indirect_boot>> boot configuration.

.Hardware Requirements for the _Default_ NEORV32 Bootloader
[IMPORTANT]
**REQUIRED**: The bootloader requires the privileged architecture CPU extension
(<<_zicsr_control_and_status_register_access_privileged_architecture>>)
and at least 512 bytes of data memory (processor-internal DMEM or external DMEM). +
+
**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) for this purpose. +
+
**RECOMMENDED**: The default bootloader uses bit 0 of the GPIO controller's
(<<_general_purpose_input_and_output_port_gpio>>) output port to drive a high-active "heart beat" status LED. +
+
**RECOMMENDED**: The MTIME machine timer (<<_machine_system_timer_mtime>> generic is _true_) 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 required
to store/load executable from external flash (for the auto boot feature).
:sectnums:
==== Bootloader SoC/CPU Requirements

The bootloader relies on certain CPU and SoC extensions and modules to be enabled to allo 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).
|=======================


: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:

* `0x03`: Read data
* `0x04`: Write disable (for volatile status register)
* `0x05`: Read (first) status register
* `0x06`: Write enable (for volatile status register)
* `0x02`: Page program
* `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.

.Known-Good Chips
[TIP]
Compatible (FGPA configuration) SPI flash memories are for example the "Winbond W25Q64FV2 or the "Micron N25Q032A".


: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
Expand All @@ -55,13 +79,13 @@ Terminal console settings (`19200-8-N-1`):

[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 around it. Some terminal programs struggle with
transmitting files larger than 4kB (see https://github.com/stnolting/neorv32/pull/215). Try a different program
if uploading a binary does not work.
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 pin are set to low level). After reset, this LED will start blinking at ~2Hz and the
following intro screen should show up in your terminal:
The bootloader uses the LSB of the top entity's `gpio_o` output port as high-active status LED. Aall other
output pin are set to low level and won't be altered. After reset, this LED will start blinking at ~2Hz and the
following intro screen should show up in the terminal:

[source]
----
Expand All @@ -78,7 +102,7 @@ DMEM: 0x00004000 bytes @0x80000000
Autoboot in 8s. Press any key to abort.
----

This start-up screen also gives some brief information about the bootloader and several system configuration parameters:
The start-up screen gives some brief information about the bootloader and several system configuration parameters:

[cols="<2,<15"]
[grid="none"]
Expand All @@ -87,7 +111,7 @@ This start-up screen also gives some brief information about the bootloader and
| `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 <<_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>>; defined by the `IO_*` and `MEM_*` configuration generics).
| `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).
|=======================
Expand Down Expand Up @@ -170,5 +194,5 @@ In many cases the error source is just _temporary_ (like some HF spike during an
| **`ERROR_1`** | Your program is way too big for the internal processor’s instructions memory. Increase the memory size or reduce your application code.
| **`ERROR_2`** | 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.
| **`ERROR_3`** | 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.
| **`ERROR - Unexpected exception!`** | The bootloader encountered an 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 beeing implemented.
| **`ERROR - Unexpected exception!`** | The bootloader encountered an 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.
|=======================
15 changes: 8 additions & 7 deletions docs/userguide/customizing_the_bootloader.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@ base ISA `rv32i` only to ensure it can work independently of the actual CPU conf
| `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_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
| `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_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_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
| `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_ADDR_BYTES` | `3` | `2`, `3`, `4` | SPI flash address size in number of bytes (2=16-bit, 3=24-bit, 4=32-bit)
| `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
Expand Down
Loading