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
andCB2
. - 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 aJMP
instruction in RAM, followed by the required ISR address. - Make the
IRQ
/NMI
hard vectors point to an indirectJMP(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.
Header
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.