<< Previous | Index | Next >>

4. How Dynamic C Cold Boots the Target System

Dynamic C assumes that target controller boards using the Rabbit 4000 CPU have no pre-installed firmware. It takes advantage of the Rabbit 4000's bootstrap (cold boot) mode, which allows memory and I/O writes to take place over the programming port.

Figure 4-1 Rabbit Programming Port

The Rabbit programming cable is a smart cable with an active circuit board in its middle. The circuit board converts RS-232 voltage levels used by the PC serial port to CMOS voltage levels used by the Rabbit 4000. The level converter is powered from the power supply voltage present on the Rabbit 4000 programming connector. Plugging the programming cable into the Rabbit programming connector results in pulling the Rabbit 4000 SMODE0 and SMODE1 (startup mode) lines high. This causes the Rabbit 4000 to enter the cold boot mode after reset.

When the programming cable connects a PC serial port to the target controller board, the PC running Dynamic C is connected to the Rabbit 4000 as shown in the table below.

Table 4-1 Programming Port Connections
PC Serial Port Signal
Rabbit 4000 Signal
DTR (output) /RESET (input, reset system)
DSR (input) STATUS (general purpose output)
TX (serial output) RXA (serial input, port A)
RX (serial input) TXA (serial output, port A)

When Dynamic C cold boots the Rabbit 4000-based target system it assumes that no program is already installed on the target. The flash memory on the target system may be blank or it may contain any data. The cold boot capability permits the use of soldered-in flash memory on the target. Soldered-in memory eliminates sockets, boot blocks and PROM programming devices.

4.1 How the Cold Boot Mode Works In Detail

Cold boot works by receiving triplets of bytes that consist of a high address byte followed by a low address byte, followed by a data byte, and writing the data byte to either memory or I/O space. Cold boot mode is entered by having one or both of the SMODE pins pulled high when the Rabbit is reset. The pin settings determine the source of the incoming triplets:

SMODE1 = 0, SMODE0 = 1 cold boot from slave port.

SMODE1 = 1, SMODE0 = 0 cold boot from clocked serial port A.

SMODE1 = 1, SMODE0 = 1 cold boot from asynchronous serial port A at 2400 bps.

SMODE1 = 0, SMODE0 = 0 start normal execution at address zero.

The SMODE pins can be used as general input pins once the cold boot is complete.

On entering cold boot mode, the microprocessor starts executing a 12-byte program contained in an internal ROM. The program contains the following code.

     
; origin zero
00 ld l,n            ; n=0c0h for serial port A
                     ; n=020h for parallel (slave port)
02 ioi ld d,(hl)     ; get address most significant byte
04 ioi ld e,(hl)     ; get least significant byte
06 ioi ld a,(hl)     ; get data
08 ioi or nop        ; if the high bit of the MSB of the address is 1
                      ; (i.e., d[7] ==1) then ioi, else nop
09 ld (de),A         ; store in memory or I/O
10 jr 0              ; jump back to zero
; note wait states inserted at bytes 3, 5 and 7 waiting
; for serial port or parallel port ready

The function of the boot ROM program depends on the settings of the pins SMODE0 and SMODE1 and on whether the high bit of the high address byte (first byte of a received triplet) that is loaded to register D is set. If bit 7 of the high address byte is set, then the data byte (last byte of the triplet) is written to I/O space when received. If the bit is clear, then the data byte gets written to memory. Boot mode is terminated by storing 80h to I/O register 24h, which causes an instruction fetch to begin at address zero.

Wait states are automatically inserted during the fetching of bytes 3, 5 and 7 to wait for the serial or parallel port ready. The wait states continue indefinitely until the serial port is ready. This will cause the processor to be in the middle of an instruction fetch until the next character is ready. While the processor is in this state the chip select, but not the output enable, will be enabled if the memory mapping registers are such as to normally enable the chip select for the boot ROM address. The chip select will stay low for extended periods while the processor is waiting for the serial or parallel port data to be ready.

4.2 Program Loading Process Overview

On start up, Dynamic C first uses the PC's DTR line on the serial port to assert the Rabbit 4000 RESET line and put the processor in cold boot mode. Next, Dynamic C uses a four stage process to load a user program:

  1. Load an initial loader (cold loader) to RAM via triplets sent at 2400 baud from the PC to a target in cold boot mode.

  2. Run the initial loader and load a secondary loader (pilot BIOS) to RAM at 57600 baud.

  3. Run the secondary loader and load the BIOS and user program to flash after compiling them to a file, optionally negotiating with the Pilot BIOS to increase the baud rate to 115200 or higher so the loading can happen quickly.

  4. Run the BIOS. Then run and debug the user program at the baud rate selected in Dynamic C.
