<< Previous | Index | Next >>

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 comprises files that contain the code needed by the user program to interface with Dynamic C and the Rabbit hardware. The BIOS may also contain a software interface to the user's particular hardware. Certain drivers in the Dynamic C library suite require BIOS routines to perform tasks that are hardware-dependent.

The BIOS also:

The file RabbitBIOS.c is a wrapper that permits a choice of which BIOS to compile. A more modular design has been implemented by moving many of the configuration macros to separate configuration libraries. The main BIOS file (Stdbios.c) and the multiple configuration libraries are located in LIB\Rabbit4000\BIOSLIB.

Dynamic C 10.21 introduces a change in the BIOS files: Origin declarations have been redesigned. One of the most dramatic results of the redesign is the ability to define relative relationships between origins during the setup of memory. This eliminates many of the macro definitions that were necessary before.

The supplied BIOS allows Dynamic C to boot up on any Rabbit-based system that follows the basic design rules needed to support Dynamic C. The BIOS requires either a 128 KB RAM or both a flash device and a 32 KB or larger 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. A list of supported flash devices is listed in Technical Note 226, available online at:

rabbit.com/docs/app_tech_notes.shtml

If the flash device 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 128 KB of RAM and the flash memory to be used are available for testing.

An existing BIOS can be used as a skeleton to create a new BIOS. Frequently it will only be necessary to change #define statements at the beginning of the file. In this case it is unnecessary for the designer to understand or work out the details of the memory setup and other processor initialization tasks. Refer to the Dynamic C User's Manual for details on creating a user-defined BIOS.

6.1 Startup Conditions Set by the BIOS

The BIOS performs initialization tasks and #use's library files that contain setup information.

6.1.1 Registers Initialized in the BIOS

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

MBxCR

There are four memory bank control registers: MB0CR, MB1CR, MB2CR, and MB3CR. They are 8-bit registers, each one associated with a quadrant of the physical memory space. A memory bank control register determines which memory chip is 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.

MECR

8-bit register that determines the quadrant size and thus the size of the physical address space.

STACKSEG(H/L)

16-bit register that determines the location of the stack segment in the physical memory space.

DATASEG(H/L)

16-bit register that determines the location of the data segment in the physical memory space, normally the location of the data variable space.

SEGSIZE

8-bit register holding two 4-bit values. Together the values determine the relative sizes of the base segment, data segment and stack segment in the 64 KB logical memory space.

MMIDR

8-bit register used to control separate I&D space and to force /CS1 to be always enabled or not. Having /CS1 always enabled reduces access time if /CS1 is routed through an external battery backup device and the propagation delay through the external device may slow the transition of /CS1 during memory cycles.

SP

The SP register is the system stack pointer. It is frequently changed by the user's code. The BIOS sets up an initial value.

6.1.2 Origins

Dynamic C uses a mechanism known as an "origin" to define regions of memory for different purposes. The BIOS declares several origins to tell the Dynamic C compiler where to place different types of code and data. Starting with Dynamic C 10.21 the origin directives are in the library file memory_layout.lib, which is #use'd in the BIOS.

For more information about the MMU and MIU registers please see the Rabbit 4000 Microprocessor User's Manual.

6.2 BIOS Flowchart

The following flowchart summarizes the functionality of the BIOS:

Figure 6-1 BIOS Flowchart
NOTE: To use the diagnostic port on the RCM43xx, you must first reset the board and then plug in the "Diag" header of the programming cable.
NOTE: If the programming cable is connected at power-up, the Rabbit will never execute the BIOS, since the cable holds the board in coldboot mode.

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 or set by the CLC (command line compiler).

Table 6-1 Partial List of Compiler-Defined Macros
Macro Name
Macro Description

_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.

CC_VER
Gives the Dynamic C version in hex, i.e., version 10.21 is 0x0A21.

_CPU_ID_
This macro identifies the CPU type, e.g., R4000 is the Rabbit 4000 microprocessor.

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

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

