0
\$\begingroup\$

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

0x400F.E000

and the offset

0x608

so the address to work for would be

0x400FE608 

The general view of the assembler code is

RCGCGPIO_ADDRES EQU 0x400FE608 /*Making the mask at start
AREA....CODE
MORE CODE
LDR  R1,=RCGCGPIO_ADDRES 
ORR  R0.....

The reference and the adress is valid?

\$\endgroup\$
  • 1
    \$\begingroup\$ Not that English is my native, but shouldn't it be "address" in your question and moreover, in "RCGCGPIO_ADDRESS"? \$\endgroup\$ – Huisman Mar 5 '19 at 20:03
  • \$\begingroup\$ Im using RCGCGPIO_ADDRESS as an example, it could be GPIODATA or any like these, but the correction of the title is right. \$\endgroup\$ – riccs_0x Mar 5 '19 at 20:15
  • 1
    \$\begingroup\$ @Huisman local symbol names are arbitrary \$\endgroup\$ – Chris Stratton Mar 5 '19 at 20:15
  • \$\begingroup\$ @Huisman, great to know. \$\endgroup\$ – riccs_0x Mar 5 '19 at 20:17
1
\$\begingroup\$

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
nop
nop
nop
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
nop
nop
nop
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.

\$\endgroup\$
1
\$\begingroup\$

You have the right idea, at least for the GNU assembler. The = for the second operand of the LDR instruction indicates that this is actually a pseudoinstruction...the assembler will store the value of the second operand in program memory just after the function (i.e. in the literal pool). The actual LDR instruction will then use PC-relative addressing to access the literal value.

The TI assembler does not use the = in the literal operand. Also, the constant must be explicitly saved in program memory using the .word directive.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for?Browse other questions tagged or ask your own question.