Skip to main content

IAR Embedded Workbench for RL78 5.20

Calling convention

In this section:

A calling convention is the way a function in a program calls another function. The compiler handles this automatically, but, if a function is written in assembler language, you must know where and how its parameters can be found, how to return to the program location from where it was called, and how to return the resulting value.

It is also important to know which registers an assembler-level routine must preserve. If the program preserves too many registers, the program might be inefficient. If it preserves too few registers, the result would be an incorrect program.

The compiler provides two calling conventions—one old, which is used in version 1.x of the compiler, and one new which is the default. This section describes the calling conventions used by the compiler. These items are examined:

At the end of the section, some examples are shown to describe the calling convention in practice.

Note

The V2 calling convention complies with the RL78 ABI standard.

Choosing a calling convention

You can choose between these calling conventions:

  • The V1 calling convention is compatible with the IAR C/C++ Compiler for RL78 version 1.40.x except for how stack arguments are cleaned up. This calling convention is recommended if you have assembler code written for an earlier version of the compiler. To make an individual function use this calling convention, use the __v1_call keyword, for example:

    extern
    __v1_call void doit(int arg);
  • The V2 calling convention complies with the RL78 ABI and is recommended when you link with code produced by a tool from another vendor. To make an individual function use this calling convention, use the __v2_call keyword.

The V2 calling convention is used by default. To make the compiler use the V1 calling convention instead, use the --calling_convention command line option.

In the IDE, choose the calling convention on the Project>General Options>Target page.

Function declarations

In C, a function must be declared in order for the compiler to know how to call it. A declaration could look as follows:

int MyFunction(int first, char * second);

This means that the function takes two parameters: an integer and a pointer to a character. The function returns a value, an integer.

In the general case, this is the only knowledge that the compiler has about a function. Therefore, it must be able to deduce the calling convention from this information.

Using C linkage in C++ source code

In C++, a function can have either C or C++ linkage. To call assembler routines from C++, it is easiest if you make the C++ function have C linkage.

This is an example of a declaration of a function with C linkage:

extern "C"
{
  int F(int);
}

It is often practical to share header files between C and C++. This is an example of a declaration that declares a function with C linkage in both C and C++:

#ifdef __cplusplus
extern "C" 
{
#endif

int F(int);

#ifdef __cplusplus
}
#endif

Registers and bank switching

The compiler only supports switching register banks for interrupt functions, to avoid having to save all registers. Any register banks that you have not used for bank switching, you can use in your assembler source code.

Preserved versus scratch registers

The general RL78 CPU registers are divided into three separate sets, which are described in this section.

Scratch registers

Any function is permitted to destroy the contents of a scratch register. If a function needs the register value after a call to another function, it must store it during the call, for example, on the stack.

The following registers are used as scratch registers:

  • The registers AX, HL, CS and ES. In the V2 calling convention, the BC and DE registers are also scratch registers.

  • Registers that are used as register parameters and for returning values by a function.

Preserved registers

Preserved registers are preserved across function calls (scratch registers are not). The called function can use the register for other purposes, but must save the value before using the register and restore it at the exit of the function.

  • In the V1 calling convention, the registers BC and DE are preserved registers.

  • In the V2 calling convention, no registers are preserved across non-interrupt function calls. Across interrupts, the registers AX, HL, BC, and DE are preserved in the active register bank, and the system registers PC and PSW.

Only registers in the current register bank are preserved. The compiler does not use the other register banks unless you have specified that it shall.

Special registers

For some registers, you must consider certain prerequisites:

  • The stack pointer register must at all times point to or below the last element on the stack. If an interrupt occurs, everything below the point the stack pointer points to will be destroyed.

Function entrance

Parameters can be passed to a function using one of these basic methods:

  • In registers

  • On the stack

It is much more efficient to use registers than to take a detour via memory, so the calling conventions are designed to use registers as much as possible. Only a limited number of registers can be used for passing parameters—when no more registers are available, the remaining parameters are passed on the stack. In the V1 calling convention, the parameters are also passed on the stack in these cases:

  • Structure types: struct, union, and classes, except structs of sizes 1, 2, and 4 (with a minimum alignment of 2 if the size is 2 or 4)

  • Unnamed parameters to variable length (variadic) functions—in other words, functions declared as foo(param1, ...), for example printf.

This means, basically, that objects greater than 4 bytes are passed on the stack and, in the V1 calling convention, all 3-byte objects. For more details, see Register parameters.

Hidden parameters

In addition to the parameters visible in a function declaration and definition, there can be hidden parameters:

  • If the function returns a structure, a pointer to the allocated space is passed as a hidden parameter. Hidden parameters are treated as ordinary parameters.

