XModem Bootloader
Introduction
Hardware
Address Map
XIP (ECPS64)
1st Stage Bootloader
2nd Stage Bootloader
XModem upload
XModem Loader FPGA image
XBOOT Header
Blinky example
How to build
Download
 

Introduction

This project here is a further development of an existing XModem Bootloader which was also created for a DE0-Nano board but for a NIOS II CPU.

With this project it should be possible to load a program into one of the different memories and start it there:

  • XIP (Execute in Place memory, existing SPI flash on the DE0-Nano)
  • IMEM (TCM, Tightly Coupled Memory)
  • SDRAM
  • SD Card to SDRAM (under development)

In addition, it should also be possible to update the FPGA image.

Furthermore, the existing DE0-Nano size configuration with IMEM of 32K, DMEM of 16K and ICACHE of 2K should be retained. Due to this condition, the bootloader could only have a maximum size of 8K.

Because of the size limitation, the bootloader has now been split into two parts:

  • 1st Stage Bootloader in ROM area
  • 2nd Stage Bootloader in XIP area

Note: Compared to the original NEORV32 bootloader, this one uses 115200 baud for output via the terminal.


Note: NEORV32 v1.8.9.6 was used, where the memory layout has changed compared to the last v1.8.4. E.g. the XIP address was changed from 0x40000000 to 0xE0000000.


Hardware

Here a DE0-Nano board with the "JTAG Terasic Adapter" was used:

Address Map

The settings on the NEORV32 result in the following address map:

 Peripheral  Address Offset  Size (bytes)  Attribute
 On-Chip Debugger  0xFFFFFF00  256  OCD address space
 SYSINFO  0xFFFFFE00  256  System Information Memory
 GPIO  0xFFFFFC00  256  General Purpose Input / Output
 WDT  0xFFFFFB00  256  Watchdog Timer
 TRNG  0xFFFFFA00  256  True Random Number Generator
 SPI  0xFFFFF800  256  SPI Controller
 UART0  0xFFFFF500  256  Primary UART
 MTIME  0xFFFFF400  256  Machine System Timer
 GPTMR  0xFFFFF100  256  General Purpose Timer
 XIP  0xFFFFEF00  256  Execute In Place Module
 Bootloader ROM  0xFFFFC000  8K  1st Stage Bootloader
 XIP  0xE07E0000  128K  XIP 2nd Stage Bootloader
 XIP  0xE0100000  7M - 128K  XIP User Memory
 XIP  0xE0000000  1M  XIP FPGA Memory
 SDRAM  0x91FE0000  128K  2nd Stage Bootloader
 SDRAM  0x90000000  32M - 128K  External SDRAM
 DMEM  0x80000000  16K  On-chip Data Memory
 IMEM  0x00000000  32K  On-chip Instruction Memory
 ICACHE  - - - - - - - - -  2K  On-chip Instruction Cache

XIP (EPCS64)

The DE0-Nano board is equipped with an EPCS64 or EPCS64 compatible serial configuration device. This configuration device is like a SPI flash memory. In case of the XModem Bootloader the address map looks like:

 Area  SPI Address Offset  XIP Address Offset  Size (bytes)
 FPGA image  0x00000000  0xE0000000  1M
 User area  0x00100000  0xE0100000  7M

The EPCS64 has a size of 8 MBytes. Where the first 1 MByte is reserved for the FPGA image with the 1st Stage Bootloader. The user area, starting by 0x00100000, can be free used.

1st Stage Bootloader

The 1st Stage Bootloader only has the task of starting the 2nd Stage Bootloader from the XIP.

Oops, how did the 2nd stage bootloader even get into the XIP for the first time? For this there is now a FPGA image available with the corresponding reduced bootloader which can be loaded into the FPGA with the Quartus programmer.

Normally you do not see the output of the 1st stage Bootloader because the start of the 2nd Stage Bootloader runs very quickly. The start process can be paused by holding down Key0, while powering on, of the DE0-Nano. In addition, the system information of the NEORV32 is also displayed:

The system information is also automatically displayed in the event of an error. Here because the 2nd Stage Bootloader could not be found at address 0xE07E0000.

In addition, LED0 is flashes very quickly (100ms) in case of this error.

2nd Stage Bootloader

The primary task of the 2nd Stage Bootloader is to start the program at address 0xE0100000. If the image is valid, it will be started automatically. But the boot process can be aborted within 3 seconds:

If the boot process is interrupted you have the following options:

With e.g. "i" you can now display information about existing images:

Currently there is a program in the XIP and the 2nd Stage Bootloader is available. No programs are stored in the TCM and SDRAM area.

Note: The bootloader will only start automatically the program from the XIP area. A program from TCM or SDRAM must be started by hand. For this there are the options "t" and "s" available.

There are also the options "E", "F", "X" and "B" for erasing the corresponding areas available.

If there is no program in the XIP area available, then the 2nd Stage Bootloader automatically starts the XModem upload mode:

XModem upload

Here I use TeraTerm which has the possibility to send data via XMODEM. While the data is transferred, the output looks like:

If the transfer is finished, some tests will be done with the image. If the tests was successful, the new image will be stored in the memory. The output for a XIP image upload looks like:

The program can now be started with the option "x".

XModem Loader FPGA image

If the 2nd Stage Bootloader is not yet stored in the XIP, it can be stored there with the development environment, for example. For this you have to be able to debug the program with JTAG.

