A keyword is a reserved word in C that represents a basic C construct. It cannot be used for any other purpose.
Used in single-user cofunctions, abandon{} must be the first statement in the body of the cofunction. The statements inside the curly braces will be executed only if the cofunction is forcibly abandoned and if a call to loophead() is made in main() before calling the single-user cofunction. See Samples\Cofunc\Cofaband.c for an example of abandonment handling.
for(;;){
costate {
...
if( condition ) abort;
}
...
}
Used in assembly blocks, the align keyword outputs a padding of nops so that the next instruction to be compiled is placed at the boundary based on VALUE.
#asm
...
align <VALUE>
...
#endasm
VALUE can have any (positive) integer expression or the special operands even and odd. The operand even aligns the instruction on an even address, and odd on an odd address. Integer expressions align on multiples of the value of the expression.
Some examples:
align odd ; This aligns on the next odd address
align 2 ; Aligns on a 16-bit (2-byte) boundary
align 4 ; Aligns on a 32-bit (4-byte) boundary
align 100h ; Aligns the code to the next address that is evenly divisible by 0x100
align sizeof(int)+4 ; Complex expression, involving sizeof and integer constant
Note that integer expressions are treated the same way as operand expressions for other asm operators, so variable labels are resolved to their addresses, not their values.
The costatement is always active. Unnamed costatements are always on.
Allows the compiler to determine in which part of memory a function will be placed.
anymem int func(){
...
}
#memmap anymem
#asm anymem
...
#endasm
Use in Dynamic C code to insert one assembly language instruction. If more than one assembly instruction is desired use the compiler directive #asm instead.
int func() {
int x,y,z;
asm ld hl,0x3333
...
}
A functions’s local variable is located on the system stack and exists as long as the function call does.
int func(){
auto float x;
...
}
IMPORTANT: bbram does not provide data integrity; instead, use the keyword protected to ensure integrity of data across power failures.
Identifies a variable with static local or global extent/scope for storage in battery-backed RAM on boards with more than one RAM device. Generally, the battery-backed RAM is attached to CS1 due to the low-power requirements. Other than its assigned root or far data location, a bbram variable is identical to a normal root or far variable. In the case of a reset or power failure, the value of a bbram variable is preserved, but not atomically like with protected variables. No software check is possible to ensure that the RAM is battery-backed. This requirement must be enforced by the user. Note that bbram variables must have either static or global storage.
For boards that utilize fast SRAM in addition to a battery-backed SRAM the size of the battery-backed root data space is specified by a BIOS macro called BBROOTDATASIZE (default value is 4K). Note that this macro is defined to zero for boards with only a single SRAM.
See the Rabbit 4000 Microprocessor Designer’s Handbook for information on how the second data area is reserved.
On boards with a single RAM, bbram variables will be treated the same as normal root or far variables. No warning will be given; the bbram keyword is simply ignored when compiling to boards with a single RAM with the assumption that the RAM is battery-backed. Please refer to the function description for _xalloc() for information on how to allocate battery-backed data in xmem.
Jumps out of a loop, if, or case statement.
while( expression ){
...
if( condition ) break;
}
switch( expression ){
...
case 3:
...
break;
...
}
Use in assembly block to insert one Dynamic C instruction.
#asm
InitValues::
c start_time = 0;
c counter = 256;
ld hl,0xa0;
ret
#endasm
Identifies the next case in a switch statement.
switch( expression ){
case constant:
...
case constant:
...
case constant:
...
...
}
Declares a variable or array element as an unsigned 8-bit character.
char c, x, *string = "hello";
int i;
...
c = (char)i; // type casting operator
Indicates the beginning of a cofunction.
cofunc|scofunc type [name][[dim]]([type arg1, ..., type argN])
{ [ statement | yield; | abort; | waitfor(expression);]... }{
...
}
cofunc, scofunc
The keywords cofunc or scofunc (a single-user cofunction) identify the statements enclosed in curly braces that follow as a cofunction.
type
Whichever keyword (cofunc or scofunc) is used is followed by the data type returned (void, int, etc.).
name
A name can be any valid C name not previously used. This results in the creation of a structure of type CoData of the same name.
dim
The cofunction name may be followed by a dimension if an indexed cofunction is being defined.
cofunction arguments (arg1, . . ., argN)
As with other Dynamic C functions, cofunction arguments are passed by value.
cofunction body
A cofunction can have as many C statements, including abort, yield, waitfor, and waitfordone statements, as needed. Cofunctions can contain calls to other cofunctions.
This keyword declares that a value will be stored in flash, thus making it unavailable for modification.
const is a type qualifier and may be used with any static or global type specifier (char, int, struct, etc.). The const qualifier appears before the type unless it is modifying a pointer. When modifying a pointer, the const keyword appears after the "*."
The const keyword in Dynamic C obeys the rules set forth in the ANSI-C89/ISO-C90 specification. Prior to Dynamic C 10.64, the behavior of const differed considerably. See Section 4.4 “The const Keyword” for an explanation of the differences and some examples that show how to update code from older Dynamic C applications to utilize the new functionality.
Skip to the next iteration of a loop.
while( expression ){
if( nothing to do ) continue;
...
}
Indicates the beginning of a costatement.
costate [ name [ state ] ] {
...
}
Name can be absent. If name is present, state can be always_on or init_on. If state is absent, the costatement is initially off.
Indicates a function is to be compiled in debug mode. This is the default case for Dynamic C functions with the exception of pure assembly language functions.
Library functions compiled in debug mode can be single stepped into, and breakpoints can be set in them.
debug int func(){
...
}
#asm debug
...
#endasm
The debug keyword in combination with the norst keyword will give you run-time checking without debug. For example,
debug norst foo() {
}
will perform run-time checking if enabled, but will not have rst instructions.
Identifies the default case in a switch statement. The default case is optional. It executes only when the switch expression does not match any other case.
switch( expression ){
case const1:
...
case const2:
...
default:
...
}
Indicates the beginning of a do loop. A do loops tests at the end and executes at least once.
do
...
while( expression );
The statement must have a semicolon at the end.
The false branch of an if statement.
if( expression )
statement // “statement” executes when “expression” is true
else
statement // “statement” executes when “expression” is false
Defines a list of named integer constants:
enum foo {
white, // default is 0 for the first item
black, // will be 1
brown, // will be 2
spotted = -2, // will be -2
striped, // will be -3
};
An enum can be declared in local or global scope. The tag foo is optional; but it allows further declarations:
enum foo rabbits;
To see a colorful sample of the enum keyword, run /samples/enum.c.
Indicates that a variable is defined in the BIOS, later in a library file, or in another library file. Its main use is in module headers.
/*** BeginHeader ..., var */
extern int var;
/*** EndHeader */
int var;
...
This keyword, when used in a variable declaration, tells the compiler to allocate storage for that variable from the far memory space (a.k.a. the physical address space). The far qualifier indicates that physical addressing will be used with all occurrences of the variable. The far type qualifier may be used with any static or global type specifier (char, int, struct, etc.). The far qualifier may appear before or after a basic or aggregate type. When modifying a pointer, the far keyword appears after the “*” in the declaration.
The use of far is very similar to that of the const qualifier in that it may only be applied to global or static variables. However, as shown in Example 1, far may come before or after the basic type (allowing far after the type is compatible with some other compilers that support the far qualifier). An error will be generated if far is applied to auto variables, function parameters, or function return values. This restriction does not apply to pointer-to-far as shown in the examples below.
// x is an integer variable in xmem // The following is prohibited |
The exception is pointers—if a pointer to far is declared, as is shown in Example 2, it can be used anywhere a “normal” pointer may be used (including autos, parameters and return types). Example 2 also shows how to place a pointer in xmem; as with const, the storage qualifier comes after the “*”, indicating that the pointer itself is in xmem. The pointers in the example are each 4 bytes, for the physical addresses they represent (effective 24-bit physical address—see the Rabbit 4000 Designer’s Manual for more information).
// x is an integer variable in xmem static far int x; // The following are allowed // The following are prohibited |
You can also declare a pointer variable in xmem to a near (logical) address, as shown in Example 3. The size of this pointer variable is 2 bytes – for the 16-bit logical address it represents, but the pointer itself is in xmem.
// x is a variable in root (may be auto or static) |
The far qualifier can also be used to put structures and arrays directly in xmem. In Example 4, we have a structure defined, and followed by a declaration. The declaration uses the far qualifier to place the entire structure in xmem. Also note that “far” is not allowed for individual structure members since this does not make any sense. However, as in the case of function parameters and auto variables, pointers to far are allowed (see Example 4). Note that arrays in xmem can be made much larger than root arrays and can be indexed using long values in addition to integers.
struct rec { // far int c; // This is not allowed // myrec is a struct in xmem // array is an array of integers in xmem |
The far qualifier can be used in typedefs as well. In Example 5, we declare a typedef for a pointer-to-far type, which can be further modified as shown.
// fptr is a pointer to an integer in xmem // cptr is a pointer to an integer in xmem // this declaration is equivalent to the previous two |
The keyword far can also be used in conjunction with const, allowing variables to be declared in the xmem space in flash. Example 6 shows an example declaration of a far constant.
// c is a constant integer variable stored in xmem on the flash device |
NOTE: The default storage class is auto, so any of the above code not explicitly marked as static or auto (and not a pointer to far) would have to be outside of a function or would have to be explicitly set to static.
The keyword firsttime in front of a function body declares the function to have an implicit *CoData parameter as the first parameter. This parameter should not be specified in the call or the prototype, but only in the function body parameter list. The compiler generates the code to automatically pass the pointer to the CoData structure associated with the costatement from which the call is made. A firstime function can only be called from inside of a costatement, cofunction, or slice statement. The DelayTick function from COSTATE.LIB below is an example of a firsttime function.
firsttime nodebug int DelayTicks(CoData *pfb, unsigned int ticks)
{
if(ticks==0) return 1;
if(pfb->firsttime){
fb->firsttime=0;
/* save current ticker */
fb->content.ul=(unsigned long)TICK_TIMER;
}
else if (TICK_TIMER - pfb->content.ul >= ticks)
return 1;
return 0;
}
Declares variables, function return values, or arrays, as 32-bit IEEE floating point.
int func(){
float x, y, *p;
float PI = 3.14159265;
...
}
float func( float par ){
...
}
Indicates the beginning of a for loop. A for loop has an initializing expression, a limiting expression, and a stepping expression. Each expression can be empty.
for(;;) { // an endless loop
...
}
for( i = 0; i < n; i++ ) { // counting loop
...
}
Causes a program to go to a labeled section of code.
...
if( condition ) goto RED;
...
RED:
Use goto to jump forward or backward in a program. Never use goto to jump into a loop body or a switch case. The results are unpredictable. However, it is possible to jump out of a loop body or switch case.
Indicates the beginning of an if statement.
if( tank_full ) shut_off_water();
if( expression ){
statements
}else if( expression ){
statements
}else if( expression ){
statements
}else if( expression ){
statements
...
}else{
statements
}
If one of the expressions is true (they are evaluated in order), the statements controlled by that expression are executed. An if statement can have zero or more else if parts. The else is optional and executes only when none of the if or else if expressions are true (non-zero).
The costatement is initially on and will automatically execute the first time it is encountered in the execution thread. The costatement becomes inactive after it completes (or aborts).
Declares variables, function return values, or array elements to be 16-bit integers. If nothing else is specified, int implies a 16-bit signed integer.
int i, j, *k; // 16-bit signed
unsigned int x; // 16-bit unsigned
long int z; // 32-bit signed
unsigned long int w; // 32-bit unsigned
int funct ( int arg ){
...
}
Indicates that a function is an interrupt service routine (ISR). All registers, including alternates, are saved when an interrupt function is called and restored when the interrupt function returns. Writing ISRs in C is never recommended, especially when timing is critical.
interrupt isr (){
...
}
An interrupt service routine returns no value and takes no arguments.
When used in a function definition, the __lcall__ function prefix forces long call and return (lcall and lret) instructions to be generated for that function, even if the function is in root. This allows root functions to be safely called from xmem. In addition to root functions, this prefix also works with function pointers. The __lcall__ prefix works safely with xmem functions, but has no effect on code generation. Its use with cofunctions is prohibited and will generate an error if attempted.
root __lcall__ int foo(void) {
return 10; // Generates an lret instruction, even though we are in root
}
main() {
foo(); // This now generates an lcall instruction
}
Declares variables, function return values, or array elements to be 32-bit integers. If nothing else is specified, long implies a signed integer.
long i, j, *k; // 32-bit signed
unsigned long int w; // 32-bit unsigned
long funct ( long arg ){
...
}
Identifies the main function. All programs start at the beginning of the main function. (main is actually not a keyword, but is a function name.)
Indicates a function is not compiled in debug mode. This is the default for assembly blocks.
nodebug int func(){
...
}
#asm nodebug
...
#endasm
See also “debug” and directives “#debug #nodebug”.
Indicates that a function does not use the RST instruction for breakpoints.
norst void func(){
...
}
The norst keyword in combination with the debug keyword will give you run-time checking without debug. For example,
debug norst foo() {
}
will perform runtime-checking if enabled, but will not have rst instructions.
Indicates a function does not use the IX register as a stack frame reference pointer. This is the default case.
nouseix void func(){
...
}
The null pointer. (This is actually a macro, not a keyword.) Same as (void *)0.
An important feature of Dynamic C is the ability to declare variables as protected. Such a variable is protected against loss in case of a power failure or other system reset because the compiler generates code that creates a backup copy of a protected variable before the variable is modified. If the system resets while the protected variable is being modified, the variable’s value can be restored when the system restarts. This operation requires battery-backed RAM and the use of the main system clock. If you are using the 32 kHz clock you must switch back to the main system clock to use protected variables because the atomicity of the write cannot be ensured when using the 32 kHz clock.
main(){
protected int state1, state2, state3;
...
_sysIsSoftReset(); // restore any protected variables
}
The call to _sysIsSoftReset checks to see if the previous board reset was due to the compiler restarting the program (i.e., a soft reset). If so, then it initializes the protected variable flags and calls sysResetChain(), a function chain that can be used to initialize any protected variables or do other initialization. If the reset was due to a power failure or watchdog time-out, then any protected variables that were being written when the reset occurred are restored.
A system that shares data among different tasks or among interrupt routines can find its shared data corrupted if an interrupt occurs in the middle of a write to a multi-byte variable (such as type int or float). The variable might be only partially written at its next use. Declaring a multi-byte variable shared means that changes to the variable are atomic, i.e., interrupts are disabled while the variable is being changed. You may declare a multi-byte variable as both shared and protected.
The register keyword is not currently implemented in Dynamic C, but is reserved for possible future implementation. It is currently synonymous with the keyword auto.
Explicit return from a function. For functions that return values, this will return the function result.
void func (){
...
if( expression ) return;
...
}
float func (int x){
...
float temp;
...
return ( temp * 10 + 1 );
}
Indicates a function is to be placed in root memory. This keyword is semantically meaningful in function prototypes and produces more efficient code when used. Its use must be consistent between the prototype and the function definition.
root int func(){
...
}
#memmap root
#asm root
...
#endasm
Indicates the beginning of a single-user cofunction. See cofunc on page 200.
Identifies a function chain segment (within a function).
int func ( int arg ){
...
int vec[10];
...
segchain _GLOBAL_INIT{
for( i = 0; i<10; i++ ){ vec[i] = 0; }
}
...
}
This example adds a segment to the function chain _GLOBAL_INIT. Using segchain is equivalent to using the #GLOBAL_INIT directive. When this function chain executes, this and perhaps other segments elsewhere execute. The effect in this example is to reinitialize vec[].
Indicates that changes to a multi-byte variable (such as a float) are atomic. Interrupts are disabled when the variable is being changed. Local variables cannot be shared. Note that you must be running off the main system clock to use shared variables. This is because the atomicity of the write cannot be ensured when running off the 32 kHz clock.
shared float x, y, z;
shared int j;
...
main(){
...
}
If i is a shared variable, expressions of the form i++ (or i = i+ 1) constitute two atomic references to variable i, a read and a write. Be careful because i++ is not an atomic operation.
Declares that a variable or array is short integer (16 bits). If nothing else is specified, short implies a 16-bit signed integer.
short i, j, *k; // 16-bit, signed
unsigned short int w; // 16-bit, unsigned
short funct ( short arg ){
...
}
Declares a function to be optimized for size (as opposed to speed).
size int func (){
...
}
Declares a variable or array to be signed. If nothing else is specified in a declaration, signed means 16-bit signed integer.
signed char c; // 8-bit, signed
signed i, j, *k; // 16-bit, signed
signed int x; // 16-bit, signed
signed long w; // 32-bit, signed
signed funct ( signed arg ){
...
}
Values in a 16-bit signed integer range from -32768 to +32767 instead of 0 to 65,535. Values in a signed long integer range from -231 to 231 - 1.
A built-in function that returns the size in bytes of a variable, array, structure, union, or of a data type. sizeof() can be used inside of assembly blocks.
int list[] = { 10, 99, 33, 2, -7, 63, 217 };
...
x = sizeof(list); // x will be assigned 14
Declares a function to be optimized for speed (as opposed to size).
speed int func (){
...
}
Declares a local variable to have a permanent fixed location in memory, as opposed to auto, where the variable exists on the system stack. Global variables are by definition static. Local variables are auto by default.
int func (){
...
int i; // auto by default
static float x; // explicitly static
...
}
This keyword introduces a structure declaration, which defines a type.
struct {
...
int x;
int y;
int z;
} thing1; // defines the variable thing1 to be a struct
struct speed{
int x;
int y;
int z;
}; // declares a struct type named speed
struct speed thing2; // defines variable thing2 to be of type speed
Structure declarations can be nested.
struct {
struct speed slow;
struct speed slower;
} tortoise; // defines the variable tortoise to be a nested struct
struct rabbit {
struct speed fast;
struct speed faster;
}; // declares a nested struct type named rabbit
struct rabbit chips; // defines the variable chips to be of type rabbit
Indicates the start of a switch statement.
switch( expression ){
case const1:
...
break;
case const2:
...
break;
case const3:
...
break
default :
...
}
The switch statement may contain any number of cases. The constants of the case statements are compared with expression. If there is a match, the statements for that case execute. The default case, if it is present, executes if none of the constants of the case statements match expression.
If the statements for a case do not include a break, return, continue, or some means of exiting the switch statement, the cases following the selected case will also execute, regardless of whether their constants match the switch expression.
This keyword provides a way to create new names for existing data types.
typedef struct {
int x;
int y;
} xyz; // defines a struct type...
xyz thing; // ...and a thing of type xyz
typedef uint node; // meaningful type name
node master, slave1, slave2;
Identifies a variable that can contain objects of different types and sizes at different times. Items in a union have the same address. The size of a union is that of its largest member.
union {
int x;
float y;
} abc; // overlays a float and an int
Declares a variable or array to be unsigned. If nothing else is specified in a declaration, unsigned means 16-bit unsigned integer.
unsigned i, j, *k; // 16-bit, unsigned
unsigned int x; // 16-bit, unsigned
unsigned long w; // 32-bit, unsigned
unsigned funct ( unsigned arg ){
...
}
Values in a 16-bit unsigned integer range from 0 to 65,535 instead of –32768 to +32767. Values in an unsigned long integer range from 0 to 232 – 1.
Indicates that a function uses the IX register as a stack frame pointer.
useix void func(){
...
}
See also “nouseix” and directives “#useix #nouseix”.
Used in a costatement or cofunction, this keyword identifies a point of suspension pending the outcome of a condition, completion of an event, or some other delay.
for(;;){
costate {
waitfor ( input(1) == HIGH );
...
}
...
}
The waitfordone keyword can be abbreviated as wfd. It is part of Dynamic C’s cooperative multitasking constructs. Used inside a costatement or a cofunction, it executes cofunctions and firsttime functions. When all the cofunctions and firsttime functions in the wfd statement are complete, or one of them aborts, execution proceeds to the statement following wfd. Otherwise a jump is made to the ending brace of the costatement or cofunction where the wfd statement appears; when the execution thread comes around again, control is given back to the wfd statement.
The wfd statements below are from Samples\cofunc\cofterm.c
x = wfd login(); // wfd with one cofunction
wfd { // wfd with several cofunctions
clrscr();
putat(5,5,"name:");
putat(5,6,"password:");
echoon();
}
wfd may return a value. In the example above, the variable x is set to 1 if login() completes execution normally and set to -1 if it aborts. This scheme is extended when there are multiple cofunctions inside the wfd: if no abort has taken place in any cofunction, wfd returns 1, 2, ..., n to indicate which cofunction inside the braces finished executing last. If an abort takes place, wfd returns -1, -2, ..., -n to indicate which cofunction caused the abort.
Identifies the beginning of a while loop. A while loop tests at the beginning and may execute zero or more times.
while( expression ){
...
}
Declares a block of data in extended flash memory.
xdata name { value_1, ... value_n };
The 20-bit physical address of the block is assigned to name by the compiler as an unsigned long variable. The amount of memory allocated depends on the data type. Each char is allocated one byte, and each int is allocated two bytes. If an integer fits into one byte, it is still allocated two bytes. Each float and long cause four bytes to be allocated.
The value list may include constant expressions of type int, float, unsigned int, long, unsigned long, char, and (quoted) strings. For example:
xdata name1 {'\x46','\x47','\x48','\x49','\x4A','\x20','\x20'};
xdata name2 {'R','a','b','b','i','t'};
xdata name3 {" Rules! "};
xdata name4 {1.0,2.0,(float)3,40e-01,5e00,.6e1};
The data can be viewed directly in the dump window by doing a physical memory dump using the 20-bit address of the xdata block. See Samples\Xmem\xdata.c for more information.
Indicates that a function is to be placed in extended memory. This keyword is semantically meaningful in function prototypes. Good programing style dictates its use be consistent between the prototype and the function definition. That is, if a function is defined as:
xmem int func(){}
the function prototype should be:
xmem int func();
Any of the following will put the function in xmem:
xmem int func();
xmem int func(){}
or
xmem int func();
int func(){}
or
int func();
xmem int func(){}
In addition to flagging individual functions, the xmem keyword can be used with the compiler directive #memmap to send all functions not declared as root to extended memory.
#memmap xmem
This construct is helpful if an application does not have enough root code space. Another strategy is to use separate I&D space. Note that using both #memmap xmem and separate I&D space might cause an application to run out of xmem, depending on the size of the application and the size of the flash. If this occurs, the programmer should consider using only one of the #memmap xmem or separate I&D space options. If the application is extremely tight for xmem code memory but has root code memory to spare, the programmer may also consider explicitly tagging some xmem or anymem functions with the root keyword.
This keyword conforms to ANSI C. Thus, it can be used in three different ways.
Parameter List - used to identify an empty parameter list (a.k.a., argument list). An empty parameter list can also be identified by having nothing in it. The following two statements are functionally identical:
int functionName(void);
int functionName();
Pointer to Void - used to declare a pointer that points to something that has no type.
void *ptr_to_anything;
Return Type - used to state that no value is returned.
void functionName(param1, param2);
Reserved for future use.
Declares a table of strings in extended memory. The strings are allocated in flash memory at compile time which means they can not be rewritten directly.
The table entries are 20-bit physical addresses. The name of the table represents the 20-bit physical address of the table; this address is assigned to name by the compiler.
xstring name { “string_1”, . . . “string_n” };
Used in a costatement, this keyword causes the costatement to pause temporarily, allowing other costatements to execute. The yield statement does not alter program logic, but merely postpones it.
for(;;){
costate {
...
yield;
...
}
...
}
Compiler directives are special keywords prefixed with the symbol #. They tell the compiler how to proceed. Only one directive per line is allowed, but a directive may span more than one line if a backslash (\) is placed at the end of the line(s).
There are some compiler directives used to decide where to place code and data in memory. They are called origin directives and include #rcodorg, #rvarorg and #xcodorg. A detailed description of origin directives may be found in the Rabbit 4000 Designer’s Handbook (look in the index under “origin directives”).
Syntax: #asm options
Begins a block of assembly code. The available options are:
const: When seperate I&D space is enabled, assembly constants should be placed in their own assembly block (or done in C). For more information, see Section 13.2.2, “Defining Constants.”
nodebug: Disables debug code during assembly. This is the default condition. It is still possible to single step through assembly code as long as the assembly window is open.
xmem: Places a block of code into extended memory, overriding any previous memory directives. The block is limited to 4KB.
If the #asm block is unmarked, it will be compiled to root.
Syntax: #class options
Controls the storage class for local variables. The available options are:
static: Place local variables in permanent, fixed storage. This option was deprecated in Dynamic C 10.44. The keyword “static” is still available to apply the static storage class to variables.
The default storage class is auto.
Enables or disables debug code compilation. #debug is the default condition. A function's local debug or nodebug keyword overrides the global #debug or #nodebug directive. In other words, if a function does not have a local debug or nodebug keyword, the #debug or #nodebug directive would apply.
#nodebug prevents RST 28h instructions from being inserted between C statements and assembly instructions.
NOTE: These directives do nothing if they are inside of a function. This is by design. They are meant to be used at the top of an application file.
Syntax: #define name text or #define name (parameters . . . ) text
Defines a macro with or without parameters according to ANSI standard. A macro without parameters may be considered a symbolic constant. Supports the # and ## macro operators. Macros can have up to 32 parameters and can be nested to 126 levels.
Ends a block of assembly code.
Syntax: #error "…"
Instructs the compiler to act as if an error was issued. The string in quotes following the directive is the message to be printed.
Syntax: #fatal “...”
Instructs the compiler to act as if a fatal error occurred. The string in quotes following the directive is the message to be printed.
Syntax: #funcchain chainname name
Adds a function, or another function chain, to a function chain.
Syntax: #GLOBAL_INIT { variables }
#GLOBAL_INIT sections are blocks of code that are run once before main() is called. They should appear in functions after variable declarations and before the first executable code. If a local static variable must be initialized once only before the program runs, it should be done in a #GLOBAL_INIT section, but other inititialization may also be done. For example:
// This function outputs and returns the number of times it has been called. // initialize count // make port A output // increment and return count |
Syntax: #if constant_expression
#elif constant_expression
#else
#endif
These directives control conditional compilation. Combined, they form a multiple-choice if. When the condition of one of the choices is met, the Dynamic C code selected by the choice is compiled. Code belonging to the other choices is ignored.
main(){ #elif BOARD_TYPE == 2 #elif BOARD_TYPE == 3 #else #endif |
The #elif and #else directives are optional. Any code between an #else and an #endif is compiled if all values for constant_expression are false.
Syntax: #ifdef name
This directive enables code compilation if name has been defined with a #define directive. This directive must have a matching #endif.
Syntax: #ifndef name
This directive enables code compilation if name has not been defined with a #define directive. This directive must have a matching #endif.
Syntax: #include "pathname" or #include <pathname>
Inserts the file specified by "pathname" into the code. This is a straight textual insertion as if the contents of the file were cut and pasted directly into the file at the location of the #include directive.
The two versions allow for control over which include paths are searched. The double-quotes ("pathname") around the path cause the compiler to first search in the directory where the source file containing the #include is located, then move on to the include path list provided by the GUI or project file. The angle brackets (<pathname>) version skips the initial path and searches just the include paths list.
Controls whether Dynamic C will intersperse library functions with the program’s functions during compilation.
#nointerleave forces the user-written functions to be compiled first.The #nointerleave directive, when placed at the top of application code, tells Dynamic C to compile all of the application code first and then to compile library code called by the application code afterward, and then to compile other library code called by the initial library code following that, and so on until finished.
Note that the #nointerleave directive can be placed anywhere in source code, with the effect of stopping interleaved compilation of functions from that point on. If #nointerleave is placed in library code, it will effectively cause the user-written functions to be compiled together starting at the statement following the library call that invoked #nointerleave.
Syntax: #makechain chainname
Creates a function chain. When a program executes the function chain named in this directive, all of the functions or segments belonging to the function chain execute.
Syntax: #memmap options
Controls the default memory area for functions. The following options are available.
anymem NNNN: When code comes within NNNN bytes of the end of root code space, start putting it in xmem. Default memory usage is #memmap anymem 0x2000.
root: All functions not declared as xmem go to root memory.
xmem: C functions not declared as root go to extended memory. Assembly blocks not marked as xmem go to root memory. See the description for xmem for more information on this keyword.
Syntax: #pragma nowarn [warnt|warns]
Trivial warnings (warnt) or trivial and serious warnings (warns) for the next physical line of code are not displayed in the Compiler Messages window. The argument is optional; default behavior is warnt.
Syntax: #pragma nowarn [warnt|warns] start
Trivial warnings (warnt) or trivial and serious warnings (warns) are not displayed in the Compiler Messages window until the #pragma nowarn end statement is encountered. The argument is optional; default behavior is warnt. #pragma nowarn cannot be nested.
Syntax: #undef identifier
Removes (undefines) a defined macro.
Syntax: #use pathname
Activates a library named in LIB.DIR so modules in the library can be linked with the application program. This directive immediately reads in all the headers in the library unless they have already been read.
See Section 4.8.1 “Libraries and File Scope” for a description of how #use interacts with file scoping (introduced in Dynamic C 10.64).
Controls whether functions use the IX register as a stack frame reference pointer or the SP (stack pointer) register. #nouseix is the default.
Note that when the IX register is used as a stack frame reference pointer, it is corrupted when any stack-variable using function is called from within a cofunction, or if a stack-variable using function contains a call to a cofunction.
Syntax: #warns “...”
Instructs the compiler to act as if a serious warning was issued. The string in quotes following the directive is the message to be printed.
Syntax: #warnt “...”
Instructs the compiler to act as if a trivial warning was issued. The string in quotes following the directive is the message to be printed.
Syntax: #ximport “filename” symbol
This compiler directive places the length of filename (stored as a long) and its binary contents at the next available place in xmem flash. filename is assumed to be either relative to the Dynamic C installation directory or a fully qualified path. symbol is a compiler generated macro that gives the physical address where the length and contents were stored.
The sample program ximport.c illustrates the use of this compiler directive.
Syntax: #zimport “filename” symbol
This compiler directive extends the functionality of #ximport to include file compression by an external utility. filename is the input file (and must be relative to the Dynamic C installation directory or be a fully qualified path) and symbol represents the 20-bit physical address of the downloaded file.
The external utility supplied with Dynamic C is zcompress.exe. It outputs the compressed file to the same directory as the input file, appending the extension .DCZ. E.g., if the input file is named test.txt, the output file will be named test.txt.dcz. The first 32 bits of the output file contains the length (in bytes) of the file, followed by its binary contents. The most significant bit of the length is set to one to indicate that the file is compressed.
The sample program zimport.c illustrates the use of this compiler directive. Please see Appendix C.0.3 for further information regarding file compression and decompression.