Alex
Alex

Reputation: 632

Confusion about `ldmdb` in ARM assembly

The ARM docs for the ldmdb instruction seem to contradict themselves.

  1. Under the description of addr_mode, the docs state that the DB address corresponds to "Decrement address Before each access".

  2. Further down in the Operation section, the docs state that "the memory addresses used for the accesses are at 4-byte intervals ranging from Rn to Rn-4*(n-1).

I'm confused as to how these two statements are not in direct conflict: if the address (stored in Rn) is decremented before each access, wouldn't the first (highest) accessed address be Rn - 4?

Based on behavior I've observed from running some code, it seems like the address is actually decremented after each access (consistent with the 2nd behavior).

Am I interpreting this wrong? What is the actual behavior of ldm/stm with the DB addressing mode?

Upvotes: 1

Views: 1749

Answers (1)

old_timer
old_timer

Reputation: 71586

Seems pretty clear to me:

LDMDB/LDMEA)

address = R[n] - 4*BitCount(registers);
for i = 0 to 14
  if registers<i> == '1' then
    R[i] = MemA[address,4]; address = address + 4;

if registers<15> == '1' then
  LoadWritePC(MemA[address,4]);

if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);

LDM(LDMIA/LDMFD)

address = R[n];
for i = 0 to 14
  if registers<i> == '1' then
    R[i] = MemA[address,4]; address = address + 4;

if registers<15> == '1' then
  LoadWritePC(MemA[address,4]);

if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);

so if r5 = 0x1000

ldmdb r5,{r2,r1}

the end result is:

r2 = mem[0x0FFC]
r1 = mem[0x0FF8]

from the pseudocode

address = 0x1000 - (2*4) = 0x0FF8, then for each register flag in the list
mem[address] = r1, address += 4
mem[address] = r2, address += 4

I think of DB meaning there wont be anything written to the starting address (0x1000 in this example).

if r5 = 0x1000

ldmia r5,{r1,r2}

the end result is

r1 = mem[0x1000]
r2 = mem[0x1004]

From the pseudocode

address = 0x1000
for each register flag enabled
r1 = mem[address] address += 4
r2 = mem[address] address += 4

I think of increment after meaning start using that address then increment. decrement before, start at the prior (word) address, then continue downward running the registers backward.

Or you could simply try the instruction on a processor or a simulator, and examine the memory.

If it doesn't make sense find one of the alternate/compatible ARM architectural reference manuals, and read that description. ARM re-writes their descriptions from time to time...

It is quite possible that there are errors in the documentation.


Edit

Yes, this text looks to be completely wrong:

For LDMDB, LDMEA, STMDB, and STMFD the memory addresses used for the accesses are at 4-byte intervals ranging from Rn to Rn - 4 * (n-1), where n is the number of registers in reglist. The accesses happen in order of decreasing register numbers, with the highest numbered register using the highest memory address and the lowest number register using the lowest memory address. If the writeback suffix is specified, the value of Rn - 4 * (n-1) is written back to Rn.

should be rn - 4 to rn - (4 * n) and rn - (4*n)

Note the architectural reference manuals and the technical reference manuals are pretty good. More recently they have been making flavors of other manuals in this case users guide, there are some programmers manuals. Seems like these are not good, I stopped looking at them after similar confusion by folks lead to me looking at it lead to me seeing how bad it was lead to me never bothering again.

Upvotes: 2

Related Questions