1

When I look at the official Arm specifications,

! 
Causes the instruction to write a modified value back to <Rn> . If ! is omitted, the instruction does not change <Rn> in this way.

This is how the function is explained, yet the ASL Code is as follows,

if ConditionPassed() then
  n = UInt(Rn); registers = '00000000':register_list;
  if BitCount(registers) < 1 then UNPREDICTABLE;
  wback = (registers<n> == '0');
  address = R[n];
  for i = 0 to 7
    if registers<i> == '1' then
      R[i] = MemA[address,4];
      address = address + 4;
if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);

So the only logical thing would be to use wback for the purpose, yet it doesn't seem to add up when I examine the general structure.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    I suppose there is a bit in the instruction encoding that keeps track of that. Have you checked the appropriate manual for the instruction encoding? – fuz Feb 24 '20 at 08:25
  • Did you try assembling the instruction with/without the `!` to see what changes in the raw machine code? It sounds like you're expecting the machine code to be similar to the pseudocode somehow, which doesn't make any sense to me. Likely there's a `wback` bit somewhere in the encoding, or it's implied by the state of multiple other things. Ah, yes `wback = (registers == '0')` seems to indicate that it's implied by the fact that the base register isn't one of the ones being loaded. – Peter Cordes Feb 24 '20 at 08:31
  • @PeterCordes This seems weird as the final conditional statement checks for `wback && registers == '0'` again. – fuz Feb 24 '20 at 08:53
  • @fuz: yeah I noticed that; super weird and that's part of why I didn't post an answer! Possibly Thumb mode only has implicit `wback` but ARM has a bit for it? Presumably someone with ARM manuals at their fingertips can answer it definitively. – Peter Cordes Feb 24 '20 at 08:56
  • That's the actual problem, spec doesn't explain how the "!" is ever used in the instruction decoding. – Alperen Keleş Feb 24 '20 at 09:02
  • 1
    @AlperenKeleş The ARM7-TDMI data sheet I referenced explains that `!` just decides whether the W bit is on (`!` present) or off (`!` absent). – fuz Feb 24 '20 at 11:22
  • 1
    I have deleted my answer as it is irrelevant for your question: Armv6-M exclusively uses thumb instructions which have a different encoding. In the thumb encoding, there is no bit to decide whether write back happens. Instead, write back always happens. Likely, Thumb2 provides additional options, but I need to research this first. – fuz Feb 24 '20 at 12:55

1 Answers1

3

It is documented in the arm documentation.

Initially it looks strange if you are used to the w bit and so that might lead you to check the armv7-m, armv7-ar, so of course go back to the original arm arm

! Causes base register writeback, and is not optional.

You can also try it and see what an assembler thinks of it

.cpu cortex-m0
.thumb
ldm r1,{r2}
ldm r1!,{r2}

arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:4: Warning: this instruction will write back the base register

line 4 being the one without the !

Disassembly of section .text:

00000000 <.text>:
   0:   c904        ldmia   r1!, {r2}
   2:   c904        ldmia   r1!, {r2}

Upon further inspection it is not a bug in the documentation though

LDM <Rn>,<registers> <Rn> included in <registers>

so test that

.cpu cortex-m0
.thumb
ldm r1,{r1}
ldm r1!,{r1}
so.s: Assembler messages:
so.s:5: Warning: this instruction will not write back the base register

line 5 being the one with the !

Disassembly of section .text:

00000000 <.text>:
   0:   c902        ldmia   r1, {r1}
   2:   c902        ldmia   r1, {r1}

Which is also stated in the psuedocode from the arm documentation:

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

so this is not encoded as a bit as in the larger instructions, this is implied based on the presence of rn in the register list.

Now go back to the original arm arm

Operand restrictions
If the base register <Rn> is specified in <registers>, the final value of <Rn> is the loaded value (not the written-back value).

so even in the original it is not written back. and if you test it gnu assembler knows this as well with similar messages

.cpu arm7tdmi
.thumb
ldm r1,{r1}
ldm r1!,{r1}


arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:5: Warning: this instruction will not write back the base register

Disassembly of section .text:

00000000 <.text>:
   0:   c902        ldmia   r1, {r1}
   2:   c902        ldmia   r1, {r1}

This is perhaps an intentional thing in the armv4 days as they were trying to operate as an IP company and a number of the UNPREDICTABLE RESULTS, and other such things were actually predictable and were how they tested to see if you had stolen a core. It would not surprise me if the way this was written in the original arm arm docs was also something to catch folks making clones.

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • Well this is certainly an interesting design choice. Do you know if this limitation has been lifted with Thumb2? – fuz Feb 24 '20 at 14:44
  • @fuz, come on, it takes only a second to look at the armv7-m documentation to see the T2 encoding. yes there is a w bit there. – old_timer Feb 24 '20 at 14:45
  • 1
    added in the armv7-m and armv7-ar architectures. is not in armv6-m – old_timer Feb 24 '20 at 14:46