Rabbit 2000™ Microprocessor Designer's Handbook

> ## 6. The Rabbit BIOS

> When Dynamic C compiles a user's program to a target board, the BIOS (Basic Input-Output System) is compiled first, as an integral part of the user's program. The BIOS is a separate program file that contains the code needed to interface with Dynamic C. It also normally contains a software interface to the user's particular hardware. Certain drivers in the Dynamic C libraries require BIOS routines to perform tasks that are hardware-dependent.The BIOS also:

> - Provides a variety of low-level services for the user's program.
> - Takes care of microprocessor system initialization.
> - Provides the communications services required by Dynamic C for downloading code and performing debugging services such as setting breakpoints or examining data variables.
> - Defines the setup of memory.

> A single, general-purpose BIOS is supplied with Dynamic C for the Rabbit. This BIOS will allow you to boot Dynamic C on any Rabbit-based system that follows the basic design rules needed to support Dynamic C. The BIOS requires both a flash memory and a 32K or larger RAM or just a 128K RAM for it to be possible to compile and run Dynamic C programs. If the user uses a flash memory from the list of flash memories that are already supported by the BIOS, the task will be simplified. If the flash memory chip is not already supported, the user will have to write a driver to perform the write operation on the flash memory. This is not difficult provided that a system with 128K of RAM and the flash memory to be used is available for testing.

> An existing BIOS can be used as a skeleton BIOS to create a new BIOS. Frequently it will only be necessary to change `#define` statements at the beginning of the BIOS. In this case it is unnecessary for the user to understand or work out the details of the memory setup and other processor initialization.

> ### 6.1 Startup Conditions Set Up By the BIOS

> The BIOS sets up initial values for the following registers by means of code and declarations.

> - The four memory bank control registers --`MB0CR`, `MB1CR`, `MB2CR`, and `MB3CR`--are 8-bit registers, each associated with one quadrant of the 1M memory space. Each register determines which memory chip will be mapped into its quadrant, how many wait states will be used for accessing that memory chip, and whether the memory chip will be write protected.
> - The `STACKSEG` register is an 8-bit register that determines the location of the stack segment in the 1M memory.
> - The `DATASEG` register is an 8-bit register that determines the location of the data segment in the 1M memory, normally the location of the data variable space.
> - The `SEGSIZ` E register is an 8-bit register holding two 4-bit registers. Together the registers determine the relative size of the base segment, data segment and stack segment in the 64K root space.
> - The `MMIDR` register is an 8-bit register used to force /CS1 to be always enabled or not. Having CS1 always enabled reduces power consumption.
> - The `XPC` register is used to address extended memory. Normally the user's code frequently changes this register. The BIOS sets the initial value.
> - The `SP` register is the system stack pointer. It is frequently changed by the user's code. The BIOS sets up an initial value.

> All together there are 11 `MMU`, `MIU` registers that are set up by the BIOS. These registers determine all aspects of the hardware setup of the memory.

> In addition, a number of origin declarations are made in the BIOS to tell the Dynamic C compiler where to place different types of code and data. The compiler maintains a number of assembly counters that it uses to place or allocate root code, extended code, data constants, data variables, and extended data variables. Each of these counters has a starting location and a block size.

> ### 6.2 BIOS Flowchart

> The following flowchart summarizes the functionality of the BIOS:

> Figure 11. BIOS Flowchart

> ### 6.3 Internally Defined Macros

> Some macros used in the BIOS are defined internally by Dynamic C before the BIOS is compiled. They are defined using tests done in the bootstrap loading, or by reading variables set in the GUI. These are:

> `_FLASH_, _RAM_` - Used for conditional compilation of the BIOS to distinguish between compiling to RAM and compiling to flash. These are set in the Options | Compiler dialog box.

> `_RAM_SIZE_, _FLASH_SIZE_` - Used to set the MMU registers and code and data sizes available to the compiler. The values given by these macros represent the number of 0x1000 blocks of memory available.

> `_BOARD_TYPE_` - This is read from the System ID block or defaulted to 0x100 (the BL1810 JackRabbit board) if no System ID block is present. This can be used for conditional compilation based on board type.

> ### 6.4 Modifying the BIOS

> The BIOS can be modified to be more specific concerning the user's configuration. This can be done one step at a time, making it easy to detect any problems. The source code for the Universal BIOS is in `BIOS\RABBITBIOS.C`. Dynamic C uses this source code for the BIOS by default, but the user can specify another BIOS for Dynamic C to use in the Options | Compiler dialog box.

> There are several macros at the top of `RABBITBIOS.C` that users may want to modify for boards they design or for special situations involving off-the-shelf Rabbit-based boards. Not all of the macros at the top of the BIOS are described here.

> #### USE115KBAUD

