diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fe8ab60e..6392170d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) | diff --git a/docs/datasheet/software_bootloader.adoc b/docs/datasheet/software_bootloader.adoc index 3e6d1dd0b..eef6066eb 100644 --- a/docs/datasheet/software_bootloader.adoc +++ b/docs/datasheet/software_bootloader.adoc @@ -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"] @@ -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. |======================= @@ -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 @@ -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 @@ -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. ---- @@ -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> @@ -140,6 +137,7 @@ Available commands: u: Upload s: Store to flash l: Load from flash + x: Boot from flash (XIP) e: Execute CMD:> ---- @@ -152,6 +150,7 @@ 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 @@ -159,10 +158,17 @@ executed via the `e` command. To store the recently uploaded executable to an at 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]. @@ -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. diff --git a/docs/userguide/customizing_the_bootloader.adoc b/docs/userguide/customizing_the_bootloader.adoc index 45723cba5..c58dc6a49 100644 --- a/docs/userguide/customizing_the_bootloader.adoc +++ b/docs/userguide/customizing_the_bootloader.adoc @@ -25,30 +25,34 @@ 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] @@ -56,46 +60,14 @@ The `clean_all` target ensure that all libraries are re-compiled. The `bootloade 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. diff --git a/rtl/core/neorv32_bootloader_image.vhd b/rtl/core/neorv32_bootloader_image.vhd index e773bbf37..7443cb12f 100644 --- a/rtl/core/neorv32_bootloader_image.vhd +++ b/rtl/core/neorv32_bootloader_image.vhd @@ -1,8 +1,8 @@ -- The NEORV32 RISC-V Processor: https://github.com/stnolting/neorv32 -- Auto-generated memory initialization file (for BOOTLOADER) from source file --- Size: 3972 bytes +-- Size: 4048 bytes -- MARCH: default --- Built: 09.07.2022 12:12:19 +-- Built: 12.07.2022 13:48:34 -- prototype defined in 'neorv32_package.vhd' package body neorv32_bootloader_image is @@ -49,7 +49,7 @@ x"00000e93", x"00000f13", x"00000f93", x"00001597", -x"ee458593", +x"f3058593", x"80010617", x"f5860613", x"80010697", @@ -95,11 +95,11 @@ x"00412483", x"00810113", x"30200073", x"fb010113", -x"04912223", -x"800004b7", -x"00048793", -x"04112623", x"04812423", +x"80000437", +x"00040793", +x"04112623", +x"04912223", x"05212023", x"03312e23", x"03412c23", @@ -114,15 +114,50 @@ x"0007a023", x"800007b7", x"0007a223", x"ffff07b7", -x"78478793", +x"7b478793", x"30579073", +x"fe802783", +x"00080737", +x"00040413", +x"00e7f7b3", +x"00078a63", x"000017b7", x"fa002423", x"90078793", x"faf02423", x"fe802783", +x"40000737", +x"00e7f7b3", +x"06078863", +x"f4002023", +x"f4002423", +x"000067b7", +x"f4002623", +x"20578793", +x"f4f02023", +x"f4002423", +x"f4002623", +x"f4002783", +x"00e7f7b3", +x"fe079ce3", +x"f4002783", +x"02000737", +x"00e7e7b3", +x"f4f02023", +x"f4002783", +x"08000737", +x"00e7e7b3", +x"f4f02023", +x"f4002783", +x"fe1fe737", +x"43f70713", +x"00e7f7b3", +x"00801737", +x"60070713", +x"00e7e7b3", +x"f4f02023", +x"fe802783", x"00010737", -x"00048493", x"00e7f7b3", x"00078863", x"00100793", @@ -135,11 +170,11 @@ x"ffff7637", x"00000713", x"5ff78793", x"a0060613", -x"1ed7e063", +x"1ad7ee63", x"000016b7", x"00000793", x"ffe68693", -x"1ee6e263", +x"1ce6e063", x"fff70713", x"01879793", x"00e7e7b3", @@ -158,76 +193,73 @@ x"08000793", x"30479073", x"30046073", x"ffff1537", -x"d8850513", -x"428000ef", +x"dd450513", +x"41c000ef", x"f1302573", -x"3ac000ef", +x"3a0000ef", x"ffff1537", -x"dc050513", -x"414000ef", +x"e0c50513", +x"408000ef", x"fe002503", -x"398000ef", +x"38c000ef", x"ffff1537", -x"dc850513", -x"400000ef", +x"e1450513", +x"3f4000ef", x"30102573", -x"384000ef", +x"378000ef", x"ffff1537", -x"dd050513", -x"3ec000ef", +x"e1c50513", +x"3e0000ef", x"fc002573", -x"370000ef", +x"364000ef", x"ffff1537", -x"dd450513", -x"3d8000ef", +x"e2050513", +x"3cc000ef", x"fe802503", -x"ffff1437", -x"358000ef", +x"ffff14b7", +x"34c000ef", x"ffff1537", -x"ddc50513", -x"3c0000ef", +x"e2850513", +x"3b4000ef", x"ff802503", -x"344000ef", -x"de440513", -x"3b0000ef", +x"338000ef", +x"e3048513", +x"3a4000ef", x"ff002503", -x"334000ef", +x"328000ef", x"ffff1537", -x"df050513", -x"39c000ef", +x"e3c50513", +x"390000ef", x"ffc02503", -x"320000ef", -x"de440513", -x"38c000ef", +x"314000ef", +x"e3048513", +x"380000ef", x"ff402503", -x"310000ef", +x"304000ef", x"fe802783", x"00020737", x"00e7f7b3", -x"04078c63", +x"04078663", x"ffff1537", -x"df850513", -x"368000ef", -x"f9402683", -x"f9002703", -x"f9402783", -x"fef69ae3", -x"fe002783", -x"000405b7", -x"00379793", -x"00e78733", -x"00f737b3", -x"00d787b3", -x"fe802683", -x"00b6f6b3", -x"0c068263", -x"fa402683", -x"0a06de63", +x"e4450513", +x"35c000ef", +x"2b8000ef", +x"fe002483", +x"000409b7", +x"00349493", +x"00a48933", +x"009934b3", +x"00b484b3", +x"fe802783", +x"0137f7b3", +x"0a078663", +x"fa402783", +x"0a07d263", x"ffff1537", -x"e2450513", +x"e7050513", x"320000ef", x"ffff1937", -x"e3090513", +x"e7c90513", x"314000ef", x"ffff1ab7", x"ffff1b37", @@ -235,161 +267,161 @@ x"ffff1bb7", x"ffff1c37", x"ffff1cb7", x"ffff17b7", -x"e9478513", +x"efc78513", x"2f4000ef", -x"fa402403", -x"fe045ee3", -x"0ff47413", -x"00040513", +x"fa402483", +x"fe04dee3", +x"0ff4f493", +x"00048513", x"254000ef", x"ffff17b7", -x"d8078513", +x"dd078513", x"2d4000ef", -x"00010737", -x"fa002783", -x"fe07cee3", -x"00e7f7b3", -x"fe078ae3", x"07200793", -x"06f41e63", +x"06f49863", x"ffff02b7", x"00028067", -x"fb1ff06f", x"00170713", x"01071713", x"00c686b3", x"01075713", -x"e11ff06f", +x"e35ff06f", x"ffe78613", x"0fd67613", x"00061a63", x"00375713", x"00178793", x"0ff7f793", -x"e05ff06f", +x"e29ff06f", x"00175713", x"ff1ff06f", -x"f9402683", -x"f9002603", -x"f9402503", -x"fea69ae3", -x"f2f6e2e3", -x"00d79463", -x"f0e66ee3", +x"1e8000ef", +x"f495e4e3", +x"00b49463", +x"f52560e3", x"00100513", -x"6b8000ef", +x"680000ef", x"ffff1537", -x"d8050513", -x"244000ef", -x"298000ef", +x"dd050513", +x"268000ef", +x"00000513", +x"079000ef", x"06800793", -x"e3090513", -x"02f40263", +x"e7c90513", +x"02f48463", x"07500793", x"00000513", -x"16f40463", +x"16f48063", x"07300793", -x"14f41a63", -x"0004a403", -x"00041863", -x"e9cb0513", +x"14f49663", +x"00042483", +x"00049a63", +x"ffff1537", +x"f0450513", +x"22c000ef", +x"f2dff06f", +x"f20b8513", +x"220000ef", +x"00048513", +x"1a4000ef", +x"f28c0513", x"210000ef", -x"f11ff06f", -x"eb8b8513", -x"204000ef", -x"00040513", -x"188000ef", -x"ec0c0513", -x"1f4000ef", -x"02000537", -x"178000ef", -x"ed8c8513", -x"1e4000ef", +x"00400537", +x"194000ef", +x"f40c8513", +x"200000ef", x"fa402983", x"fe09dee3", x"0ff9f993", x"00098513", -x"144000ef", +x"160000ef", x"07900793", -x"ecf996e3", -x"4e8000ef", +x"eef994e3", +x"4a8000ef", x"00050663", x"00300513", -x"248000ef", +x"22c000ef", x"ffff1537", -x"ee450513", -x"1ac000ef", -x"01045793", +x"f4c50513", +x"1c8000ef", +x"0104d793", x"00178a13", -x"020009b7", +x"004009b7", x"fff00d13", x"00010db7", x"fffa0a13", -x"07aa1063", +x"07aa1c63", +x"ff002683", +x"004009b7", +x"00000d13", +x"00000d93", +x"00c98793", +x"00dd0733", +x"00072583", +x"00fd0533", +x"00d12623", +x"00bd8db3", +x"6f4000ef", +x"004007b7", +x"004d0d13", +x"00c12683", +x"00c78793", +x"fc9d6ce3", x"4788d5b7", x"afe58593", -x"02000537", -x"750000ef", -x"02000537", -x"00040593", -x"00450513", -x"740000ef", -x"ff002703", -x"02000db7", -x"ffc47413", -x"00000993", -x"00000d13", -x"00cd8693", -x"00d98533", -x"00e987b3", -x"05341e63", -x"008d8513", -x"41a005b3", -x"710000ef", +x"00400537", +x"6d0000ef", +x"00048593", +x"00498513", +x"6c4000ef", +x"00898513", +x"41b005b3", +x"6b8000ef", x"ffff1537", -x"d8450513", -x"f25ff06f", -x"3cc000ef", +x"db850513", +x"f0dff06f", +x"374000ef", x"fa802703", x"0d800513", x"00176713", x"fae02423", -x"3a4000ef", +x"34c000ef", x"00098513", -x"48c000ef", +x"434000ef", x"fa802703", x"ffe77713", x"fae02423", -x"3e0000ef", +x"388000ef", x"00157513", x"fe051ce3", x"01b989b3", -x"f61ff06f", -x"0007a583", -x"00e12623", -x"00498993", -x"00bd0d33", -x"6b0000ef", -x"020007b7", -x"00c12703", -x"00c78693", -x"f7dff06f", +x"f49ff06f", x"06c00793", -x"00f41863", +x"00f49863", x"00100513", -x"528000ef", -x"dc1ff06f", +x"4f4000ef", +x"de9ff06f", x"06500793", -x"00f41863", -x"0004a783", -x"e8078ce3", -x"e69ff06f", +x"00f49a63", +x"00042783", +x"e60798e3", +x"f5cb0513", +x"ea1ff06f", +x"07800793", +x"00f49663", +x"00100513", +x"e5dff06f", x"03f00793", -x"ef4a8513", -x"e8f406e3", +x"f6ca8513", +x"e8f482e3", x"ffff17b7", -x"f2878513", -x"e81ff06f", +x"fa078513", +x"e79ff06f", +x"f9402583", +x"f9002503", +x"f9402783", +x"fef59ae3", +x"00008067", x"00040737", x"fa002783", x"00e7f7b3", @@ -409,7 +441,7 @@ x"07800513", x"ffff14b7", x"fbdff0ef", x"01c00413", -x"f7448493", +x"fc048493", x"ffc00993", x"008957b3", x"00f7f793", @@ -448,38 +480,18 @@ x"00048513", x"f25ff0ef", x"fc9ff06f", x"ff010113", -x"00112623", -x"30047073", -x"ffff1537", -x"cf850513", -x"f95ff0ef", -x"00010737", -x"fa002783", -x"fe07cee3", -x"00e7f7b3", -x"fe078ae3", -x"ff002783", -x"000780e7", -x"0000006f", -x"ff010113", x"00812423", x"00050413", x"ffff1537", -x"d0850513", +x"d7050513", x"00112623", -x"f59ff0ef", -x"03040513", -x"0ff57513", -x"ec1ff0ef", -x"03a00513", -x"eb9ff0ef", -x"02000513", -x"eb1ff0ef", +x"f91ff0ef", +x"00241513", +x"00850433", x"ffff1537", -x"00441413", -x"f3450513", +x"fac50513", x"00850533", -x"f29ff0ef", +x"f79ff0ef", x"30047073", x"fe802783", x"00010737", @@ -511,7 +523,7 @@ x"01f12423", x"342024f3", x"800007b7", x"00778793", -x"0af49663", +x"0af49463", x"fe802783", x"00010737", x"00e7f7b3", @@ -522,18 +534,17 @@ x"fcf02423", x"fe802783", x"00020737", x"00e7f7b3", -x"02078863", -x"f9802703", -x"f9c02683", +x"02078663", +x"e29ff0ef", x"fe002783", +x"fff00713", +x"f8e02c23", x"0027d793", -x"00e78733", -x"00f737b3", -x"00d787b3", -x"fff00693", -x"f8d02c23", +x"00a78533", +x"00f537b3", +x"00b787b3", x"f8f02e23", -x"f8e02c23", +x"f8a02c23", x"03c12403", x"04c12083", x"04812283", @@ -560,33 +571,31 @@ x"800007b7", x"0047a783", x"00078663", x"00100513", -x"e75ff0ef", +x"e91ff0ef", x"34102473", x"fe802783", x"00040737", x"00e7f7b3", -x"04078663", +x"04078263", x"ffff1537", -x"d1450513", -x"dc5ff0ef", +x"d7850513", +x"e19ff0ef", x"00048513", -x"d49ff0ef", -x"ffff1537", -x"d3c50513", -x"db1ff0ef", -x"00040513", -x"d35ff0ef", -x"ffff1537", -x"d4450513", x"d9dff0ef", +x"02000513", +x"d7dff0ef", +x"00040513", +x"d8dff0ef", +x"02000513", +x"d6dff0ef", x"34302573", -x"d21ff0ef", +x"d7dff0ef", x"ffff1537", -x"d4c50513", -x"d89ff0ef", +x"dd050513", +x"de5ff0ef", x"00440413", x"34141073", -x"f31ff06f", +x"f39ff06f", x"faa02623", x"fa802783", x"fe07cee3", @@ -726,9 +735,9 @@ x"00050413", x"004a0a13", x"02051863", x"ffff1537", -x"d5050513", -x"b49ff0ef", -x"020005b7", +x"d8450513", +x"ba5ff0ef", +x"004005b7", x"00040513", x"ef1ff0ef", x"4788d7b7", @@ -737,23 +746,23 @@ x"04f50863", x"00000513", x"0380006f", x"ffff1537", -x"d7050513", -x"b1dff0ef", -x"02000537", -x"aa1ff0ef", +x"da450513", +x"b79ff0ef", +x"00400537", +x"afdff0ef", x"ffff1537", -x"d7c50513", -x"b09ff0ef", +x"db050513", +x"b65ff0ef", x"fe802783", x"00080737", x"00e7f7b3", x"00079663", x"00300513", -x"b81ff0ef", +x"ba5ff0ef", x"e11ff0ef", x"fa0502e3", x"ff1ff06f", -x"020009b7", +x"004009b7", x"00498593", x"00040513", x"e89ff0ef", @@ -773,8 +782,8 @@ x"016484b3", x"00200513", x"fa0494e3", x"ffff1537", -x"d8450513", -x"a8dff0ef", +x"db850513", +x"ae9ff0ef", x"02c12083", x"02812403", x"800007b7", @@ -838,28 +847,32 @@ x"01c12983", x"01812a03", x"03010113", x"00008067", -x"746f6f42", -x"2e676e69", -x"0a0a2e2e", -x"00000000", +x"ff010113", +x"00112623", +x"00812423", +x"30047073", +x"ff002403", +x"00050463", +x"40400437", +x"ffff1537", +x"dbc50513", +x"9c5ff0ef", +x"00040513", +x"949ff0ef", +x"ffff1537", +x"dcc50513", +x"9b1ff0ef", +x"00010737", +x"fa002783", +x"fe07cee3", +x"00e7f7b3", +x"fe078ae3", +x"000400e7", x"52450a07", -x"5f524f52", -x"00000000", -x"52455b0a", -x"20524f52", -x"6e55202d", -x"65707865", -x"64657463", -x"63786520", -x"69747065", -x"20216e6f", -x"7561636d", -x"003d6573", -x"70656d20", -x"00003d63", -x"76746d20", -x"003d6c61", -x"00000a5d", +x"00005f52", +x"5252450a", +x"4358455f", +x"00000020", x"69617741", x"676e6974", x"6f656e20", @@ -874,6 +887,12 @@ x"00004028", x"2e2e2e29", x"0000000a", x"00004b4f", +x"746f6f42", +x"20676e69", +x"6d6f7266", +x"00000020", +x"0a2e2e2e", +x"0000000a", x"3c0a0a0a", x"454e203c", x"3356524f", @@ -883,8 +902,8 @@ x"72656461", x"0a3e3e20", x"444c420a", x"4a203a56", -x"20206c75", -x"30322039", +x"31206c75", +x"30322032", x"480a3232", x"203a5657", x"00000020", @@ -938,9 +957,16 @@ x"2064616f", x"6d6f7266", x"616c6620", x"200a6873", -x"45203a65", -x"75636578", -x"00006574", +x"42203a78", +x"20746f6f", +x"6d6f7266", +x"616c6620", +x"28206873", +x"29504958", +x"3a65200a", +x"65784520", +x"65747563", +x"00000000", x"444d430a", x"00203e3a", x"65206f4e", @@ -965,6 +991,10 @@ x"616c460a", x"6e696873", x"2e2e2e67", x"00000020", +x"65206f4e", +x"75636578", +x"6c626174", +x"00002e65", x"20296328", x"53207962", x"68706574", @@ -981,22 +1011,11 @@ x"00323376", x"61766e49", x"2064696c", x"00444d43", -x"6e676973", -x"72757461", -x"72652065", -x"00726f72", -x"65637865", -x"6e696465", -x"4d492067", -x"00004d45", -x"63656863", -x"6d75736b", -x"72726520", -x"0000726f", -x"20495053", -x"73616c66", -x"72652068", -x"00726f72", +x"00455845", +x"5a495300", +x"48430045", +x"4600534b", +x"0048534c", x"33323130", x"37363534", x"62613938", diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 8dc50ac6b..a720be33e 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -68,7 +68,7 @@ package neorv32_package is -- Architecture Constants (do not modify!) ------------------------------------------------ -- ------------------------------------------------------------------------------------------- constant data_width_c : natural := 32; -- native data path width - do not change! - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01070308"; -- NEORV32 version - no touchy! + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01070309"; -- NEORV32 version - no touchy! constant archid_c : natural := 19; -- official RISC-V architecture ID - hands off! -- Check if we're inside the Matrix ------------------------------------------------------- diff --git a/sw/bootloader/bootloader.c b/sw/bootloader/bootloader.c index 7fd7eef3f..7e66c6260 100644 --- a/sw/bootloader/bootloader.c +++ b/sw/bootloader/bootloader.c @@ -38,8 +38,7 @@ * @author Stephan Nolting * @brief Default NEORV32 bootloader. **************************************************************************/ - -// Libraries + #include #include @@ -50,7 +49,7 @@ **************************************************************************/ /**@{*/ -/* ---- UART interface configuration ---- */ +/* -------- UART interface -------- */ /** Set to 0 to disable UART interface */ #ifndef UART_EN @@ -62,7 +61,7 @@ #define UART_BAUD 19200 #endif -/* ---- Status LED ---- */ +/* -------- Status LED -------- */ /** Set to 0 to disable bootloader status LED (heart beat) at GPIO.gpio_o(STATUS_LED_PIN) */ #ifndef STATUS_LED_EN @@ -74,31 +73,16 @@ #define STATUS_LED_PIN 0 #endif -/* ---- Boot configuration ---- */ - -/** Set to 1 to enable automatic (after reset) only boot from external SPI flash at address SPI_BOOT_BASE_ADDR */ -#ifndef AUTO_BOOT_SPI_EN - #define AUTO_BOOT_SPI_EN 0 -#endif - -/** Set to 1 to enable boot only via on-chip debugger (keep CPU in halt loop until OCD takes over control) */ -#ifndef AUTO_BOOT_OCD_EN - #define AUTO_BOOT_OCD_EN 0 -#endif - -/** Set to 1 to enable simple UART executable upload (no console, no SPI flash) */ -#ifndef AUTO_BOOT_SIMPLE_UART_EN - #define AUTO_BOOT_SIMPLE_UART_EN 0 -#endif +/* -------- Auto-boot configuration -------- */ /** Time until the auto-boot sequence starts (in seconds); 0 = disabled */ #ifndef AUTO_BOOT_TIMEOUT #define AUTO_BOOT_TIMEOUT 8 #endif -/* ---- SPI configuration ---- */ +/* -------- SPI configuration -------- */ -/** Enable SPI module (default) including SPI flash boot options */ +/** Enable SPI (default) including SPI flash boot options */ #ifndef SPI_EN #define SPI_EN 1 #endif @@ -125,15 +109,27 @@ /** SPI flash boot base address */ #ifndef SPI_BOOT_BASE_ADDR - #define SPI_BOOT_BASE_ADDR 0x02000000 + #define SPI_BOOT_BASE_ADDR 0x00400000 +#endif + +/* -------- XIP configuration -------- */ + +/** Enable XIP boot options */ +#ifndef XIP_EN + #define XIP_EN 1 +#endif + +/** XIP page base address */ +#ifndef XIP_PAGE_BASE_ADDR + #define XIP_PAGE_BASE_ADDR 0x40000000 #endif /**@}*/ /**********************************************************************//** - Executable stream source select + Executable stream source select (for copying into IMEM) **************************************************************************/ -enum EXE_STREAM_SOURCE { +enum EXE_STREAM_SOURCE_enum { EXE_STREAM_UART = 0, /**< Get executable via UART */ EXE_STREAM_FLASH = 1 /**< Get executable via SPI flash */ }; @@ -142,28 +138,29 @@ enum EXE_STREAM_SOURCE { /**********************************************************************//** * Error codes **************************************************************************/ -enum ERROR_CODES { +enum ERROR_CODES_enum { ERROR_SIGNATURE = 0, /**< 0: Wrong signature in executable */ ERROR_SIZE = 1, /**< 1: Insufficient instruction memory capacity */ ERROR_CHECKSUM = 2, /**< 2: Checksum error in executable */ ERROR_FLASH = 3 /**< 3: SPI flash access error */ }; + /**********************************************************************//** * Error messages **************************************************************************/ -const char error_message[4][16] = { - "signature error", - "exceeding IMEM", - "checksum error", - "SPI flash error" +const char error_message[4][5] = { + "EXE", + "SIZE", + "CHKS", + "FLSH" }; /**********************************************************************//** * SPI flash commands **************************************************************************/ -enum SPI_FLASH_CMD { +enum SPI_FLASH_CMD_enum { SPI_FLASH_CMD_PAGE_PROGRAM = 0x02, /**< Program page */ SPI_FLASH_CMD_READ = 0x03, /**< Read data */ SPI_FLASH_CMD_WRITE_DISABLE = 0x04, /**< Disallow write access */ @@ -176,7 +173,7 @@ enum SPI_FLASH_CMD { /**********************************************************************//** * SPI flash status register bits **************************************************************************/ -enum SPI_FLASH_SREG { +enum SPI_FLASH_SREG_enum { FLASH_SREG_BUSY = 0, /**< Busy, write/erase in progress when set, read-only */ FLASH_SREG_WEL = 1 /**< Write access enabled when set, read-only */ }; @@ -185,7 +182,7 @@ enum SPI_FLASH_SREG { /**********************************************************************//** * NEORV32 executable **************************************************************************/ -enum NEORV32_EXECUTABLE { +enum NEORV32_EXECUTABLE_enum { EXE_OFFSET_SIGNATURE = 0, /**< Offset in bytes from start to signature (32-bit) */ EXE_OFFSET_SIZE = 4, /**< Offset in bytes from start to size (32-bit) */ EXE_OFFSET_CHECKSUM = 8, /**< Offset in bytes from start to checksum (32-bit) */ @@ -235,10 +232,12 @@ volatile uint32_t exe_available; volatile uint32_t getting_exe; -// Function prototypes +/**********************************************************************//** + * Function prototypes + **************************************************************************/ void __attribute__((__interrupt__)) bootloader_trap_handler(void); void print_help(void); -void start_app(void); +void start_app(int boot_xip); void get_exe(int src); void save_exe(void); uint32_t get_exe_word(int src, uint32_t addr); @@ -258,10 +257,10 @@ void spi_flash_write_addr(uint32_t addr); /**********************************************************************//** - * Sanity check: Base ISA only! + * Sanity check: Base RV32I ISA only! **************************************************************************/ #if defined __riscv_atomic || defined __riscv_a || __riscv_b || __riscv_compressed || defined __riscv_c || defined __riscv_mul || defined __riscv_m - #warning In order to allow the bootloader to run on *any* CPU configuration it should be compiled using the base ISA only. + #warning In order to allow the bootloader to run on *any* CPU configuration it should be compiled using the base rv32i ISA only. #endif @@ -270,83 +269,31 @@ void spi_flash_write_addr(uint32_t addr); **************************************************************************/ int main(void) { - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // AUTO BOOT: OCD - // Stay in endless loop until the on-chip debugger - // takes over CPU control - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#if (AUTO_BOOT_OCD_EN != 0) - #warning Custom boot configuration: Boot via on-chip debugger. - while(1) { - asm volatile ("nop"); - } - return 0; // bootloader should never return -#endif - - - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // AUTO BOOT: Simple UART boot - // Upload executable via simple UART interface, no console, no flash options - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#if (AUTO_BOOT_SIMPLE_UART_EN != 0) - #warning Custom boot configuration: Auto boot via simple UART interface. - - // setup UART0 (primary UART, no parity bit, no hardware flow control) - neorv32_uart0_setup(UART_BAUD, PARITY_NONE, FLOW_CONTROL_NONE); - - PRINT_TEXT("\nNEORV32 bootloader\nUART executable upload\n"); - get_exe(EXE_STREAM_UART); - PRINT_TEXT("\n"); - start_app(); - - return 0; // bootloader should never return -#endif - - - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // AUTO BOOT: SPI flash only - // Bootloader will directly boot and execute image from SPI flash - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#if (AUTO_BOOT_SPI_EN != 0) - #warning Custom boot configuration: Auto boot from external SPI flash. - - // setup UART0 (primary UART, no parity bit, no hardware flow control) - neorv32_uart0_setup(UART_BAUD, PARITY_NONE, FLOW_CONTROL_NONE); - // SPI setup - neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0, 0); - - PRINT_TEXT("\nNEORV32 bootloader\nLoading from SPI flash at "); - PRINT_XNUM((uint32_t)SPI_BOOT_BASE_ADDR); - PRINT_TEXT("...\n"); - - get_exe(EXE_STREAM_FLASH); - PRINT_TEXT("\n"); - start_app(); - - return 0; // bootloader should never return -#endif - - - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // AUTO BOOT: Default - // User UART to upload new executable and optionally store it to SPI flash - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - exe_available = 0; // global variable for executable size; 0 means there is no exe available getting_exe = 0; // we are not trying to get an executable yet - // configure trap handler (bare-metal, no neorv32 rte available) neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)(&bootloader_trap_handler)); #if (SPI_EN != 0) // setup SPI for 8-bit, clock-mode 0 - neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0, 0); + if (neorv32_spi_available()) { + neorv32_spi_setup(SPI_FLASH_CLK_PRSC, 0, 0, 0); + } +#endif + +#if (XIP_EN != 0) + // setup XIP: clock mode 0, bursts enabled + if (neorv32_xip_available()) { + neorv32_xip_setup(SPI_FLASH_CLK_PRSC, 0, 0, SPI_FLASH_CMD_READ); + neorv32_xip_burst_mode_enable(); + neorv32_xip_start(SPI_FLASH_ADDR_BYTES, XIP_PAGE_BASE_ADDR); + } #endif #if (STATUS_LED_EN != 0) + // activate status LED, clear all others if (neorv32_gpio_available()) { - // activate status LED, clear all others neorv32_gpio_port_set(1 << STATUS_LED_PIN); } #endif @@ -360,7 +307,7 @@ int main(void) { if (neorv32_mtime_available()) { NEORV32_MTIME.TIMECMP_LO = NEORV32_SYSINFO.CLK/4; NEORV32_MTIME.TIMECMP_HI = 0; - neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MTIE); // activate MTIME IRQ source only! + neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MTIE); // activate MTIME IRQ source neorv32_cpu_eint(); // enable global interrupts } @@ -409,7 +356,7 @@ int main(void) { if (neorv32_mtime_get_time() >= timeout_time) { // timeout? start auto boot sequence get_exe(EXE_STREAM_FLASH); // try booting from flash PRINT_TEXT("\n"); - start_app(); + start_app(0); while(1); } @@ -435,10 +382,10 @@ int main(void) { char c = PRINT_GETC(); PRINT_PUTC(c); // echo PRINT_TEXT("\n"); - while (neorv32_uart0_tx_busy()); if (c == 'r') { // restart bootloader asm volatile ("li t0, %[input_i]; jr t0" : : [input_i] "i" (BOOTLOADER_BASE_ADDRESS)); // jump to beginning of boot ROM + __builtin_unreachable(); } else if (c == 'h') { // help menu print_help(); @@ -450,25 +397,31 @@ int main(void) { else if (c == 's') { // program flash from memory (IMEM) save_exe(); } - else if (c == 'l') { // get executable from flash + else if (c == 'l') { // copy executable from flash get_exe(EXE_STREAM_FLASH); } #endif - else if (c == 'e') { // start application program // executable available? - if (exe_available == 0) { - PRINT_TEXT("No executable available."); + else if (c == 'e') { // start application program from IMEM + if (exe_available == 0) { // executable available? + PRINT_TEXT("No executable."); } else { - start_app(); + start_app(0); // run app from IMEM } } +#if (XIP_EN != 0) + else if (c == 'x') { // boot from SPI flash via XIP + start_app(1); + } +#endif else if (c == '?') { PRINT_TEXT("(c) by Stephan Nolting\ngithub.com/stnolting/neorv32"); } else { // unknown command PRINT_TEXT("Invalid CMD"); } - } + + } // while(1) return 0; // bootloader should never return } @@ -480,43 +433,56 @@ int main(void) { void print_help(void) { PRINT_TEXT("Available CMDs:\n" - " h: Help\n" - " r: Restart\n" - " u: Upload\n" + " h: Help\n" + " r: Restart\n" + " u: Upload\n" #if (SPI_EN != 0) - " s: Store to flash\n" - " l: Load from flash\n" + " s: Store to flash\n" + " l: Load from flash\n" #endif - " e: Execute"); +#if (XIP_EN != 0) + " x: Boot from flash (XIP)\n" +#endif + " e: Execute"); } /**********************************************************************//** - * Start application program at the beginning of instruction space. + * Start application program. + * + * @param boot_xip Set to boot via XIP. **************************************************************************/ -void start_app(void) { +void start_app(int boot_xip) { // deactivate global IRQs neorv32_cpu_dint(); - PRINT_TEXT("Booting...\n\n"); + register uint32_t app_base = NEORV32_SYSINFO.ISPACE_BASE; // default = start at beginning of IMEM +#if (XIP_EN != 0) + if (boot_xip) { + app_base = (uint32_t)(XIP_PAGE_BASE_ADDR + SPI_BOOT_BASE_ADDR); // start from XIP mapped address + } +#endif - // wait for UART to finish transmitting + PRINT_TEXT("Booting from "); + PRINT_XNUM(app_base); + PRINT_TEXT("...\n\n"); + + // wait for UART0 to finish transmitting while (neorv32_uart0_tx_busy()); - // start app at instruction space base address - register uint32_t app_base = NEORV32_SYSINFO.ISPACE_BASE; + // start application asm volatile ("jalr ra, %0" : : "r" (app_base)); - while (1); + + __builtin_unreachable(); + while (1); // should never be reached } /**********************************************************************//** * Bootloader trap handler. Used for the MTIME tick and to capture any other traps. * - * @warning Adapt exception PC only for sync exceptions! - * - * @note Since we have no runtime environment, we have to use the interrupt attribute here. Here and only here! + * @note Since we have no runtime environment, we have to use the interrupt attribute here. **************************************************************************/ void __attribute__((__interrupt__)) bootloader_trap_handler(void) { @@ -531,7 +497,7 @@ void __attribute__((__interrupt__)) bootloader_trap_handler(void) { #endif // set time for next IRQ if (neorv32_mtime_available()) { - neorv32_mtime_set_timecmp(neorv32_mtime_get_timecmp() + (NEORV32_SYSINFO.CLK/4)); + neorv32_mtime_set_timecmp(neorv32_mtime_get_time() + (NEORV32_SYSINFO.CLK/4)); } } @@ -545,13 +511,13 @@ void __attribute__((__interrupt__)) bootloader_trap_handler(void) { register uint32_t mepc = neorv32_cpu_csr_read(CSR_MEPC); #if (UART_EN != 0) if (neorv32_uart0_available()) { - PRINT_TEXT("\n[ERROR - Unexpected exception! mcause="); + PRINT_TEXT("\nERR_EXC "); PRINT_XNUM(mcause); - PRINT_TEXT(" mepc="); + PRINT_PUTC(' '); PRINT_XNUM(mepc); - PRINT_TEXT(" mtval="); + PRINT_PUTC(' '); PRINT_XNUM(neorv32_cpu_csr_read(CSR_MTVAL)); - PRINT_TEXT("]\n"); + PRINT_TEXT("\n"); } #endif neorv32_cpu_csr_write(CSR_MEPC, mepc + 4); // advance to next instruction @@ -562,7 +528,7 @@ void __attribute__((__interrupt__)) bootloader_trap_handler(void) { /**********************************************************************//** * Get executable stream. * - * @param src Source of executable stream data. See #EXE_STREAM_SOURCE. + * @param src Source of executable stream data. See #EXE_STREAM_SOURCE_enum. **************************************************************************/ void get_exe(int src) { @@ -571,7 +537,7 @@ void get_exe(int src) { // flash image base address uint32_t addr = (uint32_t)SPI_BOOT_BASE_ADDR; - // get image from flash? + // get image from UART? if (src == EXE_STREAM_UART) { PRINT_TEXT("Awaiting neorv32_exe.bin... "); } @@ -668,28 +634,23 @@ void save_exe(void) { sector += SPI_FLASH_SECTOR_SIZE; } - // write EXE signature - spi_flash_write_word(addr + EXE_OFFSET_SIGNATURE, EXE_SIGNATURE); - - // write size - spi_flash_write_word(addr + EXE_OFFSET_SIZE, size); - // store data from instruction memory and update checksum uint32_t checksum = 0; uint32_t *pnt = (uint32_t*)NEORV32_SYSINFO.ISPACE_BASE; addr = addr + EXE_OFFSET_DATA; uint32_t i = 0; - while (i < (size/4)) { // in words + while (i < size) { // in chunks of 4 bytes uint32_t d = (uint32_t)*pnt++; checksum += d; spi_flash_write_word(addr, d); addr += 4; - i++; + i += 4; } - // write checksum (sum complement) - checksum = (~checksum) + 1; - spi_flash_write_word((uint32_t)SPI_BOOT_BASE_ADDR + EXE_OFFSET_CHECKSUM, checksum); + // write header + spi_flash_write_word(SPI_BOOT_BASE_ADDR + EXE_OFFSET_SIGNATURE, EXE_SIGNATURE); // EXE signature + spi_flash_write_word(SPI_BOOT_BASE_ADDR + EXE_OFFSET_SIZE, size); // size + spi_flash_write_word(SPI_BOOT_BASE_ADDR + EXE_OFFSET_CHECKSUM, (~checksum)+1); // checksum (sum complement) PRINT_TEXT("OK"); #endif @@ -699,7 +660,7 @@ void save_exe(void) { /**********************************************************************//** * Get word from executable stream * - * @param src Source of executable stream data. See #EXE_STREAM_SOURCE. + * @param src Source of executable stream data. See #EXE_STREAM_SOURCE_enum. * @param addr Address when accessing SPI flash. * @return 32-bit data word from stream. **************************************************************************/ @@ -715,11 +676,9 @@ uint32_t get_exe_word(int src, uint32_t addr) { if (src == EXE_STREAM_UART) { data.uint8[i] = (uint8_t)PRINT_GETC(); } -#if (SPI_EN != 0) else { data.uint8[i] = spi_flash_read_byte(addr + i); // little-endian byte order } -#endif } return data.uint32; @@ -727,22 +686,21 @@ uint32_t get_exe_word(int src, uint32_t addr) { /**********************************************************************//** - * Output system error ID and stall. + * Output system error ID and halt. * * @param[in] err_code Error code. See #ERROR_CODES and #error_message. **************************************************************************/ void system_error(uint8_t err_code) { - PRINT_TEXT("\a\nERROR_"); // output error code with annoying bell sound - PRINT_PUTC('0' + ((char)err_code)); - PRINT_PUTC(':'); - PRINT_PUTC(' '); + PRINT_TEXT("\a\nERR_"); // output error code with annoying bell sound PRINT_TEXT(error_message[err_code]); neorv32_cpu_dint(); // deactivate IRQs + + // permanently light up status LED #if (STATUS_LED_EN != 0) if (neorv32_gpio_available()) { - neorv32_gpio_port_set(1 << STATUS_LED_PIN); // permanently light up status LED + neorv32_gpio_port_set(1 << STATUS_LED_PIN); } #endif @@ -764,9 +722,8 @@ void print_hex_word(uint32_t num) { PRINT_PUTC('x'); int i; - for (i=0; i<8; i++) { - uint32_t index = (num >> (28 - 4*i)) & 0xF; - PRINT_PUTC(hex_symbols[index]); + for (i=28; i>=0; i-=4) { + PRINT_PUTC(hex_symbols[(num >> i) & 0xf]); } #endif }