<< Previous | Index | Next >> | |
|
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.
- Takes care of microprocessor system initialization, such as the setup of memory.
- Provides the communications services required by Dynamic C for downloading code and performing debugging services such as setting breakpoints or examining data variables.
- Provides flash drivers.
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 inLIB\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
, andMB3CR
. 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:
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).
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 definingCL_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 inLib/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 inmemory_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
flashabove phy
ORG_FLASH_STARTsize
ORG_FLASH_SIZEThe 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_blockin
flashbelow end size
MAX_USERBLOCK_SIZEThe 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
ramabove phy
ORG_RAM_STARTsize
ORG_RAM_SIZETraditional 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
xmemcodein
flashabove start to
user_blockDefining 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
rootcodein
xmemcodeabove start log
0size
ROOTCODE_SIZEThe 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
rootdatain
ramabove start log
ROOTCODE_SIZEsize
ROOTDATA_SIZEThe 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
watcodein
rootdatabelow end size
WATCHCODESIZEThe 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
xmemdatain
ramabove
rootdatato
userdata_buffThe 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.)
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 | end6.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.
<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
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 root code
rcodorg
xmem code
xcodorg
watch code
wcodorg
watch code
wvarorg
root data
rvarorg
root constants
rconorg
All code sections (
rcodorg
,xcodorg
code andwcodorg
) grow up. All non-constant data sections (rvarorg
) grow down. Root constants are generated to thercodorg
region when separate I&D space is disabled. When separate I&D space is enabled, root constants are generated to therconorg
region.xdata
andxstring
are generated to the currentxcodorg
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
andresume
are action-qualifiers. They tell the compiler to generate code or data in the memory region specified by identifier. Anapply
action resets the code or data pointer for the specified region to the starting physical address of the region and makes the region active. Aresume
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
orresume
action or until the memory region is full.6.5.2.4 I&D Qualifiers
The
ispace
anddspace
qualifiers suppress compiler warnings regarding collisions between the two logical regions and the physical memory space. When anispace
ordspace
qualifier is used in an origin directive, that directive is no longer collision checked against origin directives in the other space. For example, arcodorg
directive with theispace
qualifier is not checked against any origin directives with adspace
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
#xcodorg mycode 0x0 0x5500 0x500 follows yourcode
tells the compiler to activate
mycode
whenyourcode
is full. This action does an implicitresume
on the memory region identified byyourcode
. In this example, the implicitresume
also generates a jump tomycode
whenyourcode
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 causedyourcode
to overflow, the data would be written to the memory region identified bymycode
.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 byxalloc()
.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
#endifThis 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 |