0

I am writing an RTOS and there is something I don't understand. My context switch, written in assembly, has the line:

STMDB r0!,{r4-r11}

Where r0 is being used to store the current process stack pointer (PSP). Since this is in a handler and running in handler mode, the MSP is being used for the function, so I can't just push.

For the sake of argument let us say that r0 stores the address 0x64 (I am aware this is not reasonable, but it is not relevant to the discussion below).

Do I understand this correctly: the first register to be stored, r4, will be placed at 0x60, since the decrement before part means that r0 is first decremented by one 32-bit word, then the storage takes place?

Michael Stachowsky
  • 717
  • 1
  • 5
  • 21
  • what part of the arm documentation did you not understand? – old_timer Jun 14 '22 at 17:03
  • 1
    Your example of the store at 0x60 is correct. I think you just needed confirmation that this is correct. There was a book by David Seal that was popular for the original ARM CPUs and it had many assembler examples. He was one of the original designers of the CPU. Well technical documentation is great, the second section has examples of sequences to achieve various common function and discuss stack types afair. – artless noise Jun 15 '22 at 13:45

2 Answers2

1

pretty clear from the arm docs.

with respect to DB, decrement before

start_address = Rn - (Number_Of_Set_Bits_In(register_list) * 4)
end_address = Rn - 4
if ConditionPassed(cond) and W == 1 then
  Rn = Rn - (Number_Of_Set_Bits_In(register_list) * 4)

STM in general

if ConditionPassed(cond) then
address = start_address
for i = 0 to 15
  if register_list[i] == 1
  Memory[address,4] = Ri
  address = address + 4
assert end_address == address - 4

what part do you not understand?

old_timer
  • 69,149
  • 8
  • 89
  • 168
1

'''TL-DR;''' 'DB' stands for 'decrement before'.

[stm|ldm][modifier] Rn!, {reg_list}

Rn! is the 'address register'

There are two mutually exclusive options for auto-index memory via the modifier.

Letter Note
I Increment the address register (ie, 3 register -> 12 bytes increment)
D Decrement the address register
B Before store/load operation
A After store/load operation

You can have variants of a full/empty decrementing/incrementing stack. Ie, stack grows down/up and stack is empty/full. Decrement before would mean the stack is at a 'full' element and you grow down.

Of course, the same operations can be used for buffers. If you have a ring buffer, it can typically point to an empty or full element. This is a design choice. You would use the 'before' or 'after' versions and for ring buffers, we usually increment memory.

LDM and STM can come in all these four flavors.

  • LDMIA - increment after (empty increasing).
  • LDMIB - increment before (full increasing).
  • LDMDA - decrement after (empty decreasing).
  • LDMDB - decrement before (full decreasing).

If you don't modify the address register, then these modifiers don't make sense. Ie, you need ldmxx Rn!, {reglist} or stmxx Rn!, {reglist}. The single word versions have a different syntax.

See: ARM increment register, University of Regina lecture


Probably a good keyword is 'fully descending stack' for searches. Some assemblers will offer alternatives like,

  • stmfd - store multiple fully descending; alias stmdb.
  • stmed - store multiple empty descending; alias stmda.

I would just stick to the 'i','d', 'b' and 'a' permutations.


What exactly is decremented and when?

It is always the leading address register that is modified. It is either before or after the register list is transferred as to when this occurs. Hopefully the above describes data structures where this is useful.

It is always a single word that is empty/full and not the whole register list. Register list is ordered numerically for access. Ie, the CPU always writes/reads R0 first and R15 (if possible) last. You can just include/exclude a 'reg list' bit in the opcode.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • A great and thorough answer. Thank you! – Michael Stachowsky Jun 14 '22 at 22:50
  • There is also an important version for context switch that allows a change to user mode; but it is relevant to the ARM Cortex-A (and older architectures) and not the Cortex-M of the OP. [ldm user mode registers](https://stackoverflow.com/questions/51341696/using-arm-ldm-instruction-to-transfer-data-into-user-mode-registers) shows the trailing '^' caret for this form. – artless noise Jun 15 '22 at 13:48