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.

TMS320F28386D: Migration COFF to EABI

Part Number: TMS320F28386D


I'm encountering an issue while working on my project for the C6000 architecture. Specifically, I'm getting the following error: [E0200] Unable to resolve this relocatable expression; relocation support for arbitrary expressions is not available in the C6000 EABI.

Continuing from the error message, it appears that the issue might be related to the definition of a macro in my code. I've reviewed the code and couldn't identify any obvious issues, so I'm reaching out to see if anyone has encountered a similar problem before and knows how to resolve it.

If anyone has any insights or suggestions on what might be causing this error or how to troubleshoot it further, I would greatly appreciate it.

Any help or suggestions would be greatly appreciated.

POINT_RVI .macro
MPY P,AR0,#(__LnPgVI>>6)
ADD PL,#(0x03FF & (flgBKB>>6))
PUSH PL
POP DP
.endmNuovo documento di testo (2).txt

Thank you!"

  • You use the C2000 compiler toolchain.  This diagnostic ...

    [E0200] Unable to resolve this relocatable expression; relocation support for arbitrary expressions is not available in the C6000 EABI.

    ... has a spelling error.  It should say C2000 EABI, and not C6000 EABI.

    Expressions like this ...

    #(__LnPgVI>>6)

    or this ...

    #(0x03FF & (flgBKB>>6))

    ... are not supported in C2000 EABI.  That's because __LnPgVI and flgBKB are relocatable symbols whose value is not known when assembling.  When a relocatable symbol is part of a larger expression like that, it is termed a relocatable expression.  These expressions are supported in the older COFF ABI, not in the newer EABI.  

    I'm not sure of the best way to fix this macro.  It is unusual to compute an address into the DP like that.  I will notify C2000 CPU experts about this thread.

    Speaking more generally, the article C2000 Migration from COFF to EABI is likely to be useful.

    Thanks and regards,

    -George

  • Hi George  thank you for your suggestions. I agree that the macro approach to calculating an address in the DP is unconventional. It is used to cycle 8 through channels.

    Below I leave a code extract, where the overvoltage of the VoBKBi variable is verified for the 8 channels.

    I appreciate your willingness to notify an expert.

    Thanks and regards, Marcos

    MOV AR0,#(nChReg-1)

    ***

    ***

    ***

    ---------- OVERVOLTAGE Vout (IsrIst.6) --------------
    ;

    POINT_RVI
    CMP @VoBKBi,#VoutMax_h
    SB IIstb2_0,LT

    TSET @IsrIst,#6 ; Attiva flag critico
    LB IIstb2nd

    IIstb2_0 CMP @VoBKBi,#VoutMax_l
    SB IIstb2nd,GT

    ;TBIT @flgBKB,#12 ; N.B: come da codice originale
    ;SB IIstb2nd,NTC

    TCLR @IsrIst,#6 ; Resetta flag critico

    IIstb2nd ;NOP

    ; --------- OVERVOLTAGE Vbus (IsrIst.5) --------------
    ;

    POINT_RVI
    NOP *,ARP2

    MOVL XAR2,#VoRLYi
    CMP *,#VbusMax_h
    SB IIstb1_0,LT

    TSET @IsrIst,#5 ; Attiva flag critico
    LB IIstb1nd

  • Added extract from the definition of the variables. I consider these symbols as not relocatable What do you think?

    flgBKB .usect ".VIpg1",1 ; Flag controllo
    _flgBKB .set flgBKB

    LnPgVI is defined within cmd

    *******************

    ********************

    GROUP
    {
    .TI.ramfunc
    { -l F2838x_C28x_FlashAPI.lib}

    } LOAD = FLASHD,
    RUN = RAMLS0_LS3,
    LOAD_START(RamfuncsLoadStart),
    LOAD_SIZE(RamfuncsLoadSize),
    RUN_START(RamfuncsRunStart),
    PAGE = 0, ALIGN(8)

    .ISR_code : LOAD = FLASHN,
    RUN = RAMGS8_GS9,
    LOAD_START(ISRcodeLoadStart),
    LOAD_SIZE(ISRcodeLoadSize),
    RUN_START(ISRcodeRunStart),
    PAGE = 0, ALIGN(8)

    .reset : > RESET, PAGE = 0, TYPE = DSECT /* not used, */
    .stack : > RAMstack, PAGE = 1
    .bss : > RAMbss, PAGE = 1
    .bss:cio : > RAMbss, PAGE = 1
    .data : > RAMbss, PAGE = 1
    .sysmem : > RAMbss, PAGE = 1


    .RamShare0 : > RAMGS0, PAGE = 1

    .reg1 : > Lx_reg1, PAGE = 1
    .reg2 : > Lx_reg2, PAGE = 1
    .reg3 : > Lx_reg3, PAGE = 1
    .reg4 : > Lx_reg4, PAGE = 1
    .reg5 : > Lx_reg5, PAGE = 1
    .reg6 : > Lx_reg6, PAGE = 1
    .reg7 : > Lx_reg7, PAGE = 1
    .VIpg1 : > LxVIpg1, PAGE = 1
    .VIpg2 : > LxVIpg2, PAGE = 1, {__LnPgVI=2*0x40;}
    .VIoth : > LxVIoth, PAGE = 1
    .bfcom : > Lx_oth, PAGE = 1

  • Try this - When you assign the variables to a memory block create a RUN_START(<symbol name>) symbol for each - similar to what is done for the flashAPI library. This symbol, defined as an extern, can be used in your code. 

  • Ciao Lori, do you propose to do this?

    -e code_start /* Forza Entry Point su pCode */
    -stack 0x05F8 /* Alloca stack per lo stack C ed ASM */


    MEMORY
    {
    PAGE 0 :

    BEGIN : origin = 0x080000, length = 0x000002

    CHECK_1 : origin = 0x080008, length = 0x000008
    CHECK_2 : origin = 0x080010, length = 0x000008
    CHECK_3 : origin = 0x080018, length = 0x000018

    /*RAMLS0 : origin = 0x008000, length = 0x000800
    RAMLS1 : origin = 0x008800, length = 0x000800
    RAMLS2 : origin = 0x009000, length = 0x000800
    RAMLS3 : origin = 0x009800, length = 0x000800*/
    RAMLS0_LS3 : origin = 0x008000, length = 0x002000

    RAMGS5 : origin = 0x012000, length = 0x001000
    RAMGS6 : origin = 0x013000, length = 0x001000
    RAMGS7 : origin = 0x014000, length = 0x001000

    /*RAMGS8 : origin = 0x015000, length = 0x001000
    RAMGS9 : origin = 0x016000, length = 0x001000*/
    RAMGS8_GS9 : origin = 0x015000, length = 0x001FF0

    RESET : origin = 0x3FFFC0, length = 0x000002

    /* Flash sectors */
    FLASHA : origin = 0x080030, length = 0x001FD0 /* check control sector */

    /*FLASHB : origin = 0x082000, length = 0x002000
    FLASHC : origin = 0x084000, length = 0x002000*/
    FLASHB_C : origin = 0x082000, length = 0x004000

    FLASHD : origin = 0x086000, length = 0x002000
    /*FLASHE : origin = 0x088000, length = 0x008000
    FLASHF : origin = 0x090000, length = 0x008000*/
    FLASHE_F : origin = 0x088000, length = 0x010000

    FLASHG : origin = 0x098000, length = 0x008000 /* on-chip Flash */
    FLASHH : origin = 0x0A0000, length = 0x008000 /* on-chip Flash */
    FLASHI : origin = 0x0A8000, length = 0x008000 /* on-chip Flash */
    FLASHJ : origin = 0x0B0000, length = 0x008000 /* on-chip Flash */
    FLASHK : origin = 0x0B8000, length = 0x002000 /* on-chip Flash */
    FLASHL : origin = 0x0BA000, length = 0x002000 /* on-chip Flash */
    FLASHM : origin = 0x0BC000, length = 0x002000 /* on-chip Flash */

    FLASHN : origin = 0x0BE000, length = 0x001FF0

    PAGE 1 :

    BOOT_RSVD : origin = 0x000002, length = 0x0001AF /* Part of M0, BOOT rom will use this for stack */
    RAMM0free : origin = 0x0001B1, length = 0x00004F

    /*RAMM0 : origin = 0x000200, length = 0x000200
    RAMM1 : origin = 0x000400, length = 0x000400*/
    RAMstack : origin = 0x000200, length = 0x0005F8

    // RAMM1_RSVD : origin = 0x0007F8, length = 0x000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */

    RAMLS4 : origin = 0x00A000, length = 0x000800
    RAMLS5 : origin = 0x00A800, length = 0x000800

    /*RAMLS6 : origin = 0x00B000, length = 0x000800
    RAMLS7 : origin = 0x00B800, length = 0x000800
    RAMD0 : origin = 0x00B000, length = 0x000800
    RAMD1 : origin = 0x00B800, length = 0x000800*/
    RAMbss : origin = 0x00B000, length = 0x002000

    RAMGS0 : origin = 0x00D000, length = 0x001000

    /*RAMGS1 : origin = 0x00E000, length = 0x001000*/
    Lx_reg1 : origin = 0x00E000, length = 0x000040
    Lx_reg2 : origin = 0x00E040, length = 0x000040
    Lx_reg3 : origin = 0x00E080, length = 0x000040
    Lx_reg4 : origin = 0x00E0C0, length = 0x000040
    Lx_reg5 : origin = 0x00E100, length = 0x000040
    Lx_reg6 : origin = 0x00E140, length = 0x000040
    Lx_reg7 : origin = 0x00E180, length = 0x000040
    LxVIpg1 : origin = 0x00E1C0, length = 0x000040
    LxVIpg2 : origin = 0x00E200, length = 0x000040
    LxVIoth : origin = 0x00E240, length = 0x000380
    Lx_oth : origin = 0x00E5C0, length = 0x000A40

    RAMGS2 : origin = 0x00F000, length = 0x001000

    /*RAMGS3 : origin = 0x010000, length = 0x001000*/
    Lx_reg1_cpu2 : origin = 0x010000, length = 0x000040
    LxVIpg1_cpu2 : origin = 0x010040, length = 0x000040
    LxVIpg2_cpu2 : origin = 0x010080, length = 0x000040
    LxVIoth_cpu2 : origin = 0x0100C0, length = 0x000380
    Lx_oth_cpu2 : origin = 0x010440, length = 0x000BC0


    /*RAMGS4 : origin = 0x011000, length = 0x001000*/
    RAMGS4_1 : origin = 0x011000, length = 0x000400
    RAMGS4_2 : origin = 0x011400, length = 0x000400


    CPU1TOCPU2RAM : origin = 0x03A000, length = 0x000800
    CPU2TOCPU1RAM : origin = 0x03B000, length = 0x000800

    CPUTOCMRAM : origin = 0x039000, length = 0x000800
    CMTOCPURAM : origin = 0x038000, length = 0x000800
    }


    SECTIONS
    {
    codestart : > BEGIN, PAGE = 0, ALIGN(8)

    codeck_c : > CHECK_1, PAGE = 0, ALIGN(8)
    codeck_asm : > CHECK_2, PAGE = 0, ALIGN(8)
    codeck_text : > CHECK_3, PAGE = 0, ALIGN(8)

    .cinit : > FLASHB_C, PAGE = 0, ALIGN(8)
    .init_array : > FLASHB_C, PAGE = 0, ALIGN(8)

    .const : > FLASHB_C, PAGE = 0, ALIGN(8)

    .text : > FLASHE_F, PAGE = 0, ALIGN(8)

    .switch : LOAD = FLASHD,
    RUN = RAMLS0_LS3,
    LOAD_START(SwitchLoadStart),
    LOAD_SIZE(SwitchLoadSize),
    RUN_START(SwitchRunStart),
    PAGE = 0, ALIGN(8)

    GROUP
    {
    .TI.ramfunc
    { -l F2838x_C28x_FlashAPI.lib}

    } LOAD = FLASHD,
    RUN = RAMLS0_LS3,
    LOAD_START(RamfuncsLoadStart),
    LOAD_SIZE(RamfuncsLoadSize),
    RUN_START(RamfuncsRunStart),
    PAGE = 0, ALIGN(8)

    .ISR_code : LOAD = FLASHN,
    RUN = RAMGS8_GS9,
    LOAD_START(ISRcodeLoadStart),
    LOAD_SIZE(ISRcodeLoadSize),
    RUN_START(ISRcodeRunStart),
    PAGE = 0, ALIGN(8)

    .reset : > RESET, PAGE = 0, TYPE = DSECT /* not used, */
    .stack : > RAMstack, PAGE = 1
    .bss : > RAMbss, PAGE = 1
    .bss:cio : > RAMbss, PAGE = 1
    .data : > RAMbss, PAGE = 1
    .sysmem : > RAMbss, PAGE = 1


    .RamShare0 : > RAMGS0, PAGE = 1

    .reg1 : > Lx_reg1, PAGE = 1
    .reg2 : > Lx_reg2, PAGE = 1
    .reg3 : > Lx_reg3, PAGE = 1
    .reg4 : > Lx_reg4, PAGE = 1
    .reg5 : > Lx_reg5, PAGE = 1
    .reg6 : > Lx_reg6, PAGE = 1
    .reg7 : > Lx_reg7, PAGE = 1
    .VIpg1 : > LxVIpg1, PAGE = 1
    .VIpg2 : > LxVIpg2, PAGE = 1, {__LnPgVI=2*0x40;}, RUN_START(__LnPgVI)
    .VIoth : > LxVIoth, PAGE = 1
    .bfcom : > Lx_oth, PAGE = 1

    .RamShare1 : > RAMGS2, PAGE = 1

    .reg1_cpu2 : > Lx_reg1_cpu2, PAGE = 1
    .VIpg2_cpu2 : > LxVIpg2_cpu2, PAGE = 1
    .bfcom_cpu2 : > Lx_oth_cpu2, PAGE = 1

    MSGRAM_CPU1_TO_CPU2 : > CPU1TOCPU2RAM, type=NOINIT
    MSGRAM_CPU2_TO_CPU1 : > CPU2TOCPU1RAM, type=NOINIT
    MSGRAM_CPU_TO_CM : > CPUTOCMRAM, type=NOINIT
    MSGRAM_CM_TO_CPU : > CMTOCPURAM, type=NOINIT

    .DataLog1 : > RAMGS4_1, PAGE = 1, RUN_START(pLog)
    .DataLog2 : > RAMGS4_2, PAGE = 1


    /* The following section definitions are required when using the IPC API Drivers */
    GROUP : > CPU1TOCPU2RAM, PAGE = 1
    {
    PUTBUFFER
    PUTWRITEIDX
    GETREADIDX
    }

    GROUP : > CPU2TOCPU1RAM, PAGE = 1
    {
    GETBUFFER : TYPE = DSECT
    GETWRITEIDX : TYPE = DSECT
    PUTREADIDX : TYPE = DSECT
    }


    }

    Thank Marcos

  • Hi Marcos,

    .reg1 : > Lx_reg1, PAGE = 1
    .reg2 : > Lx_reg2, PAGE = 1
    .reg3 : > Lx_reg3, PAGE = 1
    .reg4 : > Lx_reg4, PAGE = 1
    .reg5 : > Lx_reg5, PAGE = 1
    .reg6 : > Lx_reg6, PAGE = 1
    .reg7 : > Lx_reg7, PAGE = 1
    .VIpg1 : > LxVIpg1, PAGE = 1
    .VIpg2 : > LxVIpg2, PAGE = 1, {__LnPgVI=2*0x40;}, RUN_START(__LnPgVI)
    .VIoth : > LxVIoth, PAGE = 1
    .bfcom : > Lx_oth, PAGE = 1

    Yes, I was thinking something like this. I'm not sure what the {__LnPgVI=2*0x40;}, is for though. Maybe I've misunderstood what you are trying to do?

  • Hi Lori, The POINT_RVI macro calculates a memory address based on __LnPgVI and adjusted by a value derived from flgBKB. This is used to set the data pointer DP to a specific location in memory, where the variables of the .VIpg2 section are located.

    LnPgVI can vary from 0 to 8 and corresponds to the number of buck-boost channels, while flgBKB is a flag that summarizes the faults.

    I've tried defining .VIpg2 : > LxVIpg2, PAGE = 1, {__LnPgVI=0x80;} instead of .VIpg2 : > LxVIpg2, PAGE = 1, {__LnPgVI=2*0x40;} and the variable __LnPgVI compiles, but flgBKB does not. Why does EABI not consider it absolute? This variable is defined as follows:

    flgBKB .usect ".VIpg1",1 ; Flag controllo
    _flgBKB .set flgBKB ;

    Sections  ".VIpg2"


    ; Sez. di regolaz. per BKB page2

    Vbathf .usect ".VIpg2",1 ; Tens. batt. filtrata
    _Vbathf .set Vbathf

    Ibathf .usect ".VIpg2",1 ; Tens. corr. filtrata
    _Ibathf .set Ibathf

    VoBKBhf .usect ".VIpg2",1 ; Tens. di uscita filtrata
    _VoBKBhf .set VoBKBhf

    ILbkbhf .usect ".VIpg2",1 ; Corr. di uscita filtrata
    _ILbkbhf .set ILbkbhf

    _Vbatlf .usect ".VIpg2",1 ; Tens. batt. filtrata
    _Ibatlf .usect ".VIpg2",1 ; Tens. corr. filtrata
    _VoBKBlf .usect ".VIpg2",1 ; Tens. di uscita filtrata
    _ILbkblf .usect ".VIpg2",1 ; Corr. di uscita filtrata

    V3eBKB .usect ".VIpg2",2,1,1 ; P.I. terzo anello di tensione
    V3e1BKB .set V3eBKB+1
    pV3BKB .usect ".VIpg2",2,1,1
    SatV3max .usect ".VIpg2",2,1,1
    SatV3min .usect ".VIpg2",2,1,1

    Err3Imax .usect ".VIpg2",2,1,1
    Err3Imin .usect ".VIpg2",2,1,1

    I3eBKB .usect ".VIpg2",2,1,1 ; P.I. terzo anello di corrente
    I3e1BKB .set I3eBKB+1
    pI3BKB .usect ".VIpg2",2,0,1
    SatI3max .usect ".VIpg2",2,1,1
    SatI3min .usect ".VIpg2",2,1,1

  • Is there a global variable in the output section that you can use to determine the DP?

    In assembly this is simply MOVW DP, #<variable>

    For example: 

  • hi, Gloria we have defined the both variables of the macro as global 

    .global _LnPgVI, flgBKB, _flgBKB

    -----------------------------------------------

    flgBKB .usect ".VIpg1",1 ; Flag controllo

    _flgBKB .set flgBKB

    ----------------------------------------

    POINT_RVI .macro
    MPY P,AR0,#(__LnPgVI>>6)
    ADD PL,#(0x03FF & (flgBKB>>6))
    PUSH PL
    POP DP

    I have realized that to define the variable you have used .asg, can this generate the error? Another point, I understood that for .asm in EABI it is not necessary to declare the undercor _. Is this correct?

    in C i've defined the symbols as

    extern uint  flgBKB, _LnPgVI ...that is wrong?

    best regard Marcos

  • The .asg statements in my assembly are substitutions that enable the code to work for both EABI (no underscore on the variable) and in COFF (underscore on the variable).  It is like a #define in C.  Anywhere in my assembly code, if I compile in EABI  _myVar will be treated as myVar (www.ti.com/lit/spru513 for more information)

  • Hi Lori, I have managed to solve the problem by modifying the macro as follows.

    POINT_RVI .macro
    ;ADD PL,#(flgBKB) ;(0x0387)
    MPY P,AR0,#(_LnPgVI>>6)
    PUSH ACC
    MOV ACC,#flgBKB
    LSR AL,#6
    ADD PL,AL
    PUSH PL
    POP DP
    POP ACC
    .endm

    Thanks for your help it was useful