[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

3. Compiler

The GNU Compiler Collection integrates several compilers for many architectures. The C and C++ compilers have been ported for 68HC11 and 68HC12 micro-controllers.

This chapter gives some information about how the compiler implements several aspects of the C and C++ languages. The reader is supposed to be familiar with these programming languages (see section 7. References to obtain information or books about those languages).

The complete GCC documentation is available in The GNU Compiler Collection.


3.1 Supported Data Types

The compiler supports all the data types defined in ISO/IEC 9899:1990. The table below gives information about each type and how they are passed in function calls.

char
unsigned char
signed char
Characters are 8-bit entities. They are unsigned by default. The char type can be signed when you use the `-fsigned-char' option.

They are passed as parameters on the stack as 16-bit values. They may be stored in the B, X, Y registers. Most arithmetic operations are generated inline.

A function returns it in register B.

 
7      0
+------+
|   0  |
+------+

short
unsigned short
Shorts are 16-bit entities. They are passed as parameters on the stack as 16-bit values. They may be stored in the D, X, Y registers. Most arithmetic operations are generated inline (except mult, div and mod).

A function returns it in register D.

 
15      7     0
+------+------+
|  1   |  0   |
+------+------+

int
unsigned int
Integers are either 16 or 32-bit entities. They are 32-bit by default. The `-mshort' option turns on the 16-bit integer mode. The parameter passing rule applies to either short or long depending on its size.

void*
pointer
A pointer is a 16-bit entity. The parameter passing rules are the same as an unsigned short.

A pointer can point to a far function (that is a function which is in a paged memory). The pointer will in fact point to a trampoline code whose address is not in paged memory.

long
unsigned long
Long integers are 32-bit entities. They are passed as parameters on the stack as 32-bit values. They may be stored in the D+X register: the low-part in D and the high-part in X. Logical operations are generated inline, some addition and subtraction are inline. Other arithmetic operations are made by a library call. Comparison are inline.

A function returns it in register D and X.

 
long
31      23     15     7    0
+------+------+------+------+
|  3   |  2   |  1   |  0   |
+------+------+------+------+

float
Floats are IEEE 32-bit floating point numbers. They are treated like longs for copies, parameter passing rule and register allocation. Most/all of the operations are made by a library call.

A function returns it in register D and X.

long long
unsigned long long
Long long are 64-bit entities. They are never allocated in a hard register. They are passed on the stack for operations. They are returned like a struct (in memory). Logical operations (and, or, xor) are generated inline. Other operations are made by a library call. Some shift operations are generated inline.

 
63      55     47     39     31      23     15     7    0
+------+------+------+------+------+------+------+------+
|  7   |  6   |  5   |  4   |  3   |  2   |  1   |  0   |
+------+------+------+------+------+------+------+------+

double
Double are IEEE 64-bit floating point numbers. They are treated like long long for copies and parameter passing rule. All operations are made by a library call.

The `-fshort-double' option changes the definition of `double' to use IEEE 32-bit floating point numbers.


3.2 Register Allocation

The 68HC11/68HC12 registers (D, X and Y) are completely managed by GCC. Local variables can be stored in these registers. However, since the 68HC11 and 68HC12 have so few registers, soft-registers are used to simulate hard registers for GCC (this avoids register spill failure in the reload pass). There are two kinds of soft-registers:


3.3 Register Usage

The table below indicates how the compiler uses the given registers.

Register Description
A
B The A and B register are not directly used by GCC. Some patterns generate instructions that use these registers to generate specific instructions such as add with a carry (used in 32-bit add).
D This register is used for most arithmetic operation. It holds 8 or 16-bit values. It is also used to hold the low-part of a 32-bit value (either a long or a float). In a function call, it is used to pass the first argument of that function. If the function returns a struct or a 64-bit value, the result will be returned in memory. The caller passes a pointer to that memory location in this register. This register is also used for the result of functions.
X This register is used for indexed addressing. It holds 8 or 16-bit values. It is also used to hold the high-part of a 32-bit value (either a long or a float). When the first function parameter is 32-bit wide, it is used to pass the high-part of the 32-bit value. It is used for the result of functions when the result does not fit in a 16-bit value. This includes long, float as well as small structures (`-fno-pcc-struct-return').
Y This register is used for indexed addressing. It holds 8 or 16-bit values.
Z This register is used for indexed addressing. It is treated like X or Y by GCC. It is replaced by either X or Y during the machine reorganization. When it must be saved, it is saved in `_.z' (see below).
_.z This is a 16-bit soft-register in `.page0' that is used during the Z register replacement to save the Z register. It is possible to eliminate the use of that register by passing the `-ffixed-z' option. The program may however not compile in some cases.
_.xy This is a 16-bit soft-register in `.page0' that is used during the Z register replacement to save the old content of either X or Y. It is possible to eliminate the use of that register by passing the `-ffixed-z' option. The program may however not compile in some cases.
_.frame This is a 16-bit soft-register in `.page0' that represents the frame pointer. It is possible to eliminate the use of that register by passing the `-fomit-frame-pointer' flag. But in that case, debugging becomes difficult.
_.tmp This is a 16-bit soft-register in `.page0' that is used internally by the machine description. It is not available to GCC. It is used in some cases where the machine description needs a memory location to copy some hard registers (reg &lt;-&gt; reg copy). It is not possible to eliminate the use of that register.
_.d1.._.d32 These are the 32 soft-registers in `.page0'. Each of them is 16-bit wide. Consecutive registers may be allocated to store long as well as long long values. The use of these registers is controlled by the `-msoft-reg-count=n' option.

GCC assumes that the following registers are clobbered by any function call:

 
      D, X, Y, Z

The soft registers in `.page0' have a name which cannot be specified in C and C++. No conflict can therefore arise with a program global variable or function. However, if you want to access those registers from a C or C++ function, do the following declaration:

 
extern unsigned short d1 __asm__("_.d1");

Such declaration tells GCC that the external variable d1 corresponds to the assembly symbol _.d1.


3.4 Traps and Interrupts

GCC for 68HC11 and 68HC12 supports the generation of trap and interrupt handlers. The trap handler correspond to either the swi exception handler or to the invalid opcode handler. The difference between the trap and interrupt handlers are that the former is a synchronous exception while the later is asynchronous. Trap and interrupt handlers are specified by using the GNU extension `__attribute__'.


3.4.1 Interrupts

To define an interrupt handler, you must declare the prototype of the interrupt handler as follows:

 
   void my_interrupt_handler(void) __attribute__((interrupt));

Then, you must define your interrupt handler as follows:

 
   void my_interrupt_handler(void)
   {
     ...
   }

The prologue of the interrupt handler saves the GCC soft registers _.tmp, _.xy and _.z. Other soft registers need not to be saved (unless they are used in the interrupt handler). The epilogue restores these registers and uses rti to return from interrupt.

Note: You are responsible for installing the interrupt handler in the 68HC11/68HC12 vectors table.

Bugs: You can define an interrupt handler which has parameters and which returns some value. Such invalid specification will be forbidden later.


3.4.2 Traps

The trap handler is defined in the same manner except that you can pass parameters and it can return a value. The trap handler follows exactly the same parameter passing rules as a normal function. To define some generic system call handler, you can define for example:

 
   int syscall(int op, ...) __attribute__((trap));
   int syscall(int op, ...)
   {
     int result;
     ...
     return result;
   }

The prologue of the trap does not save the GCC soft registers _.tmp, _.xy and _.x as the interrupt handler does. This is because the trap is synchronous and its invocation is treated like a function call by GCC.

The epilogue saves the result on the stack so that the rti instruction used to return pops the correct result.

To invoke a trap handler, just call the trap handler, for example:

 
   int result = syscall(1, "Hello World!", 12);

A swi instruction will be generated instead of a bsr.

Note: You are responsible for installing the trap handler in the 68HC11 or 68HC12 vector's table. If you define several trap handlers, you must be careful in switching the <b>swi</b> vector.

Limitation: You can define a trap handler for the illegal opcode but there is no way (yet) to tell GCC to generate the illegal opcode to invoke the trap handler.


3.5 GCC CPU Target

GCC has three options `-m68hc11', `-m68hc12' and `-m68hcs12' which control what is the target micro-controller. These options are passed to the assembler and they also control the linker. When none of these options are specified, GCC uses the default CPU target that you specified during the configuration. For the binary installations (RPMs and Windows) the default CPU is the 68HC11.

When compiling, assembling and linking you must make sure to pass the same cpu target option. If you fail, you will get a linker error since 68HC11 and 68HC12 object files have different ELF magic numbers.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Stephane Carrez on January, 30 2005 using texi2html