C166 Interfacing C to Assembler
Interfacing C to Assembler
You can easily interface your C programs to routines written in XC16x/C16x/ST10 assembly language.
The A166 Assembler is a macro assembler that emits object modules in OMF166 format.
By following a few programming rules, you can call assembly routines from C and vice versa.
Public variables declared in the assembly module are available to your C programs.
There are several reasons to call an assembly routine from your C program.
- You have assembly code already written that you wish to use.
- You need to improve the speed of a particular function.
- You want to manipulate SFRs or memory-mapped I/O devices directly from assembly.
This section describes how to write assembly routines that can be directly interfaced to C programs.
For an assembly routine to be called from C, it must be aware of the parameter passing
and return value conventions used in C functions.
For all practical purposes, the assembly routine must appear to be a C function.
Function Parameters
C functions pass up to five parameters in registers (R8-R12).
Bit parameters are passed in R15.
Parameters that do not fit into R8-R12 are passed on the user stack
and are accessed using [R0+#disp] instructions.
The following examples demonstrate the C166 parameter passing conventions:
void func1 ( char a) /* 1st parameter passed in R8 */
The above function has one argument that easily fits into a single 16-bit register (R8).
void func2 ( int b, /* 1st parameter passed in R8 */ int c, /* 2nd parameter passed in R9 */ int near *d, /* 3rd parameter passed in R10 */ char e, /* 4th parameter passed in R11 */ char f) /* 5th parameter passed in R12 */
The above function has five arguments. All fit into R8-R12.
void func3 ( long g, /* 1st parameter passed in R8/R9 */ int far *h, /* 2nd parameter passed in R10/R11 */ int i, /* 3rd parameter passed in R12 */ long j) /* 4th parameter cannot be located in registers */
The above function has four arguments. The first three use all available registers. The fourth argument must be passed on the user stack.
void func4 ( double k, /* 1st parameter passed in R8/R9/R10/R11 */ long j) /* 2nd parameter LSW passed in R12 */ /* MSW passed on the user stack */
The above function has two arguments. The first argument uses four of the five registers.
The LSW of the second argument is passed in R12 and the MSW is passed on the user stack.
void func5 ( bit m, /* 1st parameter passed in R15.0 */ bit n) /* 2nd parameter passed in R15.1 */
The above function has two bit arguments that passed in R15.
void func6 ( char o, /* 1st parameter passed in R8 */ bit p, /* 2nd parameter passed in R15.0 */ char q, /* 3rd parameter passed in R9 */ bit r) /* 4th parameter passed in R15.1 */
The above function has four arguments (two are bits) that are passed in registers and in R15 (for the bits).
Function Return Values
Function return values are always passed using MCU registers.
The following table lists the possible return values and the registers used for each.
Return Type | Register | Description |
---|---|---|
bit | R4.0 | Single bit returned in R4.0. |
char, unsigned char |
RL4 | Single byte type returned in RL4. |
int, unsigned int, near pointer |
R4 | Two byte (16-bit) type returned in R4. |
long, unsigned long, far pointer, huge pointer |
R4 & R5 | LSB in R4, MSB in R5. |
float | R4 & R5 | 32-Bit IEEE format. |
double | R4-R7 | 64-Bit IEEE format. |
Register Usage
Assembler functions may destroy the contents of R1-R12, PSW, MDL, MDH, MDC, and DPP0.
When invoking a C function from assembly, assume that these registers are destroyed.
When using the MAC directive the compiler uses in addition the MAC registers MSW, MAL, MAH, MRW, and IDX0.
When code is generated with the MAC directive, these registers are used by C functions (in addition to the register listed above).
When invoking a C function form assembly you need therefore to assume that these registers are destroyed too.
The following registers have special meaning and must be preserved by the assembler subroutine.
Register | Description |
---|---|
R0 |
R0 is the user stack pointer. |
R13 |
This register may be used but its contents must be saved (on entry) and restored (before returning). |
R14 |
This register may be used but its contents must be saved (on entry) and restored (before returning). |
R15 |
This register may be used but its contents must be saved (on entry) and restored (before returning). |
DPP1 |
This DPP register may not be modified by assembler subroutines. |
DPP2 |
This DPP register may not be modified by assembler subroutines. |
DPP3 |
If DPP3 is modified in the assembler subroutine, it must be reset to 3 (SYSTEM PAGE) before returning. |
Note
- DPP0 is used only when the MOD167 C166 Compiler directive is not specified.
- If your assembler programs alter DPP0, the DPPUSE L166 Linker directive may not be used to assign DPP0 to the near memory area.
- If your assembler programs alter DPP0 or DPP3, the NODPPSAVE C166 Compiler directive may not be used to bypass saving and restoring DPP0 and DPP3 in interrupts.