4.11.1 Integrating Assembly Language Modules
Entire functions can be coded in assembly language as separate .s (or .S) source files included into your project. They will be assembled and combined into the output image by the linker.
The following are guidelines that must be adhered to when writing a C-callable assembly routine.
- Include the
<xc.h>
header file in your code. If this is included using#include
, ensure the extension used by the source file is .S to ensure the file is preprocessed. - Select or define a suitable section for the executable assembly code (see 4.14.1 Compiler-Generated Sections for an introductory guide).
- Select a name (label) for the routine
- Ensure that the routine’s label is accessible from other modules
- Use macros like
_SFR_IO_ADDR
to obtain the correct SFR address to use with instructions that can access the IO memory space. - Select an appropriate C-equivalent prototype for the routine on which argument passing can be modeled.
- If values need to be passed to or returned from the routine, use the appropriate registers to passed the arguments.
The following example shows an assembly routine for an atmega103 device
that takes an int
parameter, adds this to the content of PORTD, and
returns this as an int
.
#include <xc.h>
.section .text
.global plus ; allow routine to be externally used
plus:
; int parameter in r24/5
in r18, _SFR_IO_ADDR(PORTD) ; read PORTD
add r24, r18 ; add to parameter
adc r25, r1 ; add zero to MSB
; parameter registers are also the return location, so ready to return
ret
.end
The code has been placed in a .text
section, so it will
be automatically placed in the area of memory set aside for code without you having to
adjust the default linker options.
The _SFR_IO_ADDR
macro has been used to ensure that the
correct address was specified to instructions that read the IO memory space.
Because the C preprocessor #include
directive and
preprocessor macros were used, the assembly file must be preprocessed to ensure it uses a
.S extension when compiled.
To call an assembly routine from C code, a declaration for the routine must be provided. Here is a C code snippet that declares the operation of the assembler routine, then calls the routine.
// declare the assembly routine so it can be correctly called
extern int plus(int);
void main(void) {
volatile unsigned int result;
result = plus(0x55); // call the assembly routine
}