RL78 Application Binary Interface for GCC
ELF Machine Number: 197
ELF32 format will be used.
ELF relocations are RELA (addend in reloc, not opcode). Relocation numbers and functions match the RX relocations at the moment, minus any Red Hat specific relocations. (add table later)
ELF Flags - TBD
· Absence/presence of MUL/DIV
· Other hardware variants
· 78K0 / 78K0R compatibility flags
Debug format - the debug format is DWARF-2. Dwarf2 frame and unwind information will be encoded, and dwarf2 exception unwinding will be used. Dwarf2 register numbers 0 through 31 are assigned according to the "virtual" values in the table below. SP is register 32. PC is register 33.
Types
|
Type |
Size, bits |
|
Char |
8 |
|
short, int |
16 |
|
long |
32 |
|
long long |
64 |
|
void * |
16 |
|
void __far * |
32 |
|
float, double |
32 |
|
long double |
64 |
Note about pointers: The RL78 has a 20-bit address space, and special "bank" registers (CS/ES) to access them, but working with a default 32-bit pointer is very expensive. The above table uses a 16-bit pointer for performance reasons. GCC supports named address spaces, and includes supporting 32-bit (er, 20-bit) pointers via the "__far" named address space as an extension.
Register Usage
The RL78 has four sets of eight 8-bit registers. These registers can be used as 16-bit registers in hardware, or 32- or 64-bit registers via software emulation.
|
BANK 0 |
BANK 1 |
BANK 2 |
BANK 3 |
|||||||||||
|
SADDR |
HW/Reg |
Virtual |
SADDR |
HW/Reg |
Virtual |
SADDR |
HW/Reg |
Virtual |
SADDR |
HW/Reg |
Virtual |
|||
|
FFEF8 |
X / $r0 |
R0 |
FFEF0 |
X / $r0 |
R8 |
FFEE8 |
X / $r0 |
R16 |
FFEE0 |
X / $r0 |
R24 |
|||
|
FFEF9 |
A / $r1 |
R1 |
FFEF1 |
A / $r1 |
R9 |
FFEE9 |
A / $r1 |
R17 |
FFEE1 |
A / $r1 |
R25 |
|||
|
FFEFA |
C / $r2 |
R2 |
FFEF2 |
C / $r2 |
R10 |
FFEEA |
C / $r2 |
R18 |
FFEE2 |
C / $r2 |
R26 |
|||
|
FFEFB |
B / $r3 |
R3 |
FFEF3 |
B / $r3 |
R11 |
FFEEB |
B / $r3 |
R19 |
FFEE3 |
B / $r3 |
R27 |
|||
|
FFEFC |
E / $r4 |
R4 |
FFEF4 |
E / $r4 |
R12 |
FFEEC |
E / $r4 |
R20 |
FFEE4 |
E / $r4 |
R28 |
|||
|
FFEFD |
D / $r5 |
R5 |
FFEF5 |
D / $r5 |
R13 |
FFEED |
D / $r5 |
R21 |
FFEE5 |
D / $r5 |
R29 |
|||
|
FFEFE |
L / $r6 |
R6 |
FFEF6 |
L / $r6 |
R14 |
FFEEE |
L / $r6 |
R22 |
FFEE6 |
L / $r6 |
R30 |
|||
|
FFEFF |
H / $r7 |
R7 |
FFEF7 |
H / $r7 |
R15 |
FFEEF |
H / $r7 |
R23 |
FFEE7 |
H / $r7 |
R31 |
|||
For the purposes of this spec, the registers are named R0 through R31, with R0 being $r0 in bank 0 and R31 being $r7 in bank 3. These 32 registers are referred to as "virtual registers" as the method of accessing them varies depending on the hardware's state (mostly, the register bank select bits).
The assembler does not use these alternate names; the compiler must arrange for suitable #defines or SADDR encodings to access these registers. The compiler will assume bank 0 is active at all times (i.e. functions assume bank 0 is active at the start of the function), so R0 through R7 correspond to $r0 through $r7.
Arguments to functions are always passed on the stack, with the first argument in the parameter list pushed last. Note: this is the common "args on stack" layout most compilers use. 16-bit and larger types shall be 16-bit aligned. If an 8-bit type is passed between two 16-bit types, the 8-bit type shall be padded towards the LSB (i.e. towards address zero, so it ends up on an even address too).
Return values shall be returned in R8..Rn for as many registers as are needed to store the value. That lets us store 8, 16, 32, and 64 bit values in the same place, without using up all the "real" registers (AX, BC, etc) that might be needed to compute the return value.
Structs, unions, and other aggregates of 8 bytes or less are returned in virtual registers r8-r15. Otherwise, the aggregate will returned in the struct return area allocated by the caller. A pointer to that struct return area will be passed (on the stack) as a hidden first argument.
Registers R0 through R15 (banks 0 and 1) are not preserved across function calls (i.e. functions may change them without needing to restore the old value). Bank 0 must be selected at function entry and exit. Registers R16 through R23 (bank 2) must be preserved across function calls (i.e. functions that change them must restore the old value before returning). Registers R24 through R31 (bank 3) are reserved for interrupt handlers.
There are currently no global registers, such as small-data-pointers or constant-pool-base.