I suggest you archive the whole site then, because the fact that this over 20 years old stuff is still out there and alive is almost a miracle.
Done!
And just for anyone else who wants to know how it works...
Bootstrapping a C16x MicrocontrollerThe C16x microcontrollers bootstraps given that certain hardware conditions are met, upon a hardware reset, the processor goes into the bootstrap mode. Once in the bootstrap mode, the processor activates the asynchronous serial port S0 and follows the steps below (see reference 3):
1. Wait for a 0x00 byte
2. When received, send the handshake byte 0x55
3. Wait for 32 more bytes and place them in internal RAM starting at address 0FA40h
4. Once all 32 bytes are received, start execution from 0FA40hBootstrapping can be viewed as a procedure to serially load a 32-byte program into internal RAM and execute it. Clearly, 32 bytes is not enough to program the internal FLASH. We use the 32-byte program to load another program, which in turn may load the larger programs needed to program the internal FLASH.
This multi-stage loading is typical in all C16x family bootstrapping operations.
The first 32 bytes is perhaps the most important. Here is the code that we will use.
#define CODESIZE 176
org 0FA40h
; --- load code immediately following the boot script ---
mov r0, #0FA60h
; --- loop to load the received code ---
LOOP:
jnb S0RIR, W0 ; wait for byte
movb [r0], S0RBUF ; store byte
bclr S0RIR ; clear receive flag
movb S0TBUF, [r0] ; echo the byte
jnb S0TIR, $
bclr S0TIR
; increment pointer and check size
cmpi1 R0, #(0FA60h + CODESIZE - 1)
jmpr cc_NE, LOOP ; repeat if more bytes
nop ; filler bytes
#include <sfr166.inc> ; SFRs are defined here
The bootstrap code constructs a loop of instructions to receive a specified number of bytes from the serial port and place them starting at FA60h. The address FA60h is not arbitrary. The 32-byte code is downloaded and placed starting from FA40h. The last of the 32-byte code is thus placed in FA5Fh. Consequently, FA60h is the address of the byte (or word) immediately following the 32-byte block of bootstrap code. Provided that the bootstrap code does not branch away, the instruction at FA60h is the first instruction to be executed once the bootstrap code is finished.
Let us dissect the code. The code specifies the origin to be FA40h. Note that such address information will be stripped away while only the 32 bytes of instructions will be sent to the processor. The origin is useful, though, in developing the bootstrap code. Once assembled, the resultant list file shows the memory locations the various instructions occupy. Register R0 is used as a pointer, initialized to 0FA60h.
The loop starts with label LOOP and ends with the instruction “jmpr cc_NE, LOOP”. The loop waits for the receive interrupt flag of serial port 0 (S0RIR) to be set. This condition indicates that a byte has been received and is available at the S0 receive buffer. The byte just received is placed in internal RAM at the address held by the pointer R0.
Next, the flag S0RIR is cleared so that it may similarly be interrogated for the next byte. The byte just received is also echoed back to the host. This allows the host to verify that all bytes sent arecorrectly received by the processor. The byte is echoed back simply by copying it into the S0 transmit buffer S0TBUF. The program waits until the byte is actually transmitted. That is, the code waits for the S0 transmit interrupt request (S0TIR) flag to be set. Once set, the flag is cleared, making it ready for the next transmission. The next task is to see if all bytes are received. The macro CODESIZE is initialized to the length of the program that the loop downloads. The last byte in the program is loaded into the memory location (0FA60h + CODESIZE – 1). Note that the “cmpi1” instruction not only compares register R0 to the constant (0FA60h + CODESIZE – 1), but also increments the register R0. This updates the pointer R0 so that the bytes received are stored at consecutive locations.
The loop terminates when CODESIZE number of bytes are received. The last instruction is a “no operation” or “nop” instruction. This is needed since the bootstrap code must be exactly 32 bytes
long. The initialization of register R0 and the loop collectively take 30 bytes. The last instruction brings the bootstrap code length to 32 bytes. This is where the list file, mentioned above, comes
in handy. You may verify the size of the bootstrap program by inspecting the list file.
Note that the code to be downloaded should not overwrite the Special Function Registers (SFR) area immediately following the internal RAM. The C166 SFRs start at FE00h. If the bootstrap
code uses Peripheral Event Controllers (PECs), the PEC pointers in the region [FDE0..FDFFh] should also be off limits to the bootstrap code. Using this scheme we have a code space of
[FA60h..FDDFh] or 896 bytes. Internal RAM is also used for the registers and the stack.
Fortunately, we have a total of 64 more bytes at the low end of internal RAM, namely the block [0FA00h..0FA5Fh]. Half of this ([0FA40h-FA5Fh] is where the 32-byte bootstrap code was
loaded. The 32-byte bootstrap code is discardable. That is, once loaded and used, this memory is available for other use. We will use the memory below 0FA60h for the stack and the registers.
Of course, if the system has external RAM, the loop could be initialized to download bytes directly into external memory. Since external RAM is typically much larger than internal RAM, very large
programs can be downloaded and run with this approach. Most commercial C166 monitors are downloaded in this manner.
If all FLASH programming routines would fit in a 896-byte block, we could have simply downloaded the routines and run them. Unfortunately, the 88C166 FLASH programming is a bit
more involved. Moreover, we would like our scheme to be versatile to accommodate downloading and running routines other than just those for FLASH programming. These considerations lead to the adoption of a standard way of loading and running programs. We will call these programs “applications.” This is typically the job of an operating system. So, by all practical means, we need to write an operating system for our internal-RAM-only operations. You may have noticed that in the bootstrap loop, a code size of 176 bytes is specified, much less than the 896-byte or so block available. This 176-byte code is actually a very small operating system.