Please note: We are aware of an issue affecting replies on the Arm Community forums, which may not be loading as expected.

We apologize for any inconvenience and appreciate your patience while we investigate and work to resolve the issue.

Thank you for your understanding.


This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Inconsistency between the armv7-m document and physical board (B instruction, Thumb mode)

Hello,

    I found the arm assembler always does an extra `plus 4` when calculating the label of instruction B. (support-board: nrf52840dk, architecture; Cortex-M ), but the armv7-M document (ARM DDI 0403E.e) doesn't mention it ?  could you please give me some suggestions?

    Considering the following example:

   1) `0x01, 0xdb` (i.e. 0xdb01) corresponds to the encoding T1 of B with cond = LT and imm8=0x01

1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
--------------------------------
|1 1 0 1| cond | imm8 |
--------------------------------

   2) computing label

according to the description "
if cond == '1110' then SEE UDF;
if cond == '1111' then SEE SVC;
imm32 = SignExtend(imm8:'0', 32);
if InITBlock() then UNPREDICTABLE;

"

   we know imm32 = 0x00000002

according to the description "

Operation
if ConditionPassed() then
EncodingSpecificOperations();
BranchWritePC(PC + imm32);

"

and "

////BranchWritePC()
==========

BranchWritePC(bits(32) address)

BranchTo(address<31:1>:’0’);

"

and "

////BranchTo()
==========
BranchTo(bits(32) address)
_R[RName_PC] = address;
return;

"

   we know the label should be "pc+2", but in practise, the label is "pc+6", I tested it on my board:

```C

//

#include <stdio.h>
#include <string.h>
#include <stdint.h>

__attribute__((aligned(4))) unsigned char code[] = {
0x01, 0xdb,
0x40, 0xf2, 0x0b, 0x0b,
0xcc, 0xf8, 0x06, 0xb0,
0x32, 0xdb,
0x25, 0xfa, 0x04, 0xf5,
0x40, 0xf2, 0x2a, 0x00, 0x70, 0x47, 0x40, 0xf2, 0x3a, 0x00, 0x70, 0x47
};

/*
0x00, 0xdb,
0x40, 0xf2, 0x0b, 0x0b,
0xcc, 0xf8, 0x06, 0xb0,
0x32, 0xdb,
0x25, 0xfa, 0x04, 0xf5,

===> b always +4??? (0+4)

0x20000200 <code> blt.n 0x20000204 <code+4>
0x20000202 <code+2> movw r11, #11
0x20000206 <code+6> str.w r11, [r12, #6]
0x2000020a <code+10> blt.n 0x20000272 <impure_data+78>
0x2000020c <code+12> lsr.w r5, r5, r4

*/

/*
0x01, 0xdb
...
===> b always +4??? (2+4)

0x20000200 <code> blt.n 0x20000206 <code+6>

*/

int main(void) {
int i;

__asm volatile ("orr %[input_0], #0x1\n\t"
"blx %[input_0]\n\t"
"mov r1, r0\n\t"
: [result] "=r" (i)
: [input_0] "r" (code)
:
);
printf("get this done. returned: %d\n", i);

return 0;
}


```

  • I just found this description "Calculate the PC or Align(PC,4) value of the instruction. The PC value of an instruction is its address plus 4
    for a Thumb instruction. The Align(PC,4) value of an instruction is its PC value ANDed with 0xFFFFFFFC to
    force it to be word-aligned. (A4-104)", so maybe because Thumb adopts a different PC calculation?