5.12.3.4 Accessing Registers From Assembly Code
Special Function Registers (SFRs) can be accessed in assembly code using special symbols defined by the compiler. See How Do I Find The Names Used To Represent SFRs And Bits? for assistance on finding SFR names.
In separate assembly modules, the assembly header file <xc.inc> can be used to gain access to SFR definitions. Do not use this file for assembly in-line with C code as it will clash with definitions in <xc.h>. Include the <xc.inc> header file using the C preprocessor’s #include directive. Make sure you use a .S extension for the assembly source file.
The symbols for registers in this header file look similar to the identifiers provided by <xc.h> in the C domain, for example, PORTA and EECON1. They are different symbols to those in the C domain, but they will map to the same memory location as their C counterparts.
The names of bits within SFRs are available and are defined as registerName, bitNumber with address masking. This makes them usable in bit-orientated assembly instructions. So, for example, RA0 is defined as BANKMASK(PORTA), 0.
#include <xc.inc>
GLOBAL _setports
PSECT text,class=CODE,local,delta=2
_setports:
movlw 0xAA
BANKSEL (PORTA)
movwf BANKMASK(PORTA) ;write 0xAA to PORTA
BANKSEL (PORTB)
bsf RB1 ;set bit #1 in PORTBIf you wish to access register definitions from assembly that is in-line with C code, ensure that the <xc.h> header is included into the C module. Information included by this header will define in-line assembly symbols as well as the usual symbols accessible from C code.
<xc.inc> header. The example given previously could be rewritten as in-line assembly as follows.#include <xc.h>
int main(void) {
asm("movlw 0xAA");
asm("BANKSEL (PORTA)");
asm("movwf " ___mkstr(BANKMASK(PORTA))); ;write 0xAA to PORTA
asm("BANKSEL (PORTB)");
asm("bsf " RB1_bit); ;set bit #1 in PORTB
}Note that BANKMASK() is a predefined preprocessor macro, and thus it will not be expanded inside a C string literal. If you want to use the BANKMASK() macro within in-line assembly, convert the macro’s replacement to a string using the ___mkstr() macro (note: three leading underscore characters), defined by the inclusion of <xc.h>.
The RB1_bit operand, which represents bit #1 of PORTB, is also a predefined macro defined by the inclusion of <xc.h>. It makes use of another macro called _BIT_ACCESS, which converts the byte and bit number operands to a string, ready to be used by the in-line assembly instruction.
The code generator does not detect when SFRs could be modified by in-line assembly, so these registers might need to be preserved before the in-line assembly code and restored afterward. The list of registers used by the compiler and further information can be found in Register Usage.
