3.3.7.5 What Things Must I Manage When Writing Assembly Code?

When writing assembly code by hand, you assume responsibility for managing certain features of the device and formatting your assembly instructions and operands. The following list describes some of the actions you must take.

  • Whenever you access a RAM variable, you must ensure that the bank of the variable is selected before you read or write the location. This is done by one or more assembly instructions. The exact code is based on the device you are using and the location of the variable. Bank selection is not be required if the object is in common memory, (which is called the access bank on PIC18 devices) or if you are using an instruction that takes a full address (such as the movff instruction on PIC18 devices). Check your device data sheet to see the memory architecture of your device, as well as the instructions and registers which control bank selection. Failure to select the correct bank will lead to code failure.
The BANKSEL pseudo instruction can be used to simplify this process (see 6.1.1.2 Bank And Page Selection).
  • You must ensure that the address of the RAM variable you are accessing has been masked so that only the bank offset is being used as the instruction’s file register operand. This should not be done if you are using an instruction that takes a full address (such as the movff instruction on PIC18 devices). Check your device data sheet to see what address operand instructions requires. Failure to mask an address can lead to a fixup error (see 3.6.8 How Do I Fix a Fixup Overflow Error?) or code failure.
The BANKMASK macro can truncate the address for you (see 5.12.3.4 Accessing Registers From Assembly Code).
  • Before you call or jump to any routine, you must ensure that you have selected the program memory page of this routine using the appropriate instructions. You can either use the PAGESEL pseudo instruction (see 6.1.1.2 Bank And Page Selection), or the fcall or ljmp pseudo instructions (not required on PIC18 devices) (see 6.1.1.7 Long Jumps And Calls ) which will automatically add page selection instructions, if required.
  • You must ensure that any RAM used for storage has memory reserved. If you are only accessing variables defined in C code, then reservation is already done by the compiler. You must reserve memory for any variables you only use in the assembly code using an appropriate directive such as DS or DABS (see 6.1.9.13 Ds Directive or 6.1.9.8 Dabs Directive). It is often easier to define objects in C code rather than in assembly code.
  • You must place any assembly code you write in a psect (see 6.1.9.39 Psect Directive for the directive to do this, and 5.15.1 Compiler-Generated Psects for general information about psects). A psect that you define may need flags (options) to be specified. Take particular notice of the delta, space, reloc and class flags (see 6.1.9.39.4 Delta Flag and 6.1.9.39.18 Space Flag 6.1.9.39.16 Reloc Flag and 6.1.9.39.3 Class Flag). If these are not set correctly, compile errors or code failure will almost certainly result. If the psect specifies a class and that psect can be placed anywhere in the memory range defined by that class (see 7.1.1 A: Define Linker Class Option), you do not need to specify any options for it to be linked; otherwise, you will need to link the psect using a linker option (see 7.1.18 P: Position Psect for the usual way to link psects and 4.6.11.8 Wl: Pass Option To The Linker, Option which indicates how you can specify this option without running the linker directly).
Assembly code that is placed in-line with C code will be placed in the same psect as the compiler-generated assembly and you should not place this into a separate psect.
  • You must ensure that any registers you write to in assembly code are not already in used by compiler-generated code. If you write assembly in a separate module, then this is less of an issue because the compiler will, by default, assume that all registers are used by these routines (see 5.6 Register Usage). No assumptions are made for in-line assembly (although the compiler will assume that the selected bank was changed by the assembly, see 5.12.2 Inline Assembly) and you must be careful to save and restore any resources that you use (modify) and which are already in use by the surrounding compiler-generated code.