__SEPARATE_INST_DATA__
Flag for identifying whether separate I&D space is enabled or disabled.

FLASH_COMPILE, RAM_COMPILE, FAST_RAM_COMPILE
Used to determine compile mode in code.

See the Dynamic C User's Manual for other internally-defined macros.

6.4 Modifying the BIOS

The BIOS that is supplied with Dynamic C may be modified or replaced. Prudence demands that any changes made to this important piece of software be done one step at a time in order to more easily detect and isolate any problems that may arise.

RabbitBios.c is still used, but is more of a wrapper file that brings in some configuration and definition files, checks a few error conditions and then, before starting compilation of the application, selects which BIOS file to activate. The default BIOS is \Lib\Rabbit4000\BIOSLIB\StdBios.c.

6.4.1 Macros that Affect the BIOS

There are several macros that may be modified for custom-designed boards or for special situations involving off-the-shelf Rabbit 4000-based boards. The following list is not exhaustive.

CLOCK_DOUBLED

Default value of 1 causes the clock speed to be doubled. Setting this to zero means the clock speed will not be doubled.

To override the default, define CLOCK_DOUBLED to zero in the project by using the Defines tab of the Project Options dialog.

CS1_ALWAYS_ON

Default value of 0 disables the feature of keeping /CS1 always active.

To override the default, define CS1_ALWAYS_ON to 1 in the project by using the Defines tab of the Project Options dialog. Keeping /CS1 always active is useful if your system is pushing the limits of RAM access time. It will increase power consumption a little.

DATAORG

This macro is deprecated. Use ROOT_SIZE_4K instead.

ROOT_SIZE_4K

This macro defines the number of 4 kilobyte pages used for the base segment. The default is 3 when separate I&D space is enabled, and 6 otherwise.

To override the default, define ROOT_SIZE_4K in the project by using the Defines tab of the Project Options dialog. Increasing this value increases the size of root constants when separate I&D space is enabled, and root code when it is disabled.The sum of available root and data is constant, such that increasing one decreases the other. This macro can be changed to as high as 11 and as low as 1 when separate I&D space is enabled or as low as 3 when separate I&D space is disabled.

ENABLE_CLONING

Default value of 0 disables cloning.

To override the default, define ENABLE_CLONING to 1 in the project by using the Defines tab of the Project Options dialog. This slightly increases the code size of the BIOS.

If cloning is used, PB1 should be pulled up with 50K or so pull-up resistor. On some Rabbit core modules, such as the RCM4200, the PB1 (CLKA) signal is either not available or not pulled up on the programming port. The master can be forced to invoke cloning support by setting CL_FORCE_MASTER_MODE to 1. This will cause the BIOS to assume a cloning cable is attached on every startup, assuring that only the cloning code will run. Note that defining CL_FORCE_MASTER_MODE to 1 will not allow the program on the board to run, that is, the board will act only as a clone master.

While compiling to the target with CL_FORCE_MASTER_MODE set to 1, the loss of target communication is expected and unavoidable. After the program has loaded and target communication is lost the clone master will still correctly perform its cloning function after a cloning cable is attached.

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 Cloning Board," available at rabbit.com.

FLASH_SIZE

Sets the amount of flash available. The default value is the internally defined _FLASH_SIZE_ The units are the number of 4 KB 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.

RAM_SIZE

Sets the amount of RAM available. The default value is the internally defined _RAM_SIZE_. The units are the number of 4 KB 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.

USE_TIMERA_PRESCALE
Uncomment this macro in Lib/Rabbit4000/BIOSLIB/sysconfig.c to run the peripheral clock at the same frequency as the CPU clock instead of the standard "CPU clock/2." This allows higher baud rates if Timer A is used as the baud rate generator. USE_TIMERA_PRESCALE affects the resolution of the PWM, Input Capture and Quadrature Decoder systems.
USE_2NDFLASH_CODE

