| |||
| Home > Writing ARM and Thumb Assembly Language > Describing data structures with MAP and FIELD directives > Avoiding problems with MAP and FIELD directives | |||
Using MAP and FIELD directives can
help you to produce maintainable data structures. However, this
is only true if the order the elements are placed in memory is not important
to either the programmer or the program.
You can have problems if you load or store multiple elements of a structure in a single instruction. These problems arise in operations such as:
loading several single-byte elements into one register
using a store multiple or load multiple instruction
(STM and LDM) to store or load multiple
words from or to multiple registers.
These operations require the data elements in the structure to be contiguous in memory, and to be in a specific order. If the order of the elements is changed, or a new element is added, the program is broken in a way that cannot be detected by the assembler.
There are several methods for avoiding problems such as this.
Example 2.27 shows a sample structure.
Example 2.27.
MiscBase RN r10
MAP 0,MiscBase
MiscStart FIELD 0
Misc_a FIELD 1
Misc_b FIELD 1
Misc_c FIELD 1
Misc_d FIELD 1
MiscEndOfChars FIELD 0
MiscPadding FIELD (-:INDEX:MiscEndOfChars) :AND: 3
Misc_I FIELD 4
Misc_J FIELD 4
Misc_K FIELD 4
Misc_data FIELD 4*20
MiscEnd FIELD 0
MiscLen EQU MiscEnd-MiscStart
There is no problem in using LDM and STM instructions
for accessing single data elements that are larger than a word (for
example, arrays). An example of this is the 20-word element Misc_data.
It could be accessed as follows:
ArrayBase RN R9
ADR ArrayBase, MiscBase
LDMIA ArrayBase, {R0-R5}
Example 2.27 loads
the first six items in the array Misc_data. The
array is a single element and therefore covers contiguous memory
locations. No one is likely to want to split it into separate arrays
in the future.
However, for loading Misc_I, Misc_J,
and Misc_K into registers r0, r1, and r2 the following
code works, but might cause problems in the future:
ArrayBase RN r9
ADR ArrayBase, Misc_I
LDMIA ArrayBase, {r0-r2}
Problems arise if the order of Misc_I, Misc_J,
and Misc_K is changed, or if a new element Misc_New is
added in the middle. Either of these small changes breaks the code.
If these elements are accessed separately elsewhere, you must not amalgamate them into a single array element. In this case, you must amend the code. The first remedy is to comment the structure to prevent changes affecting this section:
Misc_I FIELD 4 ; ==} Do not split/reorder Misc_J FIELD 4 ; } these 3 elements, STM Misc_K FIELD 4 ; ==} and LDM instructions used.
If the code is strongly commented, no deliberate changes are
likely to be made that affect the workings of the program. Unfortunately,
mistakes can occur. A second method of catching these problems is
to add ASSERT directives just before the STM and LDM instructions
to check that the labels are consecutive and in the correct order:
ArrayBase RN R9
; Check that the structure elements
; are correctly ordered for LDM
ASSERT (((Misc_J-Misc_I) = 4) :LAND: ((Misc_K-Misc_J) = 4))
ADR ArrayBase, Misc_I
LDMIA ArrayBase, {r0-r2}
This ASSERT directive stops assembly at this
point if the structure is not in the correct order to be loaded
with an LDM. Remember that the element with the lowest
address is always loaded from, or stored to, the lowest numbered
register.