5.9.7.  Using register-based MAP and # directives

Register-based MAP and # directives define register-based symbols. There are two main uses for register-based symbols:

Defining register-based symbols

Register-based symbols can be very useful, but you must be careful when using them. As a general rule, use them only in the following ways:

  • As the location for a load or store instruction to load from or store to. If Location is a register-based symbol based on the register Rb and with numeric offset, the assembler automatically translates, for example, LDR Rn,Location into LDR Rn,[Rb,#offset].

    In an ADR or ADRL instruction, ADR Rn,Location is converted by the assembler into ADD Rn,Rb,#offset.

  • Adding an ordinary numeric expression to a register-based symbol to get another register-based symbol.

  • Subtracting an ordinary numeric expression from a register-based symbol to get another register-based symbol.

  • Subtracting a register-based symbol from another register-based symbol to get an ordinary numeric expression. Do not do this unless the two register-based symbols are based on the same register. Otherwise, you have a combination of two registers and a numeric value. This results in an assembler error.

  • As the operand of a :BASE: or :INDEX: operator. These operators are mainly of use in macros.

Other uses usually result in assembler error messages. For example, if you write LDR Rn,=Location, where Location is register-based, you are asking the assembler to load Rn from a memory location that always has the current value of the register Rb plus offset in it. It cannot do this, because there is no such memory location.

Similarly, if you write ADD Rd,Rn,#expression, and expression is register-based, you are asking for a single ADD instruction that adds both the base register of the expression and its offset to Rn. Again, the assembler cannot do this. You must use two ADD instructions to perform these two additions.

Setting up a C-type structure

There are two stages to using structures in C:

  • declaring the fields that the structure contains

  • generating the structure in memory and using it.

For example, the following typedef statement defines a point structure that contains three float fields named x, y and z, but it does not allocate any memory. The second statement allocates three structures of type Point in memory, named origin, oldloc, and newloc:

typedef struct Point 
{
	float x,y,z;
} Point;
Point origin,oldloc,newloc;

The following assembly language code is equivalent to the typedef statement above:

PointBase			RN		r11
			MAP		0,PointBase
Point_x			#		4
Point_y			#		4
Point_z			#		4

The following assembly language code allocates space in memory. This is equivalent to the last line of C code:

origin		%		12
oldloc		%		12
newloc		%		12

You must load the base address of the data structure into the base register before you can use the labels defined in the map. For example:

		LDR		PointBase,=origin
		MOV     r0,#0
		STR     r0,Point_x
		MOV     r0,#2
		STR     r0,Point_y
		MOV     r0,#3
		STR     r0,Point_z

is equivalent to the C code:

origin.x = 0;
origin.y = 2;
origin.z = 3;

Making faster access possible

To gain faster access to an area of memory:

  1. Describe the memory area as a structure.

  2. Use a register to address the structure.

For example, consider the definitions in Example 5.22.

Example 5.22. 

StartOfData				EQU		0x1000
EndOfData				EQU		0x2000
				MAP		StartOfData
Integer				#		4
String				#		MaxStrLen
Array				#		ArrayLen*8
BitMask				#		4
EndOfUsedData				#		0
				ASSERT  EndOfUsedData <= EndOfData

If you want the equivalent of the C code:

Integer = 1;
String = "";
BitMask = 0xA000000A;

With the definitions as above, the assembly language code could be as in Example 5.23.

Example 5.23. 

		MOV 		r0,#1
		LDR     r1,=Integer
		STR     r0,[r1]
		MOV     r0,#0
		LDR     r1,=String
		STRB    r0,[r1]
		MOV     r0,#0xA000000A
		LDR     r1,=BitMask
		STRB    r0,[r1]

Example 5.23 uses LDR pseudo-instructions. See Loading with LDR Rd, =const for an explanation of these.

Example 5.23 contains separate LDR pseudo-instructions to load the address of each of the data items. Each LDR pseudo-instruction is converted to a separate instruction by the assembler. However, it is possible to access the entire data area with a single LDR pseudo-instruction. Example 5.24 shows how to do this. Both speed and code size are improved.

Example 5.24. 

				AREA		data, DATA
StartOfData				EQU		0x1000
EndOfData				EQU		0x2000
DataAreaBase				RN		r11
				MAP		0,DataAreaBase
StartOfUsedData				#		0
Integer				#		4
String				#		MaxStrLen
Array				#		ArrayLen*8
BitMask				#		4
EndOfUsedData				#		0
UsedDataLen				EQU		EndOfUsedData - StartOfUsedData
				ASSERT  		UsedDataLen <= (EndOfData - StartOfData)
				AREA		code, CODE
				LDR     DataAreaBase,=StartOfData
				MOV     r0,#1
				STR     r0,Integer
				MOV     r0,#0
				STRB    r0,String
				MOV     r0,#0xA000000A
				STRB    r0,BitMask

Note

The MAP directive is

MAP 0, DataAreaBase,

not

MAP StartOfData,DataAreaBase.

The MAP and # directives give the position of the data relative to the DataAreaBase register, not the absolute position. The LDR DataAreaBase,=StartOfData statement provides the absolute position of the entire data area.

If you use the same technique for an area of memory containing memory mapped I/O (or whose absolute addresses must not change for other reasons), you must take care to keep the code maintainable.

One method is to add comments to the code warning maintainers to take care when modifying the definitions. A better method is to use definitions of the absolute addresses to control the register-based definitions.

Using MAP offset,reg followed by label # 0 makes label into a register-based symbol with register part reg and numeric part offset. Example 5.25 shows this.

Example 5.25. 

StartOfIOArea				EQU		0x1000000
SendFlag_Abs				EQU		0x1000000
SendData_Abs				EQU		0x1000004
RcvFlag_Abs				EQU		0x1000008
RcvData_Abs				EQU		0x100000C
IOAreaBase				RN		r11
				MAP		(SendFlag_Abs-StartOfIOArea),IOAreaBase
SendFlag				#		0
				MAP		(SendData_Abs-StartOfIOArea),IOAreaBase
SendData				#		0
				MAP		(RcvFlag_Abs-StartOfIOArea),IOAreaBase
RcvFlag				#		0
				MAP		(RcvData_Abs-StartOfIOArea),IOAreaBase
RcvData				# 		0

Load the base address with LDR IOAreaBase,=StartOfIOArea. This allows the individual locations to be accessed with statements like LDR R0,RcvFlag and STR R4,SendData.

Copyright © 1997, 1998 ARM Limited. All rights reserved.ARM DUI 0040D
Non-Confidential