Uncomment this macro in Lib/Rabbit4000/BIOSLIB/sysconfig.c only if you have a a board with two flash devices, and you want to use the second flash for extra code space.

WATCHCODESIZE

This macro defines the size in bytes of the region used for interrupt vectors, debug kernel special variables, and watch expressions. This macro must only be set to 0x800 or 0x1000 if the debug kernel is enabled, and can be set to 0x400 otherwise.

To override the default, change its value in Lib/Rabbit4000/BIOSLIB/StdBios.c.

6.4.2 Advanced Options

The following macros are defined in STDBIOS.c. See the top of the BIOS source code and/or the various configuration libraries for more options.

ENABLE_SPREADER

Default value is 1, which enables the clock spectrum spreader in normal mode to reduce EMI.

To override the default, define ENABLE_SPREADER in the project by using the Defines tab of the Project Options dialog. Define the macro to 0 to disable spectrum spreading and to 2 for strong spreading.

NUM_RAM_WAITST,NUM_RAM2_WAITST, NUM_FLASH_WAITST

These macros are defined in boardtypes.lib. They define the number of wait states to be used for read access to RAM and flash. Write access requires one more wait state than read access. These macros are used to determine the relevant bit values in the memory bank control registers.

The only valid values for these wait state macros are 4, 2, 1 and 0.

MBxCR_INVRT_A18, MBxCR_INVRT_A19

These macros 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 quadrant of physical memory access up to four 256 KB pages on the actual memory device. These would be used for special compilations of programs to be coresident on flashes between 512 KB and 1 MB in size. For more information, please see Technical Note 202, "Rabbit Memory Management In a Nutshell."

6.5 Memory Mapping in Dynamic C

The Dynamic C compiler uses the information provided by origin directives to decide where to place code and data in both logical and physical memory. The term "origin" is the mechanism by which a memory region is initially described. Dynamic C version 10.21 introduces a greatly improved version of the origin directives. The newer version of origin directives is described in Section 6.5.1 and the older version is described in Section 6.5.2.

Origin directives allow the programmer to tell the compiler where devices should be mapped in the Rabbit processor memory space. The origins are further used to describe what each device is and what properties these devices may have. Although origins are normally defined in the BIOS or one of its configuration libraries, they may also be useful in an application program for certain tasks, such as compiling a pilot BIOS or a cold loader, or special situations where a user wants two applications coresident within a single 256K quadrant of flash. See Technical Note 218, "Implementing a Serial Download Manager for a 256K Byte Flash," for more information on the later. This document is available at:
rabbit.com/docs/app_tech_notes.shtml.

6.5.1 Origins Starting with Dynamic C 10.21

The origin directives are all collected in a single library, memory_layout.lib, which is #use'd in the BIOS. The origins are arranged as a hierarchy of child and parent "origins" (memory regions) with a common parent called the "root" origin, which is essentially an abstract representation of all memory. The root origin is never explicitly defined, but any origin declaration not having a named parent origin is a child of the root origin.

The hierarchical arrangement provides a mechanism by which child origins recursively inherit the properties of their parent origins. This allows for better error checking of the memory mapping itself, since the compiler can check that a data origin is not defined in a region mapped as flash memory, for example. The example in Section 6.5.1.1 illustrates this functionality.

In addition to the inheritable properties, the origin directives use relative memory mapping. Relative memory mapping allows for more flexible descriptions of memory configurations, since the syntax allows rules to be enforced on the placement of particular regions of memory with respect to one another without having to account for the actual boundaries of those regions.

6.5.1.1 Example of Origin Declarations

The code from memory_layout.lib provides a practical application of origins. In this section, several of the origin declarations in the memory layout library are explained. (To simplify matters, the conditional compilation macros regarding board type, compile mode and separate I&D settings in memory_layout.lib are not shown in this example.) A graphical representation of the regions defined by the origin declarations follows their explanation (see Figure 6-2).

