4.1.3 Address Masking
All assembly identifiers represent a full address. The upper bits of a file register address represent the bank number of the object. Similarly, the upper bits of a program memory address represent the page number of the destination label. Such addresses might not be immediately usable as operands to some PIC instructions and might need to be masked or truncated to fit within the instruction's address field.
There are two ways of handling addresses when they are used as an instruction operand. The first is to have the linker automatically truncate these addresses to suite the instruction. The second is to manually mask the bank or page bits from the address. Both approaches have advantages. Automatic truncation is by far the easiest to use and does not clutter your assembly source with ancillary expressions in instruction operands, but this truncation is applied to all operands of all instructions in your program, and it might hide genuine errors that would otherwise be issued. Masking operands manually must be performed whenever needed but can be done in such a way that it confirms assumptions you have made regarding the location of the object, increasing the reliability of your program.
-Wl,--fixupoverflow=action
option and one of the
warn
, lstwarn
, or ignore
action
arguments. See 6.1.31 Fixupoverflow Linker Option for
more information on this option. Note that this option (except when an action argument of
error
is used) will suppress fixup overflow errors associated with all
instructions in your program. It is recommended that you
select an action argument of warn
or lstwarn
so that the
generated warnings will help you confirm that there is no potential for program failure. If
you are using this option to suppress fixup overflow errors, you do not need to mask the
addresses used with any instructions, for
example:BANKSEL flags ;select data bank of flags
subwf flags ;use flags without masking its address
PAGESEL myFunc ;select the page of myFunc
call myFunc ;use myFunc without masking its address
BANKMASK()
macro. To manually mask a program address used with the call
and
goto
flow control instructions, use the PAGEMASK()
macro. Both these macros AND out the bank or page information in the address using a
suitable device-specific mask. They are available once you include
<xc.inc>
into a source module. Use of these macros (rather than
manually using the AND operator, &
) increases code portability across
Microchip devices, since they adjust the mask to suit the bank or page size of the target
device. The following code masks the addresses used by the subwf
and
call
instructions:BANKSEL flags ;select data bank of flags
subwf BANKMASK(flags) ;remove bank bits from address to prevent fixup overflow
PAGESEL myFunc ;select the page of myFunc
call PAGEMASK(myFunc) ;remove page bits from address to prevent fixup overflow
Rather than ANDing out the bank information in an address using either the
BANKMASK()
or PAGEMASK()
macros, the address can be
XORed ( ^
operator) with a bitmask that represents the expected bank or
page bits in the address. If the address falls in the bank or page that was expected, then
the upper bits of the bitmask and address will XOR to zero; if this is not the case, the
XOR will produce a non-zero component in the upper bits of the address and trigger a fixup
overflow error from the linker (assuming this error has not been disabled by the
-Wl,--fixupoverflow
option).
flags
. The flags
symbol has been XORed with the mask 0x100, which represents the bitmap of bank 2 addresses
with the address offset
zeroed.movlb 2 ;select bank 2
subwf flags^0x100
If flags
was linked at address 0x153 (a bank
2 address), then 0x153^0x100 will result in the value 0x53, which fits into the address
field of the subwf
instruction. If flags
was accidentally
linked to address 0x34 (a bank 0 address), then 0x34^0x100 yields the result 0x134, which
is too large to fit into the 7-bit wide address field of the subwf
instruction and which will trigger a fixup overflow error, alerting you to the problem.Do not use the BANKMASK()
or PAGESEL()
macros with any instruction that expects its operand to be a full address, such as the
PIC18’s movff
instruction for example.
Note that address masking is a fundamentally different operation to bank or page selection.
Neither the -Wl,--fixupoverflow
option nor the BANKMASK()
or PAGEMASK()
macros select the bank or page of the object being accessed,
called, or jumped to. Regardless of how you handle address masking, you must always ensure
that your program contains the instructions to select the correct bank or page when
required, as described in 4.1.2 Bank And Page Selection. The one exception is when you use the fcall
and/or
ljmp
pseudo instructions (see 4.1.7 Long Jumps And Calls), which perform both
page selection and address masking for you.