ARM Assembler – How to Correctly Use an Address


Im trying to use several registers on the M4/tm4c1294 in a way to avoid write every time the same register number.

The question is how to make the number of the register and if the reference is correct.

Let say Im working with the RCGCGPIO, so from the data sheet, the RCGCGPIO has the base address


and the offset


so the address to work for would be


The general view of the assembler code is

RCGCGPIO_ADDRES EQU 0x400FE608 /*Making the mask at start
ORR  R0.....

The reference and the adress is valid?

Best Answer

First off assembly language is defined by the assembler, the program you use to turn the assembly language into machine code. So no reason to assume that gnu assembler vs keil vs arm vs others are the same.

so some gnu assembler code that demonstrates what Elliot was saying...and more.

ldr r1,=0x12345678
ldr r2,=hello
ldr r3,hello
ldr r4,=0x11
b .
hello: .word 0xAABBCCDD

You can use EQU or .EQU or equivalents to basically do a search and replace in the code. The syntax varies by assembler. AREA and SECTION and such are often not required but if you like/need them go for it.

The first line is like yours, this is pseudo code. The =something means the address of something just like &something in C. The arm instruction set is like mips and some others where there isnt enough room in the encoding for a full sized constant, so it is generally best but there are exceptions to load an immediate you cant fit into the instruction by putting it nearby and doing a pc-relative load. Normally you would use this to load an address of something, but you can, if the assembler supports this, use this to save on typing to load constants of any bit pattern.

Disassembly of section .text:

00010000 <hello-0x20>:
   10000:   e59f101c    ldr r1, [pc, #28]   ; 10024 <hello+0x4>
   10004:   e59f201c    ldr r2, [pc, #28]   ; 10028 <hello+0x8>
   10008:   e59f3010    ldr r3, [pc, #16]   ; 10020 <hello>
   1000c:   e3a04011    mov r4, #17
   10010:   e1a00000    nop         ; (mov r0, r0)
   10014:   e1a00000    nop         ; (mov r0, r0)
   10018:   e1a00000    nop         ; (mov r0, r0)
   1001c:   eafffffe    b   1001c <hello-0x4>

00010020 <hello>:
   10020:   aabbccdd
   10024:   12345678
   10028:   00010020

The assembler has done this for the first instruction it has turned that into a pc-relative load from address 0x10024 which will put that value into r1, as desired.

The second instruction is more like what this pseudo code was intended for, since we dont know what the address of a label will be when we write the code this is a way to have the assembler both generate the address and place it nearby and generate a pc-relative load. Which it has done the label hello is at address 0x10020, and the instruction generated loaded the value from address 0x10028 into r2.

Without the equals means I want to load the thing at the label hello.

And the fourth one is there to show that at least gnu assembler will create a mov immediate if it can.

Now that we know what the tool is doing we could have just done that ourself.

ldr r1,l00
ldr r2,l01
b .
l01: .word hello
l00: .word 0x12345678
hello: .word 0xAABBCCDD

Disassembly of section .text:

00010000 <l01-0x18>:
   10000:   e59f1014    ldr r1, [pc, #20]   ; 1001c <l00>
   10004:   e59f200c    ldr r2, [pc, #12]   ; 10018 <l01>
   10008:   e1a00000    nop         ; (mov r0, r0)
   1000c:   e1a00000    nop         ; (mov r0, r0)
   10010:   e1a00000    nop         ; (mov r0, r0)
   10014:   eafffffe    b   10014 <l01-0x4>

00010018 <l01>:
   10018:   00010020

0001001c <l00>:
   1001c:   12345678

00010020 <hello>:
   10020:   aabbccdd

this solution does the exact same thing with respect to your constant, but it takes more up front code. But you control where you want this word placed rather than the assembler trying to find a place.