The origin declaration syntax and semantics used in the following example are explicitly defined in Section 6.5.1.2 and Section 6.5.1.3, respectively.

The origin declarations shown below were taken from memory_layout.lib in Dynamic C 10.21. This library may change in future releases of Dynamic C.


// Macros to help declare origins
#define ORG_FLASH_SIZE (_FLASH_SIZE_*0x1000UL)
#define ORG_RAM_SIZE (_RAM_SIZE_*0x1000UL)

The macros _FLASH_SIZE_ and _RAM_SIZE_ are the number of 0x1000 (4 KB) blocks of memory available for Flash and RAM, respectively.


// In flash compile mode, the flash is always mapped at address 0x0
#define ORG_FLASH_START (0x0)
#define ORG_RAM_START (RAM_START*0x1000UL)

RAM_START is currently defined in the main BIOS file, StdBios.lib.


#orgdef flashorg flash above phy ORG_FLASH_START size ORG_FLASH_SIZE

The above line defines the flash device mapping. All origin definitions start with the compiler directive "#orgdef". Note that the origin type is "flashorg", and the origin has the user-defined name "flash". The flashorg origin type has the property of being non-volatile. The syntax "above phy ORG_FLASH_START" indicates that the origin is a child of the root origin starting at the physical address defined by the macro ORG_FLASH_START. The final piece "size FLASH_SIZE" defines the size of the flash region (this is often the size of the device for flashorg and ramorg origin types).


#orgdef resvorg user_block in flash below end size MAX_USERBLOCK_SIZE

The above line defines the user block space as an origin called "user_block". The type "resvorg" indicates that the region is a reserved origin that should not be touched by the compiler. The syntax "in flash" makes the origin a child of the origin named "flash", defined previously. Following the inheritance, "below end" indicates that the origin should be at the end of its parent (in this case, the origin called "flash"). The region has size MAX_USERBLOCK_SIZE.


#orgdef bbramorg ram above phy ORG_RAM_START size ORG_RAM_SIZE

Traditional Rabbit memory configurations have a primary SRAM device that is also battery-backed. This line defines the primary RAM device as a battery-backed RAM origin ("bbramorg" origin type) with the name "ram". The origin is a child of the root origin, starts at the physical address ORG_RAM_START, and has size ORG_RAM_SIZE.


#orgdef xcodorg xmemcode in flash above start to user_block

Defining origins for the physical memory devices in a particular configuration is not enough for the compiler, so we need to define regions for code and data. The line above defines an origin for xmem code with "xcodorg" origin type, and called "xmemcode". The compiler knows to use this origin for xmem code because of the origin type. Note that xmemcode is a child of the origin "flash", so it not only has the property of being a code region, but it is also non-volatile since it inherits that property from its parent "flash".

The final bit of syntax, "above start to user_block" means that the origin region starts at the beginning of its parent and extends to the beginning of the sibling "user_block" origin region. The "to" syntax allows the origin definition to remain unchanged even if the parent origin changes. A "to" terminal in an origin definition can also be followed by the syntax "end" to indicate that the region should occupy the entire parent origin region (this is useful for organizational purposes).


#orgdef rcodorg rootcode in xmemcode above start log 0 size ROOTCODE_SIZE

The xmem code origin is defined above to take up the entire flash device other than the small space reserved for the user block. The reason for this is that we want to be able to put xmem code anywhere in the flash device. However, we also need root code for the segmented addressing the Rabbit provides. The line above defines the "rootcode" origin to be a child of the "xmemcode" region. This is legal because root code addresses can also be used for xmem code (all root addresses have a corresponding physical address). The origin starts at the beginning of "xmemcode", but notice the addition of "log 0", for "logical 0".

The origin type for "rootcode" is rcodorg, a logical origin. This means that "rootcode" can be accessed through logical addresses, so the compiler needs to know where it is situated in logical memory, i.e., the origin needs a starting logical address. In this case, it starts at logical address "0".