> The default value of 1 specifies that Dynamic C will communicate at 115,200 baud with the target. If this macro is set to zero, Dynamic C will communicate at 57,600 baud. The lower baud rate might be needed on some PCs that can not handle 115,200 baud. If `USE115KBAUD` is changed to zero, the baud rate should be changed to 57,600 in the Dynamic C Options | Communications dialog box. Starting with Dynamic C 7.05, `USE115KBAUD` is not available to change the baud rate, simply choose the baud rate in Options | Communications.

> #### CLOCK_DOUBLED

> The default value of 1 causes the clock speed to be doubled if the crystal speed is less than or equal to 12.9 MHz. Setting this to zero means the clock speed will not be doubled.

> #### ENABLE_CLONING

> The default value of 0 disables cloning. Setting this to 1 enables cloning and slightly increases the code size of the BIOS. If cloning is used, PB1 should be pulled up with 50K or so pull up resistor. Various cloning options are available when `ENABLE_CLONING` is set to one. For more information on cloning, please see Chapter 8, "BIOS Support for Program Cloning,"in this manual and/or Technical Note 207, Rabbit 2000 Cloning Board, which is available at rabbitsemiconductor.com.

> #### DATAORG

> Beginning logical address for the data segment. The default is 0x6000. This should only be changed to multiples of 0x1000. Increasing it increases the root code space available, and decreases root data space; decreasing it has the opposite effect. It can be changed to as low as 0x3000 or as high as 0xB000.

> #### RAM_SIZE

> This macro sets the amount of RAM available. The default value is the internally defined `_RAM_SIZE_` The units are the number of 4k pages of RAM. In special situations, such as splitting RAM between two coresident programs, this may be modified to a smaller value than the actual available RAM.

> #### FLASH_SIZE

> This macro sets the amount of flash available. The default value is the internally defined `_FLASH_SIZE_` The units are the number of 4k pages of flash. In special situations, such as splitting flash between two coresident programs, this may be modified to a smaller value than the actual available flash.

> #### CS1_ALWAYS_ON

> Keeping CS1 active is useful if your system is pushing the limits of RAM access time. It will increase power consumption a little. Set to 0 to disable, 1 to enable

> #### WATCHCODESIZE

> These define the number of bytes available to the debugger for compiling watch expression. The default values are 0x200/0x060. Decreasing these increases the amount of RAM available for root data.

> #### NUM_RAM_WAITST, NUM_FLASH_WAITST

> These define the number of wait states to be used for RAM and flash. The default value for both is 0. The only valid values are 4, 2, 1 and 0.

> #### MB0CR_INVRT_A18, MB1CR_INVRT_A18, MB2CR_INVRT_A18, MB3CR_INVRT_A18
> MB0CR_INVRT_A19, MB1CR_INVRT_A19, MB2CR_INVRT_A19, MB3CR_INVRT_A19

> These determine whether the `MIU` registers for each quadrant are set up to invert address lines A18 and A19 after the logical to physical address conversion. This allows each 256K quadrant of physical memory access up to four 256k pages on the actual memory device. These would be used for special compilations of programs to be coresident on flashes between 512k and 1M in size. See application note 202, Rabbit Memory Management In a Nutshell, and application note 210, Running Two Application on a TCP/IP Development Board for more details.

> See the top of the BIOS source code (\BIOS\`RabbitBIOS.c`) for more options.

> ### 6.5 Origin Statements to the Compiler

> The Dynamic C compiler uses the information provided by origin statements to decide where to place code and data in both logical and physical memory. The origin statements are normally defined in the BIOS; however, they may also be useful in an application program for certain tasks such as compiling a pilot BIOS or cold loader, or special situations where a user wants two application coresident within a single 256K quadrant of flash.

> #### 6.5.1 Origin Statement Syntax

> Prior to Dynamic C 7.05, origin statement syntax is:

>     #<origin type> <origin name> <segment value> <logical address> <size> apply

> All arguments are required.

> Starting with Dynamic C 7.05, origin statement syntax (in BNF) is:

> origin-directive : #origin-type identifier origin-designator

> origin-designator : action-expression | origin-declaration

> origin-declaration : physical-address size [follow-expression][action-expression][debug-expression]

> origin-type: `rcodorg` | `xcodorg` | `wcodorg` | `rvarorg`

> follow-expression : `follows` identifier `[splitbin]`

> action-expression : `resume` | `apply`

> debug-expression : `debug` | `nodebug` | `all`

> size : constant-expression

> physical-address : constant-expression constant-expression

> The non-terminals, identifier and constant-expressions, are defined in the ANSI C specification.

> #### 6.5.2 Origin Statement Semantics

> An origin statement associates a code pointer and a memory region with a particular type of code. The type of code is specified by #origin-type.

