Blueshell Boot ROM
The Blueshell boot ROM code is found in the "bootrom" subdirectory. The code is written into the external memory shortly after a Blueshell system comes out of reset. The component responsible for this process is BootROMClient.bsv. Once this upload is complete, Microblaze CPUs may be brought out of reset.
Configuration files
The boot ROM is rather complex and written in not-especially-elegant C code. It should be refactored at some point. It is configured by means of #define statements in a header file; each board or CPU project may define its own configuration, or use the default. The configuration specifies the location of the virtual lab tile (used for console messages) and specifies if an Ethernet tile is present.
The default configuration file is "default-config.h" in the "bootrom" subdirectory.
The boot CPU
The first action of the boot ROM program is to establish if it is running on the boot CPU. The boot CPU is found at the Bluetiles location given by the configuration parameters (CPU_X, CPU_Y). If the boot program is running on the boot CPU, then all of the features are enabled. Otherwise, the program runs in a minimal mode which only accepts Bluetiles boot messages and ignores all other messages.
This is done because the Bluetiles CPUs operate in a shared memory space, and the boot ROM program is not able to cope with sharing memory with other instances running on other CPUs (It's not thread safe). However, the minimal mode does not write to memory, and it only accesses code and read-only data. It is, therefore, usable in the multi-CPU environment.
A disadvantage of this design is that it is not possible to upload code into the SPM of any CPU other than the boot CPU, because SPM space is private to each CPU. It's expected that a second-stage bootloader would be used for doing this.
On boot, the bootloader writes the current CPU location and VLAB location as 32-bit values into registers r5 - r8, in accordance with the Microblaze ABI. The register map is as follows:
Value | Reg |
---|---|
cpu_x | r5 |
cpu_y | r6 |
vlab_x | r7 |
vlab_y | r8 |
Event Driven design
The boot ROM program is event-driven. It responds to Bluetiles network events. The messages processed include memory read, memory write, ping, and of course boot messages. It also includes an Ethernet driver which is able to establish a connection to the "UDP.py" module, running on a PC. This may be used for fast communications with the Blueshell system. However, these communications are only available while the boot program is running. If another program replaces the boot program, it must include its own Ethernet drivers.
The boot ROM is built on top of an "operating system" called Bluetiles Reactor which may be found within https://svn.cs.york.ac.uk/svn/rtslab/blueshell/bt/ . This implements the various services (ping, memory read, etc.) and is also used to control the Ethernet MAC core. Bluetiles Reactor was once part of the boot ROM, implemented within main.c, but it was separated so that it could be reused elsewhere. This refactoring happened shortly after the move to Bluetiles II and was Jack's last big contribution to Blueshell.
Ethernet interface
Network communications take place via UDP port 1981. The Blueshell system is given a fixed IP address and a fixed MAC address, which are specified in the netconfig.py file. A connection is established by a PC running software such as "eth_loop_test.py", which uses the "UDP.py" module. The PC connects to the Blueshell system's IP address and performs a brief handshake ("registration"). Though the PC's IP address may be specified as SERVER_IP within netconfig.py, this is not used by the boot program, which will accept registrations from anywhere on the network (without authentication). SERVER_IP is actually used for other programs that send Ethernet packets such as the blast64 program.
Four basic sorts of message are used to relay Bluetiles packets via Ethernet. These are:
- "di". These come from the PC. They contain a Bluetiles packet to be transmitted by the boot loader.
- "ai". These come from Blueshell. They acknowledge receipt of a packet sent by "di".
- "do". These come from Blueshell. They contain a Bluetiles packet to be processed by the PC.
- "ao". These come from the PC. They acknowledge receipt of a packet sent by "do".
There is a primitive sort of flow control implemented by acknowledging each packet. This is not very efficient. But the boot ROM is not large enough to accommodate an implementation of a TCP stack. Lost (unacknowledged) packets are resent after a timeout; 32-bit sequence numbers are used to detect and discard duplicates.
The format of each Ethernet packet is:
- Ethernet header (14 bytes)
- IP header (20 bytes)
- UDP header (8 bytes)
- Message type (di/ai/do/ao) (2 bytes)
- Sequence number (4 bytes)
- Bluetiles header 0 (4 bytes) .. not for ai/ao messages
- Bluetiles header 1 (4 bytes) .. not for ai/ao messages
- Bluetiles payload (4N bytes for N words) .. not for ai/ao messages
Bluetiles messages are effectively sent and received by the boot CPU, with the Bluetiles address (CPU_X, CPU_Y).
Debugging
Historically, the main annoyance with the boot ROM is caused by a problem with the Bluetiles design, namely that invalid, incomplete or otherwise incorrect packets can jam the Bluetiles network, preventing any communication. This is an issue because it prevents the boot ROM printing any messages. So, even if the boot ROM knows why an error occurred, it cannot necessarily report it. It is hard to debug. The problem is somewhat reduced by adding the second send-only Bluetiles interface, independent of the primary send/receive interface (FSL0). But it is not eliminated entirely.
Really, the solution is to have some debug interface that is independent of Bluetiles. We do not yet have such a thing. However, there is an out-of-band Bluetiles debugger implemented by BluetilesDebugRouter.bsv, TileNetDebug.bsv and NetDebugPE.py. The atlys_microblaze project has an example of usage. This may help to show up problems related to incorrect packets.
If the Bluetiles network is still operating, but the boot ROM is not, then it may be possible to find the problem using the tracing tile (TileMicroblazeTrace.bsv). The Python code which communicates with this is found in "services.py". The usage example is atlys_microblaze.
In the manner of LILO, some problems can be diagnosed by looking at the messages printed by the boot ROM during startup. The word "Boot" is printed very early (just after determining if the program is running on the boot CPU). The word "load" is printed after clearing BSS. Both of these messages are sent via the secondary Bluetiles interface if available.Then, the Bluetiles network interface is started properly, a self-test is performed, and the letters "er" are printed. Lastly, the Ethernet MAC is reset (if present) and the rest of the identifying string is printed. If the Ethernet MAC responds, a further message is printed to that effect.