A simpler alternative is an FPGA image with integrated XModem Bootloader as SOF file. The SOF file can now easily be loaded into the FPGA with the Quartus programmer.

Now the 2nd Stage Bootloader can be loaded into the XIP area starting at 0xE07E0000.

neorv32-de0n-xmodem.sof which simply has to be loaded into the FPGA with the programmer.

XBOOT Header

The data received from the Bootloader must contain a valid XBOOT header. The XBOOT header looks like:

The header and data are secured by a checksum. The data follows directly after the XBOOT header. "StartAddress" is the start address of the XBOOT header in the XIP, TCM or SDRAM memory. The size of the update file, header and data, must be 4K bytes aligned. 4K bytes is the size of a sector inside the EPCS memory.

The update file for the application can be generated with the tool "bin2xboot".

The update file for a FPGA image can be generated with the tool "rpd2xboott". This little tool requires an Altera RPD (Raw Programming Data File) file for input and generates the XBOOT (XBO) update file.

Note: A program that is to be stored in the XIP area at 0xE0100000 must be linked starting at 0xE0100040. An offset of 0x40 compared to the "StartAddress" is required here, because the XBOOT header itself has a size of 0x40.

If a program is stored in the IMEM at address 0x00000000 must be linked accordingly with 0x00000040. The same applies to the SDRAM, stored at 0x90000000 and linked starting at 0x90000040.

Blinky example

The memory areas were defined in a way that they start with an offset of 0x40:

This means that the XBOOT header can now be placed in front of the actual BIN file without any problems. In the project there are now the different configurations available:

Here the "XIP to SDRAM" is selected. This mean the project should be stored in the XIP area, but will be executed in the SDRAM. The program runs in the XIP at startup, but then copies itself to SDRAM. However, since the program is for the XIP area, it must be generated for 0xE0100000 and linked for 0xE0100040.

There is also a "post-build command" that converts the BIN file into an XBOOT (xbo) file. The "StartAddress" for the XBOOT header is also specified here as a parameter.

(Click inside the picture to expand)

If the program was successfully compiled by a "Rebuild", a "build" folder is automatically created in which the file "neorv32-blinky.xbo" should now be located. This XBO file can now be used for an upload with the bootloader and the XMODEM protocol.

You can use the other configuration "SDRAM Release" or "TCM Release" to create XBO files for uploading in the IMEM (TCM) or SDRAM area.

Btw, for the software development SEGGER Embedded Studio for RISC-V was used.

How to build

The project structure looks like this:

Next, I will briefly describe the subprojects and show the configuration with which they have to be compiled for a release version.

bin2vhd is a small utility to convert a binary file to VHDL code. It will be used for converting the 1st Stage Bootloader to VHDL so that it can then be synthesized for the FPGA and stored in the ROM area. bin2vhd is a command line tool and was compiled with Microsoft Visual C++ 6.0. Don't worry, you does not need to compile it by yourself. An executable is available in the tools folder inside the projects which need this little tool.

bin2xboot is also a command line program. It is used to write the XBOOT header in front of the BIN file. Again, the executable is available in the tools folder in the projects that need this little tool. It was compiled with Microsoft Visual C++ 6.0 too.

blinky, I already mentioned blinky above. Blinky is my little test program which uses TinyCTS/AL as operating system. A CoreMark and Dhrystone benchmark are also integrated.

Configuration:

The "Release" configuration can be used to create XBO files for the relevant areas such as SDRAM, IMEM (TCM) and XIP. With the "Debug" configuration, the program can be debugged in the corresponding area. Oops, with the configuration "TCM Debug" either the IMEM area is too small or the program is too big ;o)

first-boot is the 1st Stage Bootlaoder and resides in the ROM area. The first part of the bootloader is only there to load the second part. Since the actual functionality was too big for the ROM area, or rather you would have lost FPGA "space" as a result, the actual bootloader functionality was moved to the second part.

Configuration:

The "ROM Release" configuration must be used here to create a release version. Then the BIN file can be converted into a VHDL file with bin2vhd later. After you have successfully compiled the project with "Rebuild":

Can you then use "_create_boot_vhd" to create the VHDL file:

This creates the "first_stage_bootloader.vhd" file in the "build" folder. Now copy this file into the "fpga/src" folder:

The next time the FPGA is compiled, the new 1st Stage Bootloader will be included also.

first-xboot is a functionally reduced version of the 2nd Stage Bootloader. But packaged as a 1st Stage Bootloader. This version was used in the "XModem Loader FPGA image".

Configuration:

The configuration and creation of the final VHDL file use the same steps like in the "first-boot" before.

fpga is the project for creating the FPGA image. Here Quartus II v15.0.2 was used. There really isn't much else to tell here. But, wait, NEORV32 is used as the CPU here.

second-boot this is the 2nd stage Bootloader. I already described the functionality above.

Configuration:

The "XIP to SDRAM2 Release" configuration must be used here to create a release version. After you have successfully compiled the project with "Rebuild", "_create_xip_to_sdram2_fw" must be used to create the XBO file.

The "SDRAM2" configuration can be used for testing the 2nd Stage Bootloader with the development environment.

xmodem-loader contains only the "XModem Loader FPGA image". The attentive reader should now know how to create the complete image yourself. This is now the final exam for you ;o)

Download

The repository for this project can be found on GitHub at neorv32-de0n-xboot.