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.

CC2652R: _restore_interrupts() in ti_compatibility.h causes "invalid operand for instruction"

Part Number: CC2652R
Other Parts Discussed in Thread: CC2674R10, CC1354P10,

Tool/software:

Hi all,

I'm using TI Arm Clang Compiler v3.2.2.LTS, CCS v12.4, CC2674R10 (Cortex M33, Armv8-M)

building a project based on project_zero example

trying to use code originally written for armcl

this code uses _disable_interrupts() and _restore_interrupts() intrinsics to protect critical sections:

    uint32_t savevar;
    savevar = _disable_interrupts(); // get current interrupt state and disable interrupts (TI ARM Compiler intrinsic)
    // critical code...
    _restore_interrupts(savevar);    // restore interrupt state (TI ARM Compiler intrinsic)

tiarmclang does not support these intrinsics, but provides the ti_compatibility.h header file that should convert them to a tiarmclang compatible form:

/******************************************************************************/
/* Disable interrupts                                                         */
/******************************************************************************/
static __inline__ uint32_t __attribute__((always_inline))
_disable_interrupts(void)
{
#if __ARM_ARCH_PROFILE == 'M' && __ARM_ARCH == 6
    return _disable_IRQ();
#elif __ARM_ARCH_PROFILE == 'M' && __ARM_ARCH == 7
    uint32_t res = 0;
    __asm volatile ("MRS %0, FAULTMASK" : "=r" (res) : : );
    __asm volatile ("CPSID F" : : : );
    return res;
#elif __ARM_ARCH >= 7
    uint32_t res = _get_CPSR();
     __asm volatile ("CPSID IF" : : : );
    return res;
#else
    return 0
#endif
}

/******************************************************************************/
/* Restore interrupts                                                         */
/******************************************************************************/
static __inline__ void __attribute__((always_inline))
_restore_interrupts(uint32_t x)
{
#if __ARM_ARCH_PROFILE == 'M' && __ARM_ARCH == 6
    __asm volatile ("MSR PRIMASK, %0" : : "r" (x) : );
#elif __ARM_ARCH_PROFILE == 'M' && __ARM_ARCH == 7
    __asm volatile ("MSR FAULTMASK, %0" : : "r" (x) : );
#elif __ARM_ARCH >= 7
    __asm volatile ("MSR CPSR_fc, %0" : : "r" (x) : );
#endif
}

The compiler takes the path "#elif __ARM_ARCH >= 7" and fails on _restore_interrupts() with "invalid operand for instruction":

C:\ti\ccs1240\ccs\tools\compiler\ti-cgt-armllvm_3.2.2.LTS\include\c\ti_compatibility.h:1529:21: error: invalid operand for instruction
    __asm volatile ("MSR CPSR_fc, %0" : : "r" (x) : );
                    ^
<inline asm>:1:5: note: instantiated into assembly here
MSR CPSR_fc, r0
    ^

The Armv8-M Architecture Reference Manual does not even mention a CPSR register, let alone CPSR_fc.

Is this code (and with it the whole header file) applicabe to Arm v8-M at all?

Is there already a fix available for this problem?

Or is there an alternative with the same functionality?
I found CPUcpsid() in driverlib's cpu.h: it also returns the original interrupt enable state, but there is no function to restore it to that state.


Regards,

Wolfgang

  • For the source file being built when the compiler issues this diagnostic ...

    error: invalid operand for instruction

    ... please follow the directions in the article How to Submit a Compiler Test Case.

    Thanks and regards,

    -George

  • minimal test case in source:

    #include <ti_compatibility.h>
    int main()
    {
        uint32_t savevar;
        savevar = _disable_interrupts(); // get current interrupt state and disable interrupts (TI ARM Compiler intrinsic)
        // critical code...
        _restore_interrupts(savevar);    // restore interrupt state (TI ARM Compiler intrinsic)
    
        return 0;
    }
    

    compiler version: ti-cgt-armllvm_3.2.2.LTS

    build command copied from CCS Console:
    "C:/ti/ccs1240/ccs/tools/compiler/ti-cgt-armllvm_3.2.2.LTS/bin/tiarmclang.exe" -c @"C:/ti/simplelink_cc13xx_cc26xx_sdk_7_40_00_77/source/ti/ble5stack_flash/config/build_components.opt" @"C:/ti/simplelink_cc13xx_cc26xx_sdk_7_40_00_77/source/ti/ble5stack_flash/config/factory_config.opt" -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mlittle-endian -Oz -I"C:/ti/ccs1240/ccs/tools/compiler/ti-cgt-armllvm_3.2.2.LTS/include/c" -DEXCLUDE_OAD -DCC13XX -DCC13X4 -DFLASH_ONLY_BUILD -DNVOCMP_NWSAMEITEM=1 -DNVOCMP_NVPAGES=4 -Dxdc_target__isaCompatible_v8M -DHEAPMGR_CONFIG=0x80 -DHEAPMGR_SIZE=0x0 -DEM_CC1354P10_1_LP -gdwarf-3 -MMD -MP -MF"Startup/problem.d_raw" -MT"Startup/problem.o" -std=c11 @"syscfg/ti_utils_build_compiler.opt" -o"Startup/problem.o" "../Startup/problem.c"

    preprocessed test case file:
    problem.pp.txt

  • Thank you for the test case.  I can reproduce the same behavior.  I filed the entry EXT_EP-11787 to have this investigated.  You are welcome to follow it with that link.

    Thanks and regards,

    -George

  • ok, thanks for filing this.

    So can I assume that the answer to 

    Is this code (and with it the whole header file) applicable to Arm v8-M at all?

    Is there already a fix available for this problem?

    would be "no" as of armllvm_3.2.2.LTS?

    BTW: looking for a workaround, I stumbled across another potential bug, see related question:
    https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/1372162/cc2652r-is-hal_enter_critical_section-in-hal_mcu-h-correctly-implemented

    Regards,
    Wolfgang

  • Please see EXT_EP-11787 for the explanation of the compiler's behavior.

    Thanks and regards,

    -George

  • I just noticed I had filed this under the wrong part number (got 2 concurrent projects confused)

    CC2674R10 is correct (Cortex M33)
    CC2652R was wrong (Cortex M4F)

    the test case file is however correct.

    Apologies

  • Thanks, I see, TI won't fix. So ti_compatibilty.h cannot be used for M33.

    There's a lot of stuff apart from the interrupt-related functions that would be useful for projects being ported from CC26xx M4F armcl to CC26xx M33 armllvm (like ours).

    Currently, the interrupt-related functions assume that __ARM_ARCH > 7 is Armv8, but this fails for Armv8M (Cortex M33).
    They could simply check __ARM_ARCH_PROFILE like they do for v6 and v7.

  • You are, in effect, asking that the scope of testing and support for ti_compatibility.h be expanded.  Suppose we start to expand it.  Where does that expansion end?  Rather than let that occur, we limit the scope of ti_compatibility.h to what armcl supports.  Unfortunately, that does not include support for Cortex-M33.

    Thanks and regards,

    -George

  • Yes, I see that.

    We switched from CC2652 to CC2674, i.e. from M4 to M33 (and consequently from armcl to armllvm), under the assumption that they are compatible and the switch would be easy. Now we see that it isn't and that ti_compatibility.h provides no support for this migration path.

    We can deal with that, no problem, it's just an unpleasant customer experience.