3.3 File Register Address Masking
- Use the
-Wl,--fixupoverflow=ignore|warn|lstwarnoption to request that the linker automatically truncate all instruction operands to a size that suits the instruction. This approach is the most compatible with MPASM code, but all instruction operands are truncated. - Use the
-Wl,--fixupoverflow==erroroption and mask out the bank value from the address using theBANKMASK()macro. This approach is safer as it only truncates the addresses you specify.
Note that some instructions require operands with a full address, for example the
movff and movffl PIC18 instructions and this
section, does not apply to these instructions. Note also that although address masking
using the latter of the above techniques is not required if the object being accessed is
in bank 0 (since its bank value will already be 0), it is good practice to mask all
address operands in case the object is moved later in program development.
The value of a label in data memory (for example the label associated with an object or
variable) is always the full address of where the label was positioned. The upper bits
of such an address come from the bank value of the label (its bank number, which is
preloaded into the appropriate register by the BANKSEL directive) and
the lower order bits being the offset into that bank. Most PIC instructions accessing
data memory require only the offset within a bank to be specified for the file register
operand, with the bank value having been preselected by an instruction sequence executed
earlier. For these instructions, the upper bits of the address operand, which indicate
the bank 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 bank information present.
For both approaches shown above, you must ensure that the required bank is selected
before accessing the memory location. This is typically done using the
BANKSEL assembler directive. The operation of this directive is
identical in MPASM and the PIC Assembler.
If you decide to follow the first approach, use the
-Wl,--fixupoverflow=action option and one of
the warn, lstwarn, or ignore action
arguments. 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.
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, object 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.| MPASM code | Equivalent PIC-AS code |
|---|---|
|
|
BANKMASK() macro, available once you include
<xc.inc>. This macro will perform the AND operation using the
correct mask value, based on the selected device. 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 bank value
removed. Using the BANKMASK() macro is the most portable way to
manually mask an address and its use is shown in the following migration table.| MPASM code | Equivalent PIC-AS code |
|---|---|
|
|
In addition to the above migration approaches, there is an alternate way that addresses can be masked using an XOR operation. This gives you the opportunity to perform additional checks that ensure your assumptions about the location of objects are correct.
-Wl,--fixupoverflow=error option and XOR the address with a
value that will clear the expected bank value but leave the bank offset
unchanged. Such a value will have zeros in the bank offset locations and specify the bit
pattern of the bank in which the object is expected to be located as the bank value. So,
for example, XOR the address operand with the mask 0x100 on PIC18 devices if the operand
is assumed to be the address of an object in bank 1; XOR with 0x300 if it meant to be an
object in bank 3. On Mid-range devices, XOR with 0x80 for bank 1 objects; 0x180 for bank
3 objects. On Baseline devices, XOR with 0x20 for bank 1 objects; 0x60 for bank 3
objects, etc. In the following Mid-range example, an error will be produced if
src is not in bank 1 or if dst is not in bank
2.copy:
BANKSEL 1 ;select src bank (or use 'BANKSEL src')
movf src^080h,w ;masked bank 1 address
BANKSEL 2 ;select dst bank (or use 'BANKSEL dst')
movwf dst^0100h ;masked bank 2 addressscr and
dst are now in the same bank. As a result, only one bank selection
sequence was used before accessing both these objects. An XOR can be performed using
these two symbols to ensure that the assumption regarding their location is valid. In
the last instruction, the expression src&0FF80h obtains the bank
value for src. This value is then XORed with the full address of
dst.#include <xc.inc>
copy:
BANKSEL src ;select src bank
movf BANKMASK(src),w ;move from masked src address
movwf dst^(src&0FF80h) ;move to masked dst address in the same bank as srcIf scr and dst in the above code are linked in the same
bank as it was assumed, then the XOR of the bits representing their bank values will be
0, effectively masking the bank value from the operand address to the
movwf instruction. If src and dst
are instead linked into different banks, the XOR will yield non-zero bits in the bank
value that will trigger an error, thus confuting the programmer's assumption and
preventing the code from failing at runtime. This is a case where it does not matter
what bank these objects are in, but they must both be in the same bank for the code to
execute correctly.
