Skip to content

Home > Development > Tools > nanoBoot format


nanoBoot format

Warning

This is under development.

nanoBoot is the software protocol that allows to send code (or generic data) to a Durango or any other computer fitted with a nanoLink port.

General operation

The idea is pretty simple: by using the NMI (or similar) line as a clock signal, the sender quickly gets the receiver's attention for every transmitted bit. Upon servicing this prioritary interrupt, any lower-privilege ones are masked. Then, this mask is temporarily lifted so, if the data line is asserted, an IRQ (or other lower privilege/maskable interrupt) is issued and a flag is marked, then returns. After this brief interrupt enabling, the NMI routine checks for the aforementioned flag: if that flag is not enabled, a zero was received. Otherwise, it's a one.

The NMI routine should keep count of the times it was called, so after eight calls a whole byte was received (shifting the bits in as soon as they're checked). Then, that byte is written into the corresponding address and a suitable pointer is incremented to point to the following address, until the address limit is reached; at that point, loaded code is executed, if possible (more on this later).

Note

This is a best effort protocol, without any flow control, acknowledge or negotiation. Being a simplex link, there's no way for the receiver to request any 'file' from the sender -- if the receiver is ready before the sender starts the transmission, it may succeed. Also, in case of any framing error or link breakdown, the receiver will likely hang up.

The Hardware

Signals definition

This is a two-wire interface (plus ground) based on a Synchronous Serial link. The main feature is that the receiving side needs almost no additional hardware, as it simply repurposes the regular /IRQ and /NMI interrupt lines for DATA (SERDAT, LSB first) and CLOCK (SERCLK) transmission, respectively. Note that, even if this was designed around the 6502 CPU, it may be applied to almost any CPU, as long as it has two interrupt lines with different privilege levels.

Suggested connector

The standard connector is a 4-way pin header, where one pin has been cut to prevent reversed connection. Pinout goes as follows:

Pin # Silkscreen Signal
1 G Ground
2 C SERCLK clock
3 D SERDAT data
4 x cut key

Receiver requisites

Since this communication link uses two interrupt lines (one of them non-maskable or, at least, with different privileges), you'll need these exposed. The protocol uses active-high signals (unlike the interrupt lines in most CPUs) so you'll likely need a couple of open collector inverters, which will also isolate the computer's 5 V line from 3.3 V devices (like recent Raspberry Pi_s). Also, in order not to interfere with the data transmission, a way to disable regular interrupts (other than _masking them in software) must be provided.

The SERCLK (Clock) signal will drive NMI or the interrupt with highest privileges, whereas the SERDAT (Data) signal will drive IRQ or the least privileged interrupt line. Of course, you need to connect the GND (Ground) pin as well.

Tip

The Durango·X home computer fits all requirements for nanoBoot, as do the simpler Chihuahua SBC and the recently developed Rosario 6301 computer.

Note

In case of the Durango·X computer, there's an AUDIO_FB jumper which connects the SERDAT input to the audio output, which makes a screeching sound during nanoLink transfers, as a crude (but sometimes helpful) form of feedback.

Sender requisites

Being a synchronous serial interface on a simplex link, the output interface is just a couple of pins for clock and data signals -- no need for open collector or tristate. This can be achieved thru several ways, like:

  • Two GPIO (output) pins, like those on the RaspberryPi or Arduino (3.3 V logic is OK).
  • A VIA 6522 shift register thru CB1 and CB2.
  • Another Durango with a couple of latched output pins -- a suitable interface has been developed.

Note

The bits are sent with the least significative (LSB) first. That's compatible with the use of a VIA's shift register as a sender.

Since Durango·X (as well as Chihuahua and Rosario) have the same receiving interface (BC548 BJT with 22K base resistor), there's no need for a full 5V level at these inputs. To be on the conservative side, anything over TTL levels (2.0 v active high), probably much less (but definitely over ~0.7 v). These inputs will sink 200 µA at most, thus almost any kind of circuit will be able to drive them.

Protocol

Transmission header

Prior to actual data transmission, a 40-bit header must be sent in order to identify the data type, start address and length. The receiver would be able to reject the transmission, although normal operation of the receiving computer might be affected by abnormal activity on interrupt lines during the rejected transfer, as the sender has no way to know about the desired rejection, an thus won't stop the transmission.

Byte 1 Byte 2 & 3 Byte 4 & 5
Magic number End address (BigEndian) Start address (BigEndian)

Note

Unlike 6502 code, both addresses are in Big Endian format!

The End address is the first address that will not be loaded from transmission. If, for instance, the transmitted block is to be loaded into the $6000-$7FFF area, the end address will be $8000, and thus bytes 2 to 5 will be sent precisely as $80, $00, $60, $00.

Magic numbers

This is a byte to identify the activity as a valid nanoBoot transmission, and also determine its format. As of 2024-04-24, four formats are defined.

Magic number Type Load address Execution address
$4B RAM bootloader (legacy) Specified to sender Same as load address
$4C ROM image $10000-image size Vectored at $FFFC
$4D Generic data Specified to sender N/A
$4E Pocket executable Vectored at offset $3-4 in file header Vectored at offset $5-6 in file header

Warning

$4B was the only supported mode on older versions of nanoBoot client ROM, but timing and other details may be incompatible with modern implementations. Make sure you use recent (May 2024 and later) versions of both the server (sender) and receiver (client) software!

Note

$4B, $4C and $4E are intended for executable code, when the receiver will keep waiting for something to be executed; whereas the $4D signature is about generic data for communication between Durangos (or any other nanoLink-equipped device) and still under development.

Software

Sender

According to the available hardware, there are many ways to write suitable code. Usually will be a matter of generating the transmission header and sending out the bits with suitable delays (see Timing section below for details). So far (until April 2024) a simple C program for RaspberryPi has been used, although only binary blobs (type $4B) are supported.

Receiver

Since this is an interrupt-driven feature, unless the target computer has no use for interrupts at all, your firmware will usually provide user-defined interrupt vectors. Two common ways are available for 6502 systems:

  • Make the IRQ/NMI hard vectors point to a JMP instruction in RAM, followed by the required ISR address.
  • Make the IRQ/NMI hard vectors point to an indirect JMP(abs) in ROM, which will take the ISR address from some RAM vectors.

Durango software takes the latter approach, with soft IRQ vector at $0200, and soft NMI vector at $0202. In any case, both the bootloader firmware and the executable code to be loaded are expected to set these vectors accordingly.

Also, since the normal IRQ generation will interfere with the data line, the bootloader should shut off such generation before attempting to receive, and restore it just after loading has finished (or was aborted). In the case of Durango·X computer, this is done by clearing bit 0 at the Interrupt Enable Register ($DFAx) and then setting it afterwards; the ERROR LED will stay lit while reception is enabled.

Timing

Generally speaking, nanoBoot timing is very loose, as long as the receiver is fast enough to handle the incoming data. Designed more for convenience and reliability than speed, these are the recommended minimum times to be observed.

Warning

Unlike a code bootloader, where the receiving computer keeps waiting for the code to arrive (or until cancelled by timeout or keystroke, if available), transmissions under the $4D signature (generic data) are intended to be serviced during normal operation of the receiving computer, thus must adhere to much stricter timing as most of the time the standard ISR should be kept available.

In order to allow for timeouts, feedback etc., the header is transmitted at a slow pace of 500 bits per second. Current software waits 2 ms between bits, of which the SERCLK pulse is kept for at least 15 µS for reliability. After each byte is transmitted, and extra 1 mS delay** is used for reliable operation, although not strictly necessary.

The whole header takes about 85 mS to be transmitted.

Data stream

Originally designed to work reliably on a 1 MHz computer, which is the minimum expected for any 6502 system, each bit takes a total of 80 µS, of which the SERCLK pulse is kept for at least 15 µS as before. After all 8 bits are transmitted, an extra 125 µS delay is specified.

However, unlike the header trasnmission, page boundary crossing may happen and extra delay must be added, especially if some kind of feedback is desired. Originally stated at 1 mS, current version specifies 2 mS allowing for graphic screens to be updated.

Note

Albeit most transmissions will be page-aligned, note that this 2 mS delay is not necessarily done every 256 transmitted bytes, but ever the next received byte will be stored at $xx00, when the actual page boundary is crossed.

All of this means the nominal rate is 12.5 kbit per second, although the needed overhead will get the actual transfer rate a bit over 1 KByte per second, which is reasonable for its purpose.

Note

You may speed up the transmission if the receiving computer is fast enough; but reliability might be affected. Experiments with 1 MHz 65C02 were able to make successful transmissions up to 18 kb/s nominal rates, but sometimes it needed a few attempts to succeed.

Tip

Generally speaking, the SERDAT line should be updated before the SERCLK pulse is sent (NMI will be generated at the leading edge); but in most cases, there will be at least a 7-cycle margin while the NMI is acknowledged, allowing the use of a VIA Shift Register as a sender, for instance. This margin should be taken into account for the hold time as well, plus whatever delay creates your NMI code before briefly enabling the IRQ (SERDAT) line.