Doc:compiler
- [GNU Compiler Documentation]
- The GNU Compiler Collection integrates several compilers for many architectures. The C and C++ compilers have been ported for 68HC11, 68HC12 and 68HCS12 micro-controllers. The documentation explains how to invoke the compiler and describes the specific details in using it.
- Compilation FAQ
- Specific questions about the compiler.
Contents |
This page provides specific information about the compiler for these micro-controllers.
Refer to the GNU Compiler Documentation for using the compiler.
Description of the Port
This section gives some information about the port itself.
Supported Data Types
Type | Description | Return |
char unsigned char signed char |
Characters are 8-bit entities. They are unsigned by default. They are passed as parameters on the stack as 8-bit values. They may be stored in the D, X, Y registers. All arithmetic operations are generated inline. | B |
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. All arithmetic operations are generated inline (except mult, div and mod). | D |
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. | cf short cf long |
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. | Low: D High: X |
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. | Low: D High: 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. | Ptr D |
double | Double are IEEE 64-bit floating point numbers. They are treated like long long for copies and parameter passing rule. Most/all of the operations are made by a library call. | Ptr D |
Register Allocation
The M68HC11 registers (D, X and Y) are completely managed by GCC. Local variables can be stored in these registers. However, since the M68HC11 has 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:
- A set of soft registers which are replaced during the machine specific reorganization into a real hard register. At present, this set of soft registers is only composed of a single register called 'Z'. This register is treated like X or Y register by GCC. It is replaced by X or Y and sometimes D. When it is replaced, the old X/Y/D value is saved and restored if this is necessary. In general, the 'Z' register is allocated during the reload pass for the reload of an address. This 'Z' register helps significantly the reload pass and contributes in the generation of better code. It is possible to disable the 'Z' register by using the -ffixed-z option (in general and depending on the program, this will result in register spill failure...).
- A set of general soft registers which are located in .softregs
section (mapped in page0 or data memory bank). These
registers are not replaced during the machine reorganization. There
are 4 soft registers by default for 68HC11 and 2 for 68HC12.
This is configured by using the
-msoft-reg-count=cnt. The minimum depends on your
program, and the maximum is 32.
Note: It is not clear whether having a lot of soft-registers produces optimal code. For small functions, reducing the number of soft registers is a good idea. For large functions, increasing to 8 or 12 helps in generating a smaller and faster code.
Register Usage
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).
|
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).
|
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 <-> 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 now 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.
Traps and Interrupts
GCC for 68HC11 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__.
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 vectors table. <p> Bugs: You can define an interrupt handler which has parameters and which returns some value. Such invalid specification will be forbidden later.
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 vector's table. If you define several trap handlers, you must be careful in switching the 68HC11 swi 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.
Branches
It is the responsibility of the assembler to turn relative branches into absolute branches when the displacement is out of bounds. The GNU Assembler knows how to do that for function calls (bsr) as well as all the conditional branches (for example beq).
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.
Based on the target given to gcc, certain symbols are defined which the pre-processor can check and decide what code fragment to use. You can see what initial define are passed to the pre-processor by passing -v to m6811-elf-gcc.
- -Dmc68hc1x -D__mc68hc1x__ -D__mc68hc1x are always passed (HC11/HC12/HCS12).
- -Dmc6811 -DMC6811 -Dmc68hc11 is passed for HC11 (-m68hc11)
- -Dmc6812 -DMC6812 -Dmc68hc12 is passed for HC12 (-m68hc12)
- -Dmc6812 -DMC6812 -Dmc68hcs12 is passed for HCS12 (-m68hcs12)
So the -Dmc68hcNNN allows you to more specifically identify the processor.
When compiling, assembling and linking you must make sure you 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.
68HC12 memory banks
For 68HC12, the -mlong-calls option can be used to tell the compiler to use call and rtc for function calls and returns.
Generated Code Size Comparison
The table below gives the size of the text section for the same C source file <A HREF="files/string.c">string.c</A> compiled with different options.
Note:
- this file comes from GNU/Linux kernel, it was modified a little to compile outside of Linux kernel.
- the assembly file corresponds to the result of the latest development version (Alpha 1.9b).
- Release 1.1 is based on GCC 2.95.3.
- Alpha 1.9b is based on GCC 3.0.3.
Target 68HC11 | |||||
---|---|---|---|---|---|
Compilation | Apr 24, 2000 | Aug 5, 2000 | Release 1.1 | Alpha 1.9b | Asm |
gcc -O | 1648 | 1497 | 1531 | 1589 | <A HREF="files/string-32-O.s">string-32-O.s</A> |
gcc -O -fomit-frame-pointer | 1437 | 1287 | 1315 | 1379 | <A HREF="files/string-32-Of.s">string-32-Of.s</A> |
gcc -O -mshort | 1453 | 1334 | 1371 | 1391 | <A HREF="files/string-16-O.s">string-16-O.s</A> |
gcc -O -mshort -fomit-frame-pointer | 1253 | 1131 | 1157 | 1190 | <A HREF="files/string-16-Of.s">string-16-Of.s</A> |
Target 68HC12 | |||||
---|---|---|---|---|---|
Compilation | Release 1.1 | Alpha 1.9b | Asm | ||
gcc -O | 1811 | 1597 | <A HREF="files/string-32-O-h12.s">string-32-O-h12.s</A> | ||
gcc -O -fomit-frame-pointer | 1362 | 914 | <A HREF="files/string-32-Of-h12.s">string-32-Of-h12.s</A> | ||
gcc -O -mshort | 1616 | 1412 | <A HREF="files/string-16-O-h12.s">string-16-O-h12.s</A> | ||
gcc -O -mshort -fomit-frame-pointer | 1176 | 762 | <A HREF="files/string-16-Of-h12.s">string-16-Of-h12.s</A> | ||
gcc -O -mshort -fomit-frame-pointer -mauto-incdec -msoft-reg-count=0 |
911 | 738 | <A HREF="files/string-16-Ofm-h12.s">string-16-Ofm-h12.s</A> |