XMODEM Bootloader

Introduction

This describes a bootloader system for the W65C832 and RISC-V FPGA cores by Michael Kohn. I thought it would be nice to be able to load programs into RAM without having to "burn" them into ROM with the processor core itself, which can take several minutes.

To make this possible, Mike designed a simple two-wire UART module. I initially wrote a bootloader which decoded ASCII hexadecimal, which wasn't very reliable. So I switched to the XMODEM protocol, which doesn't require much code to implement, and can work over a basic serial line without handshaking.

Test Setup

Connections are made to the iceFUN FPGA board as follows:

Red 5V not connected
Black GND
White RX goes to H3
Green TX goes to G3

Communications Setup

Terminal software which supports the original XMODEM protocol is required (e.g. Minicom). The serial port should be set to:

Protocol

Character Codes:

SOH 0x01 Start of Header
EOT 0x04 End of Transmission
ACK 0x06 Acknowledged
NAK 0x15 Not Acknowledged
CAN 0x18 Cancel (ignored by this implementation)

The iceFUN board has four buttons, defined in icefun.pcf as follows:

  1. button_halt
  2. button_0
  3. button_reset
  4. button_program_select

Pressing button_reset will display a short message. After initiating an XMODEM transfer in the terminal software, pressing button_0 will begin the download. The other buttons aren't used.

A 132-byte XMODEM packet begins with either an SOH or EOT character. If it's SOH then the download begins (or continues). The remaining 131 bytes are then read all at once:

0 Packet Count
1 Inverse Packet Count
2-129 Data
130 Checksum

A few tests are done to provide reasonable assurance that the data is correct:

(The checksum is simply the low byte of the 16-bit sum of all 128 data bytes in the received packet.)

If a test fails, then a NAK character is sent and the program waits for a new SOH.

If successful, an ACK is sent and the data portion of the packet (128 bytes) is stored into program memory, and the client's packet count is incremented by one. The next SOH signals to continue, or an EOT ends the transmission.

The final packet is padded by the host with extra characters (typically 0x1a) if needed to make it 128 bytes in length.

Details

The bootloader resides in ROM starting at 0x4000. The W65C832/RISC-V cores have 4K ROM and 4K RAM by default. But since the bootloaders require little ROM, the amount defined in rom.v can be smaller, which allows for the amount of RAM defined in ram.v to be proportionally larger. (When changing memory sizes the address bus widths may also need to be adjusted.)

The booloader sends "Ready." to the terminal by default, but this can be customized at the end of the assembly source code file if desired.

On the W65C832, the CPU register widths are set to 8-bits, hence "65C02" instructions are used for the most part. The bootloader fits within 256 bytes of ROM, with room to spare for a longer welcome messag. The downloaded program starts at 0x200, above "zero-page" and the stack.

The RISC-V version loads the program directly into memory starting at location zero. It's register-based and doesn't need a stack. It's a little over 300 bytes.

User programs need to use the correct .org directive: ".org 0x200" for W65C832, ".org 0" for RISC-V.

Programs

The downloaded program is executed immediately after a successful transfer. On the W65C832, memory initially used by the bootloader (0x00-0x1ff) may be used freely.

Pressing the reset button while a program is running restarts the FPGA, allowing a different program (or revision) to be loaded. The assembly source code contains the routines (read_uart and write_uart) which can be copied and used by custom programs which need to interact with the terminal.

Conclusion

Though XMODEM is an older protocol intended to be used over telephone lines, it still worked well for this purpose. The bootloader makes designing software more efficient than "burning" the entire FPGA core over again just to test a different program. And once fully tested, a user program can then replace the bootloader itself.

Source Code

Assembly code is included in the "test" directories of the FPGA core sources. Running "make bootloader" will create the rom.txt file used in the build process.