> All code sections (`rcodorg`, `xcodorg` code and `wcodorg`) grow up. All non-constant data sections (`rvarorg`) grow down. Root constants are generated to the `rcodorg` region. `xdata` and `xstring` are generated to the current `xcodorg` region.

> All origin statements must have a unique ANSI C identifier. The scope of this identifier is only with other origin statements or declarations. In the pre 7.05 syntax this is the `<origin name>`.

> Each memory region is defined by calculating a physical address from an 8-bit base address (first constant-expression of physical-address) and a 16-bit logical address (second constant-expression of physical-address). The size of the memory region is determined by 20-bit size. Overflow of these three values is truncated. In the pre 7.05 syntax these three values are `<segment value>`,`<logical address>` and `<size>`.

> The keywords `apply` and `resume` are action-expressions. They tell the compiler to generate code or data in the memory region specified by identifier. An `apply` action resets the code or data pointer for the specified region to the starting physical address of the region and makes the region active. A `resume` action does not reset the code or data pointer, but does make the memory region active.

> A region remains active (i.e., the compiler will continue to generate code or data to it) until another region of the same origin-type is activated with an `apply` or `resume` action or until the memory region is full.

> The option follow-expression is best described with an example. First, let us declare `yourcode` in an origin statement containing an origin-declaration. A follow-expression can only name a region that has already been declared in an origin-declaration.

>     #rcodorg yourcode 0x0 0x5000 0x500

> then the origin statement:

>     #rcodorg mycode 0x0 0x5500 0x500 follows yourcode

> tells the compiler to activate `mycode` when `yourcode` is full. This action does an implicit `resume` on the memory region identified by `yourcode`. In this example, the implicit `resume` also generates a jump to `mycode` when `yourcode` is full. For data regions, the data that would overflow the region is moved to the region that follows. Combined data and code regions (like `#rcodorg`) use both methods, which one is used depends on whether code or data caused the region to overflow. In our example, if data caused `yourcode` to overflow, the data would be written to the memory region identified by `mycode`.

> Furthermore, a follow-expression may specify that when the code or data resumes at the next region it should generate a separate bin file. This option is designed to support burning multiple flash or EPROM devices. The binary files generated share the same base name as the original file, but appended with a number which is followed by the .bin extension. For example, if `hello.c`, a large program that spans both flash chips, is compiled to file with the `splitbin` option on, `hello1.bin` and `hello2.bin` will be generated. Obviously, this option is only meaningful when compiling to a file.

> The optional debug-expression is only valid with the `xcodorg` origin-type. It tells the compiler to generate only `debug` or `nodebug` code in that physical memory region. If debug-expression is not specified, the declaration is treated as an `all` region. An `all` region can have both `debug` and `nodebug` code. Activating an `all` region (by using `apply` or `resume`) will cause both `debug` and `nodebug` regions to become inactive. If an `all` region is active, both `debug` and `nodebug` regions must be made active to entirely deactivate the `all` region. In other words, if an `all` region is active and a `debug` region is activated, any `nodebug` code will still be generated to the `all` region until a `nodebug` region is made active.

> With regard to follow-expressions, a `debug` region may not follow a `nodebug` region or vice versa. An `all` region may follow either a `debug` or a `nodebug` region. Only an `all` region may follow another `all` region. This allows `debug` and `nodebug` regions to spill into a common `all` region.

> #### 6.5.3 Origin Statement Examples

> The diagram below shows how the origin statements define the mapping between the logical and physical address spaces.

>     #define DATASEGVAL 0x91
>     #rvarorg rootdata  (DATASEGVAL) 0xc5ff 0x6600  apply // grows down
>     #rcodorg rootcode  0x00         0x0000 0x6000  apply
>     #wcodorg watcode   (DATASEGVAL) 0xc600 0x0400  apply
>     #xcodorg xmemcode  0xf8         0xe000 0x1a000 apply
>     // data declarations start here

> Dynamic C defines macros that include information about compiling to RAM or flash and identifying memory device types, memory sizes, and board type. The origin setup shown above differs from that included in the standard BIOS included with Dynamic C as the standard BIOS uses additional macros values for dealing with a wider range of boards and memory device types.

> #### 6.5.4 Origin Directives in Program Code

> To place programs in different places in root memory or to compile a boot strapping program, such as a pilot BIOS or cold loader, origin statements may be used in the user's program code.

> For example, the first line of a pilot BIOS program, `pilot.c`, would be

>     #rcodorg rootcode 0x0 0x0 0x6000 apply

> A program with such an origin directive could only be compiled to a .bin file, because compiling it to the target would overwrite the running BIOS.

Rabbit Semiconductor Corporation http://www.rabbitsemiconductor.com Voice: (530) 757-8400 Fax: (530) 757-8402