(ARM).Using the ARM assembler
.pdfApplication Note 50
Using the ARM Assembler
Document number: ARM DAI 0050A
Issued: January 1998
Copyright Advanced RISC Machines Ltd (ARM) 1998
ENGLAND |
|
|
GERMANY |
|
||
Advanced RISC Machines Limited |
Advanced RISC Machines Limited |
|||||
Fulbourn Road |
|
|
Otto-Hahn Str. 13b |
|
||
Cherry Hinton |
|
|
85521 Ottobrunn-Riemerling |
|||
Cambridge CB1 4JN |
|
Munich |
|
|
||
UK |
|
|
|
Germany |
|
|
Telephone: |
+44 |
1223 400400 |
Telephone: |
+49 89 608 75545 |
||
Facsimile: |
+44 |
1223 400410 |
Facsimile: |
+49 89 608 75599 |
||
Email: |
info@arm.com |
Email: |
info@arm.com |
|||
JAPAN |
|
|
|
USA |
|
|
Advanced RISC Machines K.K. |
ARM USA Incorporated |
|||||
KSP West Bldg, 3F 300D, 3-2-1 Sakado |
Suite 5 |
|
|
|||
Takatsu-ku, Kawasaki-shi |
985 University Avenue |
|||||
Kanagawa |
|
|
Los Gatos |
|
||
213 Japan |
|
|
CA 95030 USA |
|
||
Telephone: |
+81 |
44 850 1301 |
Telephone: |
+1 408 399 5199 |
||
Facsimile: |
+81 |
44 850 1308 |
Facsimile: |
+1 408 399 8854 |
||
Email: |
info@arm.com |
Email: |
info@arm.com |
World Wide Web address: http://www.arm.com
Open Access
Proprietary Notice
ARM and the ARM Powered logo are trademarks of Advanced RISC Machines Ltd.
Neither the whole nor any part of the information contained in, or the product described in, this document may be adapted or reproduced in any material form except with the prior written permission of the copyright holder.
The product described in this document is subject to continuous developments and improvements. All particulars of the product and its use contained in this document are given by ARM in good faith. However, all warranties implied or expressed, including but not limited to implied warranties or merchantability, or fitness for purpose, are excluded.
This document is intended only to assist the reader in the use of the product. ARM Ltd shall not be liable for any loss or damage arising from the use of any information in this document, or any error or omission in such information, or any incorrect use of the product.
Key
Document Number
This document has a number which identifies it uniquely. The number is displayed on the front page and at the foot of each subsequent page.
ARM |
XXX |
0000 |
X |
- 00 |
(On review drafts only) Two-digit draft number
Release code in the range A-Z
Unique four-digit number
Document type
Document Status
The document’s status is displayed in a banner at the bottom of each page. This describes the document’s confidentiality and its information status.
Confidentiality status is one of:
ARM Confidential |
Distributable to ARM staff and NDA signatories only |
Named Partner Confidential |
Distributable to the above and to the staff of named partner companies only |
Partner Confidential |
Distributable within ARM and to staff of all partner companies |
Open Access |
No restriction on distribution |
Information status is one of: |
|
Advance |
Information on a potential product |
Preliminary |
Current information on a product under development |
Final |
Complete information on a developed product |
Change Log
Issue |
Date |
By |
Change |
A |
January 1998 |
SKW |
Released |
|
Application Note 50 |
ii |
ARM DAI 0050A |
Open Access
Table of Contents
Table of Contents
1 |
Introduction |
2 |
|
2 |
Describing Data Structures Using ^ and # Directives |
3 |
|
|
2.1 |
When to use non-register-based ^ and # directives |
3 |
|
2.2 |
When not to use non-register-based ^ and # directives |
5 |
|
2.3 |
When to use register-based ^ and # directives |
6 |
|
2.4 |
Warnings in the use of ^ and # directives |
12 |
3 Using Macros |
14 |
||
4 |
Using the Barrel Shifter |
17 |
|
|
4.1 |
Assembler mnemonics |
17 |
|
4.2 |
Register operands |
18 |
5 |
Access to C Global Variables from Assembly Code |
20 |
Application Note 50
ARM DAI 0050A |
1 |
Open Access
Introduction
1 Introduction
This Application Note gives additional information on how to use the ARM and Thumb
Assemblers to best effect. It covers:
∙how to describe data structures in memory using the ^ and # directives
∙how to specify macros
∙how the barrel shifter works on register operands
∙how to access C global variables from assembly code.
|
Application Note 50 |
2 |
ARM DAI 0050A |
Open Access
Describing Data Structures Using ^ and # Directives
2 Describing Data Structures Using ^ and # Directives
The C language allows for the easy use of data structures by providing the struct construct. In a similar way the Assembler provides the ^ and # directives to describe the layout of store in a way that is easily maintainable. The ^ directive initializes the storage map location counter to a base address. This can be either to a specified numeric expression (fixed at assembly compile time), or to a register-based expression; that is, a notional sum of a register and a numeric expression (which is evaluated during run time). The # directive defines its label to be equal to the current value of the storage map location counter, then increments the storage map location counter by a specified number. The label inherits the type of the storage map location counter; that is, it is a numeric expression or a registerbased expression, depending on what the last ^ directive specified.
2.1 When to use non-register-based ^ and # directives
These should be used when your program has a known area of memory that it can use to store its data and a number of data items to go into it, but it is not important precisely where any particular data item goes. For example, if you have memory from 0x1000 to 0x2000 available, and you need to store two integers, a string of length MaxStrLen, an array of ArrayLen double-precision floating point numbers and a bitmask of length 32 bits in that area, you could write:
StartOfMyData |
EQU |
0x1000 |
|
|
|
^ |
StartOfMyData |
Integer |
# |
4 |
|
Integer2 |
# |
4 |
|
String |
# |
MaxStrLen |
|
Array |
# |
ArrayLen*8 |
|
BitMask |
# |
4 |
|
This use of ^ and # does not make anything possible that is not possible with EQU directives, but it does make the code more readable and maintainable. For example, the equivalent of the above code using EQU directives is:
StartOfMyData EQU 0x1000
Integer |
EQU |
StartOfMyData |
Integer2 |
EQU |
Integer+4 |
String |
EQU |
Integer2+4 |
Array |
EQU |
String+MaxStrLen |
BitMask |
EQU |
Array+ArrayLen*8 |
This is confusing to read; in particular, the definition of each data item contains the length of the previous item, not its own length, and the length of the last item is never mentioned.
Similarly, adding another data item to the middle of the list or re-ordering the list is easier using ^ and #: for example, adding another integer to the list just involves inserting Integer3 # 4 in the first piece of code above, but something like Integer3 EQU Integer2+4 and a change of String EQU Integer2+4 to String EQU Integer3+4 in the second.
One useful technique when doing this is to use # with an operand of 0 to find out where you are without allocating any storage. Two examples using this technique are:
∙Finding out where the end of the allocated data is
∙Forcing alignment to be correct
Application Note 50
ARM DAI 0050A |
3 |
Open Access
Describing Data Structures Using ^ and # Directives
Finding out where the end of the allocated data is
For example, if in the above code you want to check that MaxStrLen and ArrayLen are not large enough to exceed the available storage:
StartOfMyData |
EQU |
0x1000 |
EndOfMyData |
EQU |
0x2000 |
|
^ |
StartOfMyData |
Integer |
# |
4 |
Integer2 |
# |
4 |
String |
# |
MaxStrLen |
Array |
# |
ArrayLen*8 |
BitMask |
# |
4 |
EndOfUsedData |
# |
0 |
ASSERT EndOfUsedData <= EndOfMyData
Forcing alignment to be correct
For example, if you include some character variables in the above code, the following code would almost certainly fail because a lot of words would end up being misaligned:
StartOfMyData EQU 0x1000
EndOfMyData EQU 0x2000
|
^ |
StartOfMyData |
Char |
# |
1 |
Char2 |
# |
1 |
Char3 |
# |
1 |
Integer |
# |
4 |
Integer2 |
# |
4 |
String |
# |
MaxStrLen |
Array |
# |
ArrayLen*8 |
BitMask |
# |
4 |
EndOfUsedData |
# |
0 |
ASSERT EndOfUsedData <= EndOfMyData
This cannot be dealt with by use of the ALIGN directive, which aligns the current location within the code that is being generated, not the current storage map location.
It could be dealt with by inserting an extra Dummy # 1 after the Char3 # 1 line, but this produces a maintenance problem when the number of character variables is subsequently changed: you must recalculate the right amount of padding each time.
What you can do instead is:
StartOfMyData |
EQU |
0x1000 |
EndOfMyData |
EQU |
0x2000 |
|
^ |
StartOfMyData |
Char |
# |
1 |
Char2 |
# |
1 |
Char3 |
# |
1 |
EndOfChars |
# |
0 |
Padding |
# |
(-EndOfChars):AND:3 |
|
Application Note 50 |
4 |
ARM DAI 0050A |
Open Access
Describing Data Structures Using ^ and # Directives
Integer |
# |
4 |
Integer2 |
# |
4 |
String |
# |
MaxStrLen |
Array |
# |
ArrayLen*8 |
BitMask |
# |
4 |
EndOfUsedData |
# |
0 |
ASSERT EndOfUsedData <= EndOfMyData
This automatically adjusts the amount of padding used whenever character variables are added or removed.
Note The (-EndOfChars):AND:3 expression is a convenient way of producing:
0 if EndOfChars is 0 mod 4;
3 if EndOfChars is 1 mod 4;
2 if EndOfChars is 2 mod 4;
1 if EndOfChars is 3 mod 4.
2.2 When not to use non-register-based ^ and # directives
Do not use these when it matters precisely which memory location is used by each data item. The standard example of this is memory-mapped I/O locations. These are better defined using EQU directives; for example:
SendFlag EQU 0x1000000
SendData EQU 0x1000004
RcvFlag EQU 0x1000008
RcvData EQU 0x100000C
This guarantees that they do not accidentally get changed when other changes are made in the code.
If the above code is written using ^ and #, bugs are more likely to be created when maintaining the code:
|
^ |
0x1000000 |
SendFlag |
# |
4 |
SendData |
# |
4 |
RcvFlag |
# |
4 |
RcvData |
# |
4 |
For example, if the interface is later extended with a fault status register at 0x1000001 and 0x1000009, the first piece of code just needs SendStatus EQU 0x1000001 and RcvStatus EQU 0x1000009 added to it, while the second needs more extensive and non-obvious changes to get:
|
^ |
0x1000000 |
SendFlag |
# |
1 |
SendStatus |
# |
3 |
SendData |
# |
4 |
RcvFlag |
# |
1 |
RcvStatus |
# |
3 |
RcvData |
# |
4 |
Application Note 50
ARM DAI 0050A |
5 |
Open Access
Describing Data Structures Using ^ and # Directives
2.3 When to use register-based ^ and # directives
Unlike the non-register-based versions, these give a way to define register-based symbols, which is not possible with the other directives.
Register-based symbols can be very useful, but need to be treated with care. As a general rule, they should be used 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 part offset,
the Assembler will automatically translate, for example, LDR Rn,Location into
LDR Rn,[Rb,#offset].
∙In an ADR or ADRL instruction, ADR Rn,Location is similarly 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. Only do this if the two register-based symbols are based on the same register; otherwise, you get a combination of two registers and a numeric value, which will probably result in an assembler error message.
∙As the operand of a :BASE: or :INDEX: operator. With a couple of exceptions for :INDEX: (described below), these operators are mainly of use in macros.
Other uses will usually result in assembler error messages. For example, if you write LDR Rn,=Location, you are asking the Assembler to load Rn from a memory location which 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 which adds both the base register of the expression and its offset to Rn. Again, the Assembler cannot do this: you need two ADD instructions to perform these two additions.
There are two main uses for register-based ^ and # directives:
∙Setting up something similar to a C structure
∙Making faster access possible to the sort of memory area described by non- register-based use of ^ and #.
Setting up a C-type structure
There are two parts to using structures in C: defining the fields which the structure contains, and generating and using the structures in storage. This is clearest when typedefs are used. For example, consider the code:
typedef struct Point
{
float x,y,z; } Point;
Point origin,oldloc,newloc;
In this, the typedef statement defines that a Point structure contains three float fields named x, y and z, but does not allocate any storage. The second statement allocates three such structures in storage, named origin, oldloc and newloc.
Note C also allows the two parts to be done in the same statement, as in:
|
Application Note 50 |
6 |
ARM DAI 0050A |
Open Access
Describing Data Structures Using ^ and # Directives
struct Point
{
int x,y,z;
} origin,oldloc,newloc;
The assembler syntax does not allow anything similar.
The equivalent assembler code to the typedef statement is something like:
PointBase |
RN |
r11 |
|
^ |
0,PointBase |
Point_x |
# |
4 |
Point_y |
# |
4 |
Point_z |
# |
4 |
You then allocate the actual structures in whatever way is suitable¾typically, in your own data area for the equivalent of a C static variable, on the stack for the equivalent of a C auto variable, or by IMPORTing a symbol for the equivalent of a C extern variable.
To work with a data structure, make certain that its address is in the base register of the symbol, and load or store to it using the symbols defined above. For example, the equivalent of the C code:
origin.x = 0; origin.y = 0; origin.z = 0;
is:
ADR |
PointBase,origin |
MOV |
r0,#0 |
STR |
r0,Point_x |
STR |
r0,Point_y |
STR |
r0,Point_z |
(The first statement could also be
LDR PointBase,=origin
, ADD PointBase,sp,#n
or other addressing code, depending where the structure is allocated.)
As with the non-register-based use of ^ and #, a zero operand to # is often useful. For example, to make a definition of the length of the Point data structure which automatically adjusts to any changes to the data structure, use code similar to:
PointBase |
RN |
r11 |
|
^ |
0,PointBase |
PointStart |
# |
0 |
Point_x |
# |
4 |
Point_y |
# |
4 |
Point_z |
# |
4 |
PointEnd |
# |
0 |
PointLen |
EQU |
PointEnd-PointStart |
(Note that the last statement is an example of subtracting a register-based symbol from another one based on the same register, to get an ordinary numeric expression.)
Application Note 50
ARM DAI 0050A |
7 |
Open Access
Describing Data Structures Using ^ and # Directives
For example, this would allow you to write the equivalent of the C code:
Point |
pointarray[10]; |
|
int |
|
i; |
for |
(i=0; i<10; i++) |
|
|
{ |
|
pointarray[i].x = i; pointarray[i].y = i; pointarray[i].z = i;
}
as:
ADR |
PointBase,pointarray |
MOV |
r0,#0 |
LoopStart |
|
STR |
r0,Point_x |
STR |
r0,Point_y |
STR |
r0,Point_z |
ADD |
PointBase,PointBase,#PointLen |
ADD |
r0,r0,#1 |
CMP |
r0,#10 |
BLT |
LoopStart |
Similarly, to impose alignment restrictions in a structure, a zero operand to # is again useful, this time combined with the use of :INDEX: to extract the numeric part of the register-based expression. For example, the equivalent of the C structure definition:
typedef struct Misc
{
char a,b,c; int i;
int data[20]; } Misc;
is similar to:
MiscBase |
RN |
r10 |
|
^ |
0,MiscBase |
MiscStart |
# |
0 |
Misc_a |
# |
1 |
Misc_b |
# |
1 |
Misc_c |
# |
1 |
MiscEndOfChars |
# |
0 |
MiscPadding |
# |
(-:INDEX:MiscEndOfChars) :AND: 3 |
Misc_I |
# |
4 |
Misc_data |
# |
4*20 |
MiscEnd |
# |
0 |
MiscLen |
EQU |
MiscEnd-MiscStart |
This ensures that Misc_i is word-aligned within the structure, and so is word-aligned in memory as long as MiscBase contains a word-aligned address.
|
Application Note 50 |
8 |
ARM DAI 0050A |
Open Access