3.4 Program Flow and Address Masking

On Baseline and Mid-range PIC devices, the call and goto flow control instructions require the destination page of the call or jump to be preselected and the upper bits of the destination address (referred to here as the page number) removed to prevent build errors. There are three approaches you can follow to use flow control instructions when using the PIC Assembler.

  • Use a page selection sequence prior to call and goto instructions, plus use the -Wl,--fixupoverflow=ignore|warn|lstwarn option, which will automatically truncate all instruction operands to the required size. This approach is the most compatible with MPASM code, but all instruction operands are truncated.
  • Use a page selection sequence prior to call and goto instructions, as well as the -Wl,--fixupoverflow=error option, then manually mask out the page values from destination operand addresses using the PAGEMASK() macro. This approach is efficient for new code and only truncates the addresses you specify.
  • Use the fcall and ljmp pseudo instructions to have both page selection and address masking applied automatically. This approach is the easiest for new code but might not be the most efficient.

Note that on PIC18 devices, these same flow control instructions can reach any program memory destination specified with a valid label operand, and this section does not concern code written for such devices.

If you decide to follow the first approach when using Baseline or Mid-range devices, the page of a routine can be preselected by using the PAGESEL directive. The operation of this directive is identical in MPASM and the PIC Assembler.

It is first helpful to understand how PIC Assembler addresses are comprised. The value of a label in program memory (for example the label associated with a routine) is always the full address of where the label was positioned. The upper bits of such an address come from the page value of the destination label (its page number, which is preloaded into the PCLATH register by the PAGESEL directive) and the lower order bits being the offset into that page. The flow control instructions require only the offset within a page to be specified for the operand, so the upper bits of the address operand, which indicate the page value, must be removed (zeroed). The PIC Assembler will issue a fixup overflow error (for symbolic operands) or warning (for absolute operands) should it detect that these instructions have an operand with superfluous page information present.

The first approach has the linker automatically truncate all addresses to fit the instruction. To do this, use the -Wl,--fixupoverflow=action option and one of the ignore, warn, or lstwarn action arguments to prevent any fixup overflow errors from being issued. The lstwarn argument is the default if the option not specified. See the MPLAB® XC8 PIC® Assembler User's Guide for full information on this feature.

To have the PIC Assembler exactly mimic the behavior of MPASM, use the ignore action argument. This will tell the linker to truncate instruction operands with no warning, similar to how MPASM operates. Note, however, that the linker will truncate all operands for all instructions in your program. In some situations, an operand that is too large to fit the relevant field in the instruction might indicate a flaw in the program design. It is recommended that you select an action argument of warn or lstwarn, or both (colon-separated), as these modes of operation will have the linker issue a warning when it truncates a value so that you can confirm there is no potential for program failure. If you are using this option with any of the warn, lstwarn, or ignore action arguments, destination labels can be used in instructions without modification, as shown in the following comparison table, where example MPASM code and the equivalent PIC-AS code are identical.
Table 3-4. Migrating flow control instruction when using the first migration approach (-Wl,--fixupoverflow= ignore|warn|lstwarn)
MPASM codeEquivalent PIC-AS code
process:
  PAGESEL  init    ;select init page
  call     init
  PAGESEL  loop    ;select loop page
  goto     loop
process:
  PAGESEL  init    ;select init page
  call     init
  PAGESEL  loop    ;select loop page
  goto     loop

When using the second approach, page selection again takes place using the PAGESEL directive.

To remove the bank value following the second approach, perform a bitwise AND of the address operand using the PAGEMASK() macro, available once you include <xc.inc>. This macro will perform the AND operation using the correct mask value, based on the selected device and can be used with both call and goto instructions. Next, specify the -Wl,--fixupoverflow=error option, which will force the linker to generate an error should it encounter any operand that has not had its page value removed. Using the PAGEMASK() macro is the most portable way to manually mask an address, and its use is shown in the following migration table.
Table 3-5. Migrating flow control instruction when using the second migration approach (-Wl,--fixupoverflow= error)
MPASM codeEquivalent PIC-AS code
process:
  PAGESEL  init    ;select init page
  call     init
  PAGESEL  loop    ;select loop page
  goto     loop
process:
  PAGESEL  init    ;select init page
  call     PAGEMASK(init)
  PAGESEL  loop    ;select loop page
  goto     PAGEMASK(loop)

The third approach is to again use the -Wl,--fixupoverflow=error option but to use pseudo call and jump instructions supplied by the PIC Assembler to perform both page selection and destination address masking for you. See the MPLAB® XC8 PIC® Assembler User's Guide for full information on these instructions.

The fcall pseudo instruction will expand into a regular call instruction, and the ljmp pseudo instruction will expand into a regular goto instruction, both with the destination address correctly masked. Additionally, both pseudo instructions will insert a page selection sequence prior to and after the call or jump to ensure that the correct destination is reached and that the current page is selected afterward. Do not mask the address operand of these pseudo instructions in any way; they use the full address to determine the page of the destination.
Table 3-6. Migrating flow control when using the third migration approach (-Wl,--fixupoverflow= error)
MPASM codeEquivalent PIC-AS code
process:
  PAGESEL  init    ;select init page
  call     init
  PAGESEL  loop    ;select loop page
  goto     loop
process:
  fcall     init
  ljmp      loop

Although this is the easiest way to write source code, it may result in page selection instructions that are redundant, and hence increase code size. You should also remember that these pseudo instructions can expand into more than one device instruction, and so they should not be placed immediately after any test-and-skip instruction, like the btfsc instruction, for example.