MSP430FR5969: Addressing Mode of CG(R3) for ADDA and SUBA instructions

Part Number: MSP430FR5969

Tool/software:

Hello,

I’m currently working with an MSP430 (MSP430X) device and have encountered a question regarding how the instruction code 0x03EF (ADDA R3, R15) is interpreted. Specifically, my C code is:

Fullscreen
1
2
volatile unsigned int* p = START;
p += 1;
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

After compiling, the assembly output shows:

Fullscreen
1
ADDA #2, R15
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Yet the actual machine code in the ELF file for this instruction is 0x03EF, which some disassemblers display as ADDA R3, R15.

I understand that R2/R3 serve as constant generator registers on the MSP430, and that certain addressing mode in the As bits can cause R3 to represent the immediate value #2. However, I’m trying to reconcile this with the documentation in SLAU367 (MSP430x5xx/MSP430x6xx Family User’s Guide)—particularly Table 4-2, which lists “Indirect register mode” to get value #2 from R3, while chapters 4.5.2.6 and 4.6.1 describe 0x0*E* machine code instruction as “Register mode.” (ADDA Rsrc Rdst)

I suspect this is the expected behavior, and that I may just be overlooking the relevant documentation. It makes sense if this is an exceptional case of ADDA (and SUBA) because it is pointless to get zero from R3 in these instructions.

I’d greatly appreciate any guidance or documentation references that illuminate this particular behavior.

Thank you in advance,

Seki

 

  • I understand your confusion about the interpretation of the instruction code 0x03EF. It's indeed a bit tricky when the disassembled output doesn't match the expected assembly code.

    First of all, you're right about R2/R3 being constant generator registers on the MSP430. The special behavior you're observing is likely due to the interaction between the instruction encoding and the constant generation mechanism.

    In the case of the `ADDA` instruction, the machine code `0x03EF` is an encoding that the disassembler interprets as `ADDA R3, R15`. However, because R3 can be used as a constant generator to represent the immediate value #2 in certain addressing modes, the actual effect is equivalent to `ADDA #2, R15`.

    Regarding the documentation in SLAU367, the difference between the "Indirect register mode" in Table 4 - 2 and the "Register mode" in chapters 4.5.2.6 and 4.6.1 might seem conflicting at first glance. But in reality, these modes are defined based on different aspects of instruction encoding and execution.

    The "Indirect register mode" might refer to how the value is retrieved from the register in a more complex memory - accessing scenario, while the "Register mode" is more about the basic operation of using registers directly in an instruction.

    As for the exceptional case you mentioned about `ADDA` and `SUBA`, it makes perfect sense. Since getting zero from R3 in these instructions would be pointless, the hardware designers might have chosen to use R3 in a special way to represent immediate values like #2.

  • I would have to say that this behaviour is undocumented. The value you get from the constant generator when referring to R3 depends on the source address mode bits. But the ADDA instruction doesn't have these bits. So what happens isn't documented.

    Kind of like PUSHX.A.

  • I tried but the GCC insists on using the documented immediate mode encoding. When coerced (asm(" .word 0x3ef");) the disassembler displays this as register mode.  So the constant generator thing was a closely held secret.

    I wonder what magic happens if you refer to R2?

  • I did further experiments on my device (MSP430FR5969 LaunchPad). 

    To summarize:

    * ADDA R3, R4 increments R4 by 2
    * SUBA R3, R4 decrements R4 by 2
    * ADDA R2, R4 increments R4 by 4
    * SUBA R2, R4 decrements R4 by 4.  // note: edited typo

    * MOVA R3, R4 set R4 to 0
    * CMPA R3, #2 reset Z

    So I think this is unique behaviour for ADDA and SUBA. The As bits seem to be "10" for accessing R3 on this instruction.

    Here is the complete code and the output. (compiled with msp430-elf-gc)

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <stdio.h>
    #include <msp430.h>
    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
    register unsigned int *p;
    // R4 = 8
    // ADDA R3, R4
    asm(
    "mova #8, r4\n\t"
    // ".word 0x03e4\n\t"
    "adda r3, r4\n\t"
    "mova r4, %0"
    : "=r"(p));
    printf("p = 8; adda r3, p; p = %p\n", p);
    // R4 = 8
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Fullscreen
    1
    2
    3
    4
    5
    6
    p = 8; adda r3, p; p = 0xa
    p = 8; suba r3, p; p = 0x6
    p = 8; adda r2, p; p = 0xc
    p = 8; suba r2, p; p = 0x4
    mova r3, p; p = 0
    cmpa r3, #2; Z = 0
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    004726: 140A PUSHM.A #1,R10
    004728: 00B1 0008 SUBA #0x00008,SP
    6 WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
    00472c: 40B2 5A80 015C MOV.W #0x5a80,&Watchdog_Timer_WDTCTL
    12 asm(
    004732: 0084 0008 MOVA #0x00008,R4
    004736: 03E4 INCDA R4
    004738: 04CC MOVA R4,R12
    19 printf("p = 8; adda r3, p; p = %p\n", p);
    00473a: 0C71 0004 MOVA R12,0x0004(SP)
    00473e: 1800 40F1 4400 0000 MOVX.A #0x04400,0x00000(SP)
    004746: 008A 47CA MOVA #0x047ca,R10
    00474a: 134A CALLA R10
    23 asm(
    00474c: 0084 0008 MOVA #0x00008,R4
    004750: 03F4 DECDA R4
    004752: 04CC MOVA R4,R12
    30 printf("p = 8; suba r3, p; p = %p\n", p);
    004754: 0C71 0004 MOVA R12,0x0004(SP)
    004758: 1800 40F1 441B 0000 MOVX.A #0x0441b,0x00000(SP)
    004760: 134A CALLA R10
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Thank you for your comments. That's a good point to see so I experimented with R2 as well. I posted the results to the thread.

    ADDA R2, R4 incremented R4 by four. So the situation is the same as R3.

    > asm(" .word 0x3ef");

    What a trick. I never think of that idea.

  • Thank you for your comment. 

    the hardware designers might have chosen to use R3 in a special way to represent immediate values like #2

    Can I get a statement or document from TI for this behavior?

    Still from what I decode the SLAU367 document, it is possible that it increments R15 by any number of the Table 4-2.

  • Please refer to these e2e for addtional reference:

    That added nothing to this discussion. Which is about CPUX address instructions which have no As address mode bits for the constant generator to work with. The behaviour noted is undocumented in any way by TI.

  • Agreed. The designer's intention to enhance the machine code density is understandable. I want to see some clarifications from the official.

  • Sorry, all the MSP430 related designers are left TI.... So you can't get any formal declaration. All we can refer is the released docs. 

  • all the MSP430 related designers are left TI....

    Oh..., sad news.

  • Yes. Sorry, for MSP430, we just keep it in mantianness. Currently, we can only give some limited support from application level. 

**Attention** This is a public forum