Register parameters

The registers available for passing parameters are AX, BC, and DE.

Parameters

Passed in registers in this order

V1 calling convention

Passed in registers in this order

V2 calling convention

8-bit values

A, B, C, X, D, E

A, X, C, B, E, D

16-bit values

AX, BC, DE

AX, BC, DE

24-bit values

Passed on the stack

C:AX, X:BC, E:BC, X:DE, B:DE (struct)

A:DE, X:DE, C:DE, B:DE, X:BC (far pointer)

32-bit values

BC:AX

BC:AX, DE:BC

64-bit values

Passed on the stack

Passed on the stack

Table 65. Registers used for passing parameters 


The assignment of registers to parameters is a straightforward process. Traversing the parameters in strict order from left to right, the first parameter is assigned to the available register or registers. Should there be no suitable register available, the parameter is passed on the stack.

Stack parameters and layout

Stack parameters are stored in the main memory, starting at the location pointed to by the stack pointer. Below the stack pointer (toward low memory) there is free space that the called function can use. The first stack parameter is stored at the location pointed to by the stack pointer. The next one is stored at the next location on the stack that is divisible by two, etc. Objects on the stack are stored with alignment 2, which means that 1-byte objects (char) will occupy 2 bytes.

This figure illustrates how parameters are stored on the stack:

Stack_image_high_to_low_70percent.png

Function exit

A function can return a value to the function or program that called it, or it can have the return type void.

The return value of a function, if any, can be scalar (such as integers and pointers), floating-point, or a structure.

Registers used for returning values

The registers available for returning values are A, B, C, and X.

Return values

Passed in registers

V1 calling convention

Passed in registers

V2 calling convention

8-bit values

A

A

16-bit values

AX

AX

24-bit values

A:HL

C:AX (struct)

A:DE (far pointer)

32-bit values

BC:AX

BC:AX

64-bit values

Passed via a pointer

Passed via a pointer

Table 66. Registers used for returning values  


Stack layout at function exit

It is the responsibility of the calling function to clean the stack before function exit, in other words, responsible for cleaning the pushed parameters before the function returns.

Return address handling

A function written in assembler language should, when finished, return to the caller. At a function call, the return address is stored on the stack, for example:

            CALL    func

Typically, a function returns by using the RET instruction.

There are two exceptions to this rule:

  • For interrupt functions, the instruction RETI is used for a function return

  • For the break interrupt, BRK instruction, the instruction RETB is used for a function return.

Bitfield allocation

The two calling conventions use different bitfield allocation strategies:

  • If the V1 calling convention is the default calling convention, bitfield containers of different types cannot overlap in memory (disjoint types allocation)

  • If the V2 calling convention is the default calling convention, you can choose between disjoint types allocation and joined types allocation, where each bitfield is placed in the next container of its base type that has enough available bits to accommodate the bitfield. This allocation strategy is used by default if the V2 calling convention is the default calling convention.

Note that overriding the calling convention for a single function by use of an extended keyword does not affect the bitfield allocation strategy for that function—it is still controlled by the default calling convention for the project. For more information about bitfield allocation, see Bitfields.

Examples

The following section shows a series of declaration examples and the corresponding calling conventions. The complexity of the examples increases toward the end.

Example 1

Assume this function declaration:

int add1(int);

This function takes one parameter in the register AX, and the return value is passed back to its caller in the register AX.

This assembler routine is compatible with the declaration—it will return a value that is one number higher than the value of its parameter:

            name    return
            section CODE:CODE
            public  _add1
add1:            
            incw    ax
            ret
            end
Example 2

This example shows how structures are passed on the stack. Assume these declarations:

struct MyStruct 
{ 
  short a;
  short b;
  short c;
  short d;
  short e;
};

int MyFunction(struct MyStruct x, int y);

The calling function must reserve 10 bytes on the top of the stack and copy the contents of the struct to that location. The integer parameter y is passed in the register AX. The return value is passed back to its caller in the register AX.

Example 3

The function below will return a structure of type struct MyStruct.

struct MyStruct 
{ 
  int mA[20]; 
};

struct MyStruct MyFunction(int x);

It is the responsibility of the calling function to allocate a memory location for the return value and pass a pointer to it as a hidden first parameter. If you are using the near data model, the pointer to the location where the return value should be stored is passed in AX. The caller assumes that these registers remain untouched. The parameter x is passed in BC.

Assume that the function instead was declared to return a pointer to the structure:

struct MyStruct *MyFunction(int x);

In this case, the return value is a pointer, so there is no hidden parameter. The parameter x is passed in AX, and the return value is returned in AX.