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

[sw] update bootloader #364

Merged
merged 7 commits into from
Jul 12, 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 |
|:-------------------:|:-------:|:--------|
| 12.07.2022 | 1.7.3.9 | clean-up and rework **bootloader**; :sparkles: add "boot via XIP" option; [#364](https://github.com/stnolting/neorv32/pull/364) |
| 11.07.2022 | 1.7.3.8 | **physical memory protection(PMP)**: locking entry `i` in TOR mode will now also prevent write access to `pmpaddr(i-1)` (RISC-V compatibility); [#363](https://github.com/stnolting/neorv32/pull/363) |
| 09.07.2022 | 1.7.3.7 | :bug: fixed **bootloader's** byte order when using the flash for application storage: :warning: was BIG-endian, is now also LITTLE-endian; [#362](https://github.com/stnolting/neorv32/pull/362) |
| 08.07.2022 | 1.7.3.6 | :test_tube: added burst mode option to **XIP module** to accelerate consecutive flash read accesses; :warning: fixed XIP endianness: was BIG-endian and is now LITTLE-endian; [#361](https://github.com/stnolting/neorv32/pull/361) |
Expand Down
66 changes: 36 additions & 30 deletions docs/datasheet/software_bootloader.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ via UART. This allows to build processor setups with _non-volatile application s
:sectnums:
==== Bootloader SoC/CPU Requirements

The bootloader relies on certain CPU and SoC extensions and modules to be enabled to allo full functionality.
The bootloader relies on certain CPU and SoC extensions and modules to be enabled to allow full functionality.

[cols="<3,<12"]
[grid="none"]
Expand All @@ -32,6 +32,7 @@ Without UART0 the auto-boot via SPI is still supported but the bootloader should
| _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.
|=======================


Expand All @@ -42,11 +43,11 @@ The bootloader can access an SPI-compatible flash via the processor's top entity
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
* `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)
* `0x02`: Page program
* `0xD8`: Block erase (64kB)

.Custom Configuration
Expand All @@ -55,10 +56,6 @@ Most properties (like chip select line, flash address width, SPI clock frequency
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
Expand All @@ -83,21 +80,21 @@ can transfer data in _raw_ byte mode without any protocol overhead (e.g. XMODEM)
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. 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:
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: Feb 16 2022
HWV: 0x01060709
BLDV: Jul 11 2022
HWV: 0x01070307
CLK: 0x05f5e100
ISA: 0x40901107 + 0xc000068b
SOC: 0x7b7f402f
IMEM: 0x00008000 bytes @0x00000000
DMEM: 0x00004000 bytes @0x80000000
ISA: 0x40901104 + 0xc0000783
SOC: 0x7c5f400f
IMEM: 0x00004000 bytes @0x00000000
DMEM: 0x00002000 bytes @0x80000000

Autoboot in 8s. Press any key to abort.
----
Expand All @@ -123,13 +120,13 @@ you press any key within the 8 seconds, the actual bootloader user console start
----
<< NEORV32 Bootloader >>

BLDV: Feb 16 2022
HWV: 0x01060709
BLDV: Jul 11 2022
HWV: 0x01070307
CLK: 0x05f5e100
ISA: 0x40901107 + 0xc000068b
SOC: 0x7b7f402f
IMEM: 0x00008000 bytes @0x00000000
DMEM: 0x00004000 bytes @0x80000000
ISA: 0x40901104 + 0xc0000783
SOC: 0x7c5f400f
IMEM: 0x00004000 bytes @0x00000000
DMEM: 0x00002000 bytes @0x80000000

Autoboot in 8s. Press any key to abort.
Aborted. <1>
Expand All @@ -140,6 +137,7 @@ Available commands:
u: Upload
s: Store to flash
l: Load from flash
x: Boot from flash (XIP)
e: Execute
CMD:>
----
Expand All @@ -152,17 +150,25 @@ The auto boot countdown is stopped and the bootloader's user console is ready to
* `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]
The CPU is in machine level privilege mode after reset. When the bootloader boots an application,
this application is also started in machine level privilege mode.
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].
Expand Down Expand Up @@ -190,13 +196,13 @@ In many cases the error source is just _temporary_ (like some HF spike during an
[cols="<2,<8"]
[grid="rows"]
|=======================
| **`ERROR_0`** | 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. Also, if no SPI flash was found during an auto-boot attempt, this message will be displayed.
| **`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 being implemented.
| **`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 some hexadecimal debug information showing
If an unexpected exception has been raised the bootloader prints hexadecimal debug information showing
the <<_mcause>>, <<_mepc>> and <<_mtval>> CSR values.
66 changes: 19 additions & 47 deletions docs/userguide/customizing_the_bootloader.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,77 +25,49 @@ base ISA `rv32i` only to ensure it can work independently of the actual CPU conf
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+^| Auto-boot configuration
| `AUTO_BOOT_TIMEOUT` | `8` | _any_ | Time in seconds after the auto-boot sequence starts (if there is no UART input by the 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_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` | `0x02000000` | _any_ 32-bit value | Defines the _base_ address of the executable in external flash
| `SPI_BOOT_BASE_ADDR` | `0x00400000` | _any_ 32-bit value | Defines the _base_ address of the executable in external flash
4+^| XIP configuration
| `XIP_EN` | `0` | `0`, `1` | Set `1` to enable the XIP options
| `XIP_PAGE_BASE_ADDR` | `0x40000000` | _any_ 32-bit value | Defines the page _base_ address where the XP flash will be mapped to
|=======================

[NOTE]
The XIP options re-use the "SPI configuration" options for configuring the XIP's SPI connection.

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 `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`):
For example, to configure a UART Baud rate of 57600 and redirecting the status LED to GPIO output pin 20
use the following command:

.Example: customizing, re-compiling and re-installing the bootloader
[source,console]
----
$ make USER_FLAGS+=-DUART_BAUD=57600 USER_FLAGS+=-DSTATUS_LED_PIN=20 clean_all bootloader
sw/bootloader$ 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:
=== Bootloader Boot Configuration

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.
=== Auto-Boot Configuration

:sectnums!:
==== Default Boot Configuration

The _default_ bootloader configuration provides a UART-based user interface that allows to upload new executables
The default bootloader 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]
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.
The bootloader also provides an _automatic boot sequence_ (auto-boot) which will start copying an executable
from external SPI flash to IMEM using the default SPI configuration. By this, the default bootloader
provides a "non-volatile program storage" mechanism that automatically boots from external SPI flash
(after `AUTO_BOOT_TIMEOUT`) while still providing the option to re-program the SPI flash at any time
via the UART console.
Loading