This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Absence of LDR pseudo instruction

Other Parts Discussed in Thread: TMS570LS3137, HALCOGEN

I'm using CCS v5.4.0.00091 and TMS570LS3137.

What I'm trying to achieve is to load a 32-bit address into a register using a label (e.g. imported using .ref command).

On the GCC compiler, I can do something like this:

movw r0, #:lower16:ta_irqEntry
movt r0, #:upper16:ta_irqEntry

On the other hand, ARM documentation mentions LDR pseudo instruction from their own toolchain (which seems to do the same thing behind the scenes:
ldr r0, =ta_irqEntry
 
CCS doesn't seem to support neither.
My question is this: how can I achieve the same result in CCS? I'm not interested in manually splitting the value into upper and lower half, I would like to use the label directly.

  • Sorry for the broken highlight - this doesn't seem to work. It should be:
    movw r0, #:lower16:ta_irqEntry
    movt r0, #:upper16:ta_irqEntry

    By the way, why can I edit my own message?
  • You should be able to edit it via the 'More' button.
  • Hello Lukasz,

    Are you using the TI Compiler with GCC extensions or the GCC compiler within CCS? If you are using the GCC compiler within CCS, it doesn't natively support the Hercules product line since there is no runtime library for it.

    LDR is an ARM assembly instruction and is supported by the Code Generation Tools/Compiler in CCS. If you have a look at the asm files generated by the Halcogen tool, you will see some examples of the use of this instruction and the proper syntax.

    For example,
    ldr r0, ESMSR1_REG ; load the ESMSR1 status register address

    where ESMSR1_REG is defined as:
    ESMSR1_REG .word 0xFFFFF518

    Also, here are some links to questions about working with the GCC compiler with the Hercules products. It is possible but there are some steps that need to be taken as outlined in these threads.

    e2e.ti.com/.../392386

    e2e.ti.com/.../1356263

    e2e.ti.com/.../413871

    e2e.ti.com/.../344105
  • Hello Chuck.

    I'm using CCS compiler with GCC extensions enabled.

    I do know that LDR instruction is working alright in CCS (I'm using it myself). What I'm missing is LDR pseudoinstruction which is replaced by assembler by one or more "real" instructions that do the same thing, so e.g.:

    LDR r0, =0xAAAABBBB

    is expanded to MOV or LDR with generated variable (depending on the value right to =),

    see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489i/Babbfdih.html

    Your example might be working alright only if the address of ESMSR1_REG is close enough (I believe it is something like +- 4096 bytes) the usage of LDR. My problem is that I need to load addresses from entire 32-bit space (and then assembling of the LDR will fail).

    Alternatively, the mentioned macros to get symbol address's upper and lower half would be sufficient for me.

    Regards.

  • Hello Lukasz,

    The link you provided is to an ARM compiler page. From what you have explained you are using the TI ARM compiler. Correct?

    I'm not certain the TI ARM compiler supports the pseudo instruction.

    It seems this discussion is primarily a compiler topic and I believe the best support opportunity will be with our code gen team. As such, I am going to move this thread to their forum. Sorry for any inconvenience. If you do not get the support you need there, please feel free to send me a private message through the forum and I will help try and get you some help from their support team.
  • Lukasz Matecki said:
    What I'm missing is LDR pseudoinstruction which is replaced by assembler by one or more "real" instructions that do the same thing

    The TI ARM assembler does not support this feature.

    Thanks and regards,

    -George

  • George,

    Is there any other way (a macro or anything) to do that?

    Regards.

  • Unfortunately, no.  -George

  • You could write your own macro:

    PSEUDO  .macro dst, src
            MOVW dst, #(src&0xffff)
            MOVT dst, #((src>>16)&0xffff)
            .endm
    
            PSEUDO r0, 0x12345678
    
  • Thanks for this hint, but I think this will only work for immediate values. I need something that will work with relocation symbols (I think there have to be compiler support for that). My example (using your macro):

       .global coverageStartAddress

    ...

       PSEUDO r0, coverageStartAddress

    This gives the following errors:

    "../../aaa.asm", WARNING! at line 368: [W1500]

    warning: relocation template 275 not found; returning OFR_INVALID

    MOVW dst, #(src&0xffff)

    "../../aaa.asm", REMARK at line 368: [R0001]

    After symbol substitution the line became:

    MOVW r0, #(coverageStartAddress&0xffff)

  • Unfortunately, your request is beyond the capability of macros supplied in the TI assembler.

    Thanks and regards,

    -George

  • While it is true that it is presently beyond the capabilities of the TI assembler to perfectly replicate the behavior of the LDR pseudo-instruction, I'm not convinced that you necessarily need all of the features of that pseudo-instruction.  I think you just need the TI assembler to accept the machine-generated syntax and load the the register with the correct value, and you need this on a Cortex device.  I think the following does that.  It will miss opportunities to use a smaller instruction sequence, so there will be a small code size hit.

    LDR     .macro dst, src
            .if $$firstch(src,'#')
            LDR  dst, :src(2,$$symlen(src)):
            .elseif $$firstch(src,'=')
            LDR  dst, :src(2,$$symlen(src)):
            .elseif $$iscons(src)
            MOVW dst, #(src >> 16)
            MOVT dst, #(src & 0xffff)
            .else
            MOVW dst, src
            MOVT dst, src
            .endif
            .endm
    
            .global _c_int00
            .global main
    main:
             LDR   R3, 0xabcd1234
             LDR   R3, #0xabcd1234
             LDR   R3, main
             LDR   R3, _c_int00
             LDR   R3, =main
             LDR   R3, =_c_int00
    
  • Correct me if I'm wrong, but this macro seems to be using single LDR for loading address of a label. While this might work fine for locally defined labels which address can be calculated (relatively to the address of LDR instruction) at assemble time, it will fail when trying to use external symbol. And it should - an external symbol can have any address within 32-bit space so it is simply impossible to load the address using a single 32-bit opcode.

    Anyway, thanks for the effort of writing this macro. I believe it will be helpful to use it for constants like in LDR R3, 0xabcd1234.

  • If the argument is a symbol, local or otherwise, it will end up using two instructions: a MOVW/MOVT pair. The first two cases are just striping the # or = prefix and calling the macro again.
  • This works!

    I turns out that "movt, reg, symbol" takes the HIGHER half of the symbol - which is something that I didn't expect. The ARMv7_RM says that:

    Assembler syntax
    MOVT{<c>}{<q>} <Rd>, #<imm16>
    where:
    <c>, <q> See Standard assembler syntax fields on page A8-287.
    <Rd> The destination register.
    <imm16> The immediate value to be written to  <Rd> . It must be in the range 0-65535.
    Operation
    if ConditionPassed() then
    EncodingSpecificOperations();
    R[d]<31:16> = imm16;
    // R[d]<15:0> unchanged

    So I'm surprised that I can use a symbol and assembler knows that it should take the upper half. I was expecting that it will take the LOWER 16 bits and chop off the rest. This is something that is missing in the CSS documentation (or I didn't found it).

    By the way, thanks for pointing out that the macro may be calling itself (didn't know that it is possible).

    Anyway, Archaeologist provided the right solution for me. One suggestion - use a different name (not LDR) so the regular LDR opcode can be used instead of macro.

    Thanks.