NOTE: Step 4 is combined with step 3 when using 4 K (or greater) sector flash.

4.2.1 Program Loading Process Details

When Dynamic C starts to compile a program, the following sequence of events takes place:

  1. The serial port is opened at 2400 baud with the DTR line high, and after a 500 ms delay, the DTR line is lowered. This pulses the reset line on the target low (the programming cable inverts the DTR line), placing the target into bootstrap mode.

  2. A group of triplets defined in the file COLDLOAD.BIN consisting of 2 address bytes and a data byte are sent to the target. The first few bytes sent are sent to I/O addresses to set up the MMU and MIU and do system initialization. The MMU is set up so that RAM is mapped to 0x00000, and flash is mapped to 0x80000.

  3. The remaining triplets place a small initial loader program at memory location 0x00000. The last triplet sent is 0x80, 0x24, 0x80, which tells the CPU to ignore the SMODE pins and start running code at address 0x00000.

  4. The initial loader measures the crystal speed to determine what divisor is needed to set a baud rate of 19200. The divisor is stored at address 0x3F02 for later use by the BIOS, and the programming port is set to 57600 baud.

  5. The PC now bumps the baud rate on the serial port being used to 57600 baud.

  6. The initial loader then reads 7 bytes from the serial port. First a 4-byte address field: the physical address to place the secondary loader, followed by a 2-byte length field: the number of bytes in the secondary loader. The 7th byte is a checksum (simple summation) of the previous 6 bytes. Whether or not the checksum matched, it is echoed back as an acknowledgement.

  7. The data segment is then mapped to the given physical location, using the DATASEG register. The data segment boundary will also be set to 0x6000, so the secondary loader will always be located at the same place in logical space, regardless of where it physically resides.

  8. The initial loader finally enters a loop where it receives the specified number of bytes that compose the secondary loader program (pilot.bin sent by the PC) and writes those bytes starting at 0x6000 (logical). The first byte sent this way MUST be 0xCC, as an indicator to the initial loader. This byte will be stored as 0x00 (nop), instead of 0xCC. A 2-byte checksum will be sent after the secondary loader has been received, using the 8-bit Fletcher Algorithm (see RFC1145 for details), such that the load can be verified. After all of the bytes are received, and the checksum has been sent, program execution jumps to 0x6000.

  9. The secondary loader does a wrap-around test to determine how much RAM is available, and reads the flash and CPU IDs. This information is made available for transmittal to Dynamic C when requested.

  10. The secondary loader now enters a finite state machine (FSM) that is used to implement the Dynamic C/Target Communications protocol. Dynamic C requests the CPU ID, flash ID, RAM size, and 19200 baud rate divisor to define internally defined constants and macros. Dynamic C uses the flash ID to lookup flash parameters that are sent back to the secondary loader so that it can initialize flash write/erase routines. At this stage, the compiler can request the baud rate be increased to a higher value. The secondary loader is now ready to load a BIOS and user program.

  11. Dynamic C now compiles the BIOS and user programs. Both are compiled to a file, then the file is loaded to the target using the Pilot BIOS' FSM. After the loading is complete, Dynamic C, using the Pilot BIOS' FSM, tells the Pilot BIOS to map flash to 0x00000, map RAM to 0x80000, and start program execution at 0x0000, thereby running the compiled BIOS.

  12. If the Pilot BIOS detects a RAM compile or small-sector flash that uses sector-write mode, Dynamic C uses a slightly different loading procedure. The BIOS will be compiled as normal, and loaded using the Pilot BIOS. After the BIOS is loaded, Dynamic C will tell the Pilot BIOS to start it, and the rest of the program will be loaded through the compiled BIOS.

  13. Once the compiled BIOS starts up, it runs some initialization code. This includes setting up the serial port for the debug baud rate (set in the Communications tab in Options | Project Options), setting up serial interrupts and starting the BIOS FSM. Dynamic C sets a breakpoint at the beginning of main() and runs the program up to the breakpoint. The board has been programmed, and Dynamic C is now in debug mode.

  14. If the programming cable is removed and the target board is reset, the user's program will start running automatically because the BIOS will check the SMODE pins to determine whether to run the user application or enter the debug kernel.

Rabbit 4000
Designer's Handbook
<< Previous | Index | Next>> rabbit.com