Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

(ARM).Using the ARM assembler

.pdf
Скачиваний:
39
Добавлен:
23.08.2013
Размер:
86.57 Кб
Скачать

Application 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