Mixing C and assembler
The IAR C/C++ Compiler for RL78 provides several ways to access low-level resources:
Modules written entirely in assembler
Intrinsic functions (the C alternative)
Inline assembler.
It might be tempting to use simple inline assembler. However, you should carefully choose which method to use.
Intrinsic functions
The compiler provides a few predefined functions that allow direct access to low-level processor operations without having to use the assembler language. These functions are known as intrinsic functions. They can be useful in, for example, time-critical routines.
An intrinsic function looks like a normal function call, but it is really a built-in function that the compiler recognizes. The intrinsic functions compile into inline code, either as a single instruction, or as a short sequence of instructions.
The advantage of an intrinsic function compared to using inline assembler is that the compiler has all necessary information to interface the sequence properly with register allocation and variables. The compiler also knows how to optimize functions with such sequences—something the compiler is unable to do with inline assembler sequences. The result is that you get the desired sequence properly integrated in your code, and that the compiler can optimize the result.
For more information about the available intrinsic functions, see Intrinsic functions.
Mixing C and assembler modules
It is possible to write parts of your application in assembler and mix them with your C or C++ modules.
This gives several benefits compared to using inline assembler:
The function call mechanism is well-defined
The code will be easy to read
The optimizer can work with the C or C++ functions.
This causes some overhead in the form of a CALL and a RET instruction, and the compiler will regard some registers as scratch registers. However, the compiler will also assume that all registers are destroyed by an inline assembler instruction. In many cases, the overhead of the extra instructions can be removed by the optimizer.
An important advantage is that you will have a well-defined interface between what the compiler produces and what you write in assembler. When using inline assembler, you will not have any guarantees that your inline assembler lines do not interfere with the compiler generated code.
When an application is written partly in assembler language and partly in C or C++, you are faced with several questions:
How should the assembler code be written so that it can be called from C?
Where does the assembler code find its parameters, and how is the return value passed back to the caller?
How should assembler code call functions written in C?
How are global C variables accessed from code written in assembler language?
Why does not the debugger display the call stack when assembler code is being debugged?
The first question is discussed in Calling assembler routines from C. The following two are covered in Calling convention.
The answer to the final question is that the call stack can be displayed when you run assembler code in the debugger. However, the debugger requires information about the call frame, which must be supplied as annotations in the assembler source file. For more information, see Call frame information.
The recommended method for mixing C or C++ and assembler modules is described in Calling assembler routines from C, and Calling assembler routines from C++, respectively.
Note
To comply with the RL78 ABI, the compiler generates assembler labels for symbol and function names by prefixing an underscore. You must remember to add this extra underscore when you access C symbols from assembler. For example, main must be written as _main.
Similarly, when referencing an external assembly module from C, an underscore will be added to the symbol used in the C module, so the name of the assembly module must start with an added underscore.