#orgdef rvarorg rootdata in ram above start log ROOTCODE_SIZE size ROOTDATA_SIZE

The origin named "rootdata" is a child of "ram" and as such inherits the property of being battery- backed. The origin starts at the beginning of "ram", and has size ROOTDATA_SIZE. It is a logical origin; its starting logical address is ROOTCODE_SIZE, a macro defined in the BIOS.


#orgdef wcodorg watcode in rootdata below end size WATCHCODESIZE

The origin named "watcode" is a child of "rootdata" and as such is also of logical origin type. Its starting logical address is not explicitly stated, but can be determined from the parent origin's logical extents. Following the inheritance, "below end" indicates that the origin should be at the end of its parent "rootdata", with size WATCHCODESIZE. This information is used to determine the starting logical address: We know that the starting logical address of the parent "rootdata" is ROOTCODE_SIZE. The logical addresses for child origins necessarily must be relative to their parents. In this case, that means that the starting logical address for "watcode" is then, ROOTCODE_SIZE + ROOTDATA_SIZE - WATCHCODESIZE.


#orgdef xvarorg xmemdata in ram above rootdata to userdata_buff

The origin named "xmemdata" is a child of "ram" and as such inherits the property of being battery- backed. The origin starts where its sibling origin "rootdata" ends; therefore, it starts at ORG_RAM_START+ROOTDATA_SIZE. "xmemdata" extends to the beginning of "userdata_buff". (The declaration for the origin named "userdata_buff" is in memory_layout.lib along with the declarations for several other regions needed for buffers. For simplicity's sake, none of them are shown here and they are not reflected in Figure 6-2.)

Figure 6-2 Origins from memory_layout.lib

Each origin declaration adds a little more to the overall mapping. We recommend reading the code in memory_layout.lib and drawing memory maps like the one in Figure 6-2. This exercise will help to further your understanding of the complex topic of memory mapping.

6.5.1.2 Origin Declaration Syntax

Following is an EBNF (Extended Backus Naur Form) representation of the origin grammar facets: declarations, actions, and macros. Angle brackets ("<" and ">") indicate non-terminals while terminals are represented literally with these exceptions: the "|" symbol represents a disjunction, the "::=" represents a definition, and the "[" and "]" symbols are used to enclose optional synatx.

     
<decl> ::= #orgdef <type> <name> [in <name>] <vector> <size> [locate <int>]
<type> ::= <phy_org> | <log_org> | wcodorg | resvorg
<phy_org> ::= flashorg | bbramorg | fastramorg | xconorg | xcodorg | xvarorg | xmemorg
<log_org> ::= rconorg | rcodorg | rvarorg
<vector> ::= below <offset> | above <offset>
<offset> ::= <position> [ log <int>] | <name> [ log <int> ]
<position> ::= phy <int> | start | end
<size> ::= size <int> | to <offset>
// Origin declaration start and end syntax
<start> ::= #orgstart
<end> ::= #orgend
// Origin application syntax
<orguse>    ::= orgact <name> <action>
<action>    ::= apply | resume
// Origin macro declaration syntax
<macdef>    ::= #orgmac <define>
<define>    ::= <name> = <orgval>
<orgval>    ::= <name> [ <int> ] [ <boundary> ] <aspect>
<aspect>    ::= <quality> <position> | size | fragments
<quality>   ::= physical | logical | segment
<position>  ::= start | end

6.5.1.3 Origin Declaration Semantics

The formal semantics of the origin declaration syntax are explained in this section.

<decl>

The non-terminal "decl" represents an origin declaration. All origin declarations begin with "#orgdef".

<type>

The non-terminal "type" represents two subcategories of origins: physical origins and logical origins. Physical origins do not require a logical beginning and ending address because they are not accessed through logical addresses, or if they are, then through the xmem window, which is fixed. This distinction has no obvious effect on the grammar as it is written, but influences a semantic restriction discussed later.

Physical origins are represented by the phy_org non-terminal and logical origins by log_org. The origin types "wcodorg" and "resvorg" are exceptional because they may be either physical or logical.

Table 6-2 Origin Type Descriptions
Origin Type Keyword
Description
flashorg
Used for mapping flash; non-volatile.
bbramorg
Used for mapping RAM; battery-backed.
fastramorg
Used for mapping fast RAM.
xconorg
Used for mapping xmem constants.
xcodorg
Used for mapping xmem code
xvarorg
Used for mapping xmem data.
xmemorg
Reserved for future use.
rconorg
Used for mapping root constants.
rcodorg
Used for mapping root code.
rvarorg
Used for mapping root data.
wcodorg
Used for mapping watch code.
resvorg
Reserved origin, meaning that it will not be touched by the compiler.

<name>

The non-terminal "name," though not explicitly defined in the grammar, is equivalent to a C-style identifier (not in the C namespace) and denotes the name of the origin declared.

in

The terminal "in" denotes a new concept for declaring origins - the idea of a hierarchical organization, or parentage. Given y is a previously declared origin, stating x in y denotes that x is a child of y or that y is the parent of x. The name following "in" qualifier represents the identifier of a previously declared origin. We will use the terms 'parent', 'child' and 'sibling' when referring to relationships between origins. The principle uses of this concept are the creation of boundary dependence and the enforcement of natural boundary constraints. Much of the remaining syntax becomes very natural when following the implications of this concept.

Another key concept in the child-parent model of origin declarations is the notion that child origins remove space from their parents. The reason for this is that we are still modeling a linear memory space. The hierarchy is simply a way to organize the information in a dependent manner, which obviates the macro verbosity that was previously required by origin declarations. As shown in the examples above, each origin represents an entire space of a particular origin type. Child origins transfer space from their parents to themselves. The remaining space in the parent origin is fragmented automatically by the compiler. At the end of the origin declaration section, all that remains is a flattened map that represents the true layout of memory in the physical space.

<placement>

The non-terminal "placement" denotes the placement of an origin within a larger parent space relative to the beginning of that parent (in the absence of the "in" qualifier, the parent can be considered to be all of the physical memory or "root"). The "placement" non-terminal is either the "fill" terminal or the non-terminal <vector> followed by the non-terminal "size." The "vector" non-terminal is not a vector in the mathematical sense, but rather denotes a position and an orientation. An origin may be declared relative to the beginning or end of its parent or a sibling, and this placement determines its orientation. The orientation determines how other siblings may reference the origin; for example, if a child is placed at the end of a parent origin, no sibling origins may be declared "above" it.

<vector>

The non-terminal "vector" consists of the terminal "above" or the terminal "below" followed by an the non-terminal "offset." The declaration determines the meaning of offset: "above" indicates that the offset will be the lower boundary of the declared origin while "below" indicates that the offset will be the upper boundary.

<offset>

The non-terminal "offset" is either the non-terminal "position" or the non-terminal "name." A name must be the identifier of a previously declared sibling origin. When placing an origin "above" a sibling, the upper boundary of the reference origin is used as the lower boundary of the origin being declared. Similarly, when placing an origin "below" a sibling, the lower boundary of the reference origin is used as the upper boundary of the origin being declared.

<position>

A position can be either of the special terminals "start" or "end", or it can be a physical offset followed by an optional logical address. Though inessential to the grammar, the terminal symbols "phy" and "log" prevent accidental macro expansion problems and add clarity for inexperienced users. The physical offset is measured from the beginning of the parent origin. The logical address is required for origins of logical type that are declared relative to a physical origin, and are optional otherwise. It must be omitted if the declared origin is of physical type. The exceptional origin types "wcodorg" and "resvorg" may be declared with logical offsets, making them logical origins. In the absence of logical offsets, they will still be logical origins if declared as children of a logical origin. The terminals "start" and "end" indicate the lower and upper boundaries of the parent origin, respectively. In the absence of a parent origin, the extents are the physical addressable range defined by the MECR.

<size>

The non-terminal size is either the terminal symbol "size" followed by an integer or the symbol "to" followed by an integer. The integer following "size" specifies the number of bytes the origin contains. The "to" terminal indicates where the origin ends, in which case its size is the absolute value of the difference between the end and beginning of the origin. Note that since origins can be defined in terms of their lower or upper boundaries, "to" always specifies the complimentary boundary.

6.5.1.4 Origin Declaration Start and End Syntax

<start>

The non-terminal start is simply the terminal "#orgstart". It must occur exactly once and must occur before the end non-terminal. All origin declarations must follow this non-terminal.

<end>

The non-terminal end is simply the terminal "#orgend". It must occur exactly once and must occur after the start non-terminal. When the compiler encounters this non-terminal, it locks the definitions of the origins and performs final collision detection. All origin declarations must precede this non-terminal.

6.5.1.5 Origin Application Syntax

<orguse>

The orguse non-terminal specifies which region the compiler should use for the origin type corresponding to name. The name non-terminal must be a previously declared origin. All occurrences of orguse must follow orgend.

<action>

The action non-terminal specifies what action the compiler should take for the named origin and may be the terminal "apply" or "resume". The "apply" terminal signifies resetting the memory region, and should be used with care since the compiler may have already generated code or data to the origin. The "resume" terminal signifies switching to the origin with its state preserved before a previous orguse refocused the compiler's attention.

The terminals "apply" and "resume" have no effect on a region of type "xvarorg".

6.5.1.6 Origin Macro Declaration Syntax

<macdef>

The non-terminal macdef is the terminal "#orgdef" followed by the non-terminal define and signifies a macro declaration based on an attribute of a previously declared origin. Although the compiler does not force restrictions on where one may place a macdef, prudence dictates the placing them after orgend is the logical choice in most cases.

<define>

The define non-terminal represents the assignment of an origin attribute to a specific macro name. The non-terminal name must be a valid C macro identifier not previously declared. The orgval non-terminal represents an origin attribute as explained below.

<orgval>

An orgval is the non-terminal name, which must be a previously declared origin, followed by an optional non-negative integer, followed by the optional terminal "boundary", followed finally by the aspect non-terminal. The optional integer specifies an origin fragment if the given origin is fragmented, otherwise the compiler ignores it. A user must access fragments of an origin linearly as if they were elements of a C array. Thus, one accesses the first fragment through index zero, and so forth. The optional terminal "boundary" signals the compiler to return attributes that the origin had before it were fragmented or shortened by the declaration of any child origins.

<aspect>

The aspect non-terminal represents an individual aspect of an origin. This non-terminal may be one of three things. It may be the "size" terminal, in which case the compiler assigns the size of the origin in bytes to the macro. It may be the "fragments" terminal, wherein the compiler will assign the number of fragments within the origin to the macro. Lastly, it may be the non-terminal quality followed by position as explained below.

<quality>

This non-terminal specifies a quality of a particular boundary, and may be any of the terminal symbols "physical", "logical", or "segment". Each correspond to the physical address, logical address, and segment value respectively of the origin boundary in context. If the origin is not a logical origin, then the segment and logical terminals will represent the physical boundary converted to an xxx:Exxx address type.

<position>

The position non-terminal is either "start" or "end", and represents the beginning or end respectively of the origin in context.

6.5.2 Origins Prior to Dynamic C 10.21

The following grammar (in BNF) describes the syntax used for the declaration of origin statements prior to Dynamic C version 10.21.

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

origin-designator : action-expression | origin-declaration

origin-declaration : physical-address size [follow-qualifier][I&D-qualifier][action-qualifier] [debug-qualifier]

origin-type: rcodorg | xcodorg | wcodorg | wvarorg | rvarorg | rconorg

follow-qualifier : follows identifier [splitbin]

I&D-qualifier : ispace | dspace

action-qualifier : resume | apply

size : constant-expression

physical-address : constant-expression constant-expression

The non-terminals, identifier and constant-expression, are defined in the ANSI C specification. Basically, an identifier is a sequence of letters and digits that must start with a letter. The underscore character is considered a letter. The definition of constant-expression is more involved as it winds up the restricted subset of operators that are allowed in the evaluation of the expression, but the result is a constant. For a comphrensive definition of the non-terminals, identifier and constant-expression, please refer to Appendix A in "The C Programming Language" by Kernighan and Ritchie.

6.5.2.1 Origin Directive Semantics

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

Table 6-3 Origin Types Recognized by the Compiler
Origin Type
Keyword
root code

rcodorg        
xmem code

xcodorg
watch code

wcodorg
watch code

wvarorg
root data

rvarorg
root constants              

rconorg

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 when separate I&D space is disabled. When separate I&D space is enabled, root constants are generated to the rconorg region. xdata and xstring are generated to the current xcodorg region.

All origin directives must have a unique ANSI C identifier. The scope of this identifier is only with other origin directives or declarations.

6.5.2.2 Defining a Memory Region

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.

6.5.2.3 Action Qualifiers

The keywords apply and resume are action-qualifiers. 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.

6.5.2.4 I&D Qualifiers

The ispace and dspace qualifiers suppress compiler warnings regarding collisions between the two logical regions and the physical memory space. When an ispace or dspace qualifier is used in an origin directive, that directive is no longer collision checked against origin directives in the other space. For example, a rcodorg directive with the ispace qualifier is not checked against any origin directives with a dspace qualifier.

6.5.2.5 Follow Qualifiers

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

#xcodorg yourcode 0x0 0x5000 0x500

then the origin statement:

#xcodorg 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.

6.5.2.6 Origin Directive Examples

The diagram below shows how the origin directives 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 macro values for dealing with a wider range of boards and memory device types.

NOTE: This mapping assumes separate I&D space is disabled.

6.5.2.7 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 directives 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.

6.5.2.8 Origin Directive to Reserve Blocks of Memory

With the Rabbit 4000, the compiler generates an origin table that contains the blocks that are reserved for code and data origin or other non-xalloc use. With this change, the method of reserving a block of memory so that xalloc() does not use it has also changed. To reserve a block of memory in DC 9.30 and later, the #resvorg should be used. All other origins (e.g., #rcodorg, #rvarorg, etc.) are also tracked by the compiler and those blocks are entered into the origin table generated by the compiler so they are not used by xalloc().

The #resvorg is used as follows:

#resvorg <NAME> segment offset size [reserve]

For example, the following code would reserve the entire flash memory in flash compile mode

#resvorg flashmem 0x0 0x0 0x80000 reserve

The reserve keyword must be added to the end to reserve the entire block of memory.

Some applications may require that fixed regions of RAM be reserved for their own use. For example, you may want to reserve the upper half of a 512K RAM in Flash compile mode. To reserve this you need to add the following line of code to \LIB\BIOSLIB\STDBIOS.C just below the "#resvorg removeflash 0x0 0x0 0x80000 reserve."

#ifdef RESERVE_UPPER_RAM
#resvorg reserveupperram 0xC0 0x0 RESERVE_UPPER_RAM
batterybacked reserve
#endif

This tells the compiler to reserve RESERVE_UPPER_RAM bytes from physical address 0xC0000 by adding it to the origin table. This removes this memory block from the available xalloc memory.

In the Defines tab of the Options | Project Options dialog, enter the amount of memory you want to reserve. For example,

RESERVE_UPPER_RAM=0x40000

would reserve physical memory from 0xC0000-0xFFFFF and make it unavailable for xalloc. You can then access this memory directly from your program as follows:

     
main() {
long addr;
addr = 0xC0000; //
point to block reserved for my use
}

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