AM263P4: ARM Cortex R5F FIQ interrupt and FPU context saving

Part Number: AM263P4

Hello,

I am facing similar issue reported in AM263P4: FIQ interrupt has been interrupting code in main loop and not saving the context of the s0-s31 registers

In my case, I am not manually saving the FPU context but I have rebuilt the SDK with the HWIP_FPU_CONTEXT_SAVE_RESTORE_ENABLE flag in order to save/restore the FPU context in the HwiP_fiq_handler but it still doesn't work and the FPU registers are randomly corrupted by the FIQ. When I configure the interrupt as an IRQ then it works fine.

Consider this code, executed in a FreeRTOS task (I also have called the vPortTaskUsesFPU in the task even thoug this shouldn't be relevant for an FIQ):

image.pngimage.png
vac_val has a value of -10.88 but the check passes randomly, when I looked into the assemply and the registers, it seems that the value in the FPU was corrupted
image.pngimage.png
 
This is how it looks like when the registers are not corrupted:
image.png

Could you please provide any advice on how to fix this issue, many thanks in advance

Note: I am using mcu_plus_sdk_am263px_26_00_00_06 SDK and ti_cgt_arm_llvm_4.0.4.LTS compiler

  • I changed the project compiler to TI Clang v5.1.1.LTS and still has the same issue.

    I added the __attribute__((target("general-regs-only"))) as suggested in the other post but I get a warning and it's ignored by the compiler

    void TEXT_HWI __attribute__((interrupt("FIQ"))) __attribute__((target("general-regs-only")))HwiP_fiq_handler(void)
     Compiling: freertos.am263px.r5f.ti-arm-clang.debug.lib: dpl/r5/HwiP_armv7r_handlers_freertos.c
    '+general-regs-only' is not a recognized feature for this target (ignoring feature)
    By the way this is the disassembly of the of the FIQ Handler HwiP_fiq_handler() and the save/restore FPU context functions

    Hwip_restore_fpu_context()
    BC01                pop     {r0}
    0B20ECBD            vpop    {d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15}
    0A10EEE1            vmsr    fpscr, r0
    4770                bx      lr
    0000                movs    r0, r0
    0000                movs    r0, r0

    Hwip_save_fpu_context()
    0A10EEF1            vmrs    r0, fpscr
    0B20ED2D            vpush   {d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15}
    B401                push    {r0}
    4770                bx      lr
    0000                movs    r0, r0
    0000                movs    r0, r0

    HwiP_fiq_handler()
    B5DF                push    {r0, r1, r2, r3, r4, r6, r7, lr}
    AF06                add     r7, sp, #0x18
    B086                sub     sp, #0x18
    466C                mov     r4, sp
    0402F36F            bfc     r4, #0, #3
    46A5                mov     sp, r4
    F9C7F7E8            bl      0x7029f2a0 <Hwip_save_fpu_context>
    F865F000            bl      0x702b6fe0 <HwiP_getFIQVecAddr>
    68A4F246            movw    r8, #0x66a4
    082AF2C7            movt    r8, #0x702a
    0000F8C8            str.w   r0, [r8]
    A804                add     r0, sp, #0x10
    F86CF000            bl      0x702b7000 <HwiP_getFIQ>
    9005                str     r0, [sp, #0x14]
    8014F8DD            ldr.w   r8, [sp, #0x14]
    0F00F1B8            cmp.w   r8, #0x0
    D13B                bne     0x702b6fac
    E7FF                b       0x702b6f36
    9804                ldr     r0, [sp, #0x10]
    FFA2F7FF            bl      0x702b6e80 <HwiP_isPulse>
    9003                str     r0, [sp, #0xc]
    800CF8DD            ldr.w   r8, [sp, #0xc]
    0F00F1B8            cmp.w   r8, #0x0
    D004                beq     0x702b6f52
    E7FF                b       0x702b6f4a
    9804                ldr     r0, [sp, #0x10]
    FC10F7FF            bl      0x702b6770 <HwiP_clearInt>
    E7FF                b       0x702b6f52
    9010F8DD            ldr.w   r9, [sp, #0x10]
    1820F243            movw    r8, #0x3120
    082AF2C7            movt    r8, #0x702a
    9029F858            ldr.w   r9, [r8, r9, lsl #2]
    9008F8CD            str.w   r9, [sp, #0x8]
    9010F8DD            ldr.w   r9, [sp, #0x10]
    0889EB08            add.w   r8, r8, r9, lsl #2
    8400F8D8            ldr.w   r8, [r8, #0x400]
    8004F8CD            str.w   r8, [sp, #0x4]
    8008F8DD            ldr.w   r8, [sp, #0x8]
    0F00F1B8            cmp.w   r8, #0x0
    D005                beq     0x702b6f8c
    E7FF                b       0x702b6f82
    8008F8DD            ldr.w   r8, [sp, #0x8]
    9801                ldr     r0, [sp, #0x4]
    47C0                blx     r8
    E7FF                b       0x702b6f8c
    EB1EF000            blx     0x702b75cc <HwiP_disableFIQ>
    800CF8DD            ldr.w   r8, [sp, #0xc]
    0F00F1B8            cmp.w   r8, #0x0
    D104                bne     0x702b6fa4
    E7FF                b       0x702b6f9c
    9804                ldr     r0, [sp, #0x10]
    FBE7F7FF            bl      0x702b6770 <HwiP_clearInt>
    E7FF                b       0x702b6fa4
    9804                ldr     r0, [sp, #0x10]
    F853F000            bl      0x702b7050 <HwiP_ackFIQ>
    E00D                b       0x702b6fc8
    1920F243            movw    r9, #0x3120
    092AF2C7            movt    r9, #0x702a
    8804F8D9            ldr.w   r8, [r9, #0x804]
    0801F108            add.w   r8, r8, #0x1
    8804F8C9            str.w   r8, [r9, #0x804]
    2000                movs    r0, #0x0
    F845F000            bl      0x702b7050 <HwiP_ackFIQ>
    E7FF                b       0x702b6fc8
    F962F7E8            bl      0x7029f290 <Hwip_restore_fpu_context>
    0418F1A7            sub.w   r4, r7, #0x18
    46A5                mov     sp, r4
    40DFE8BD            pop.w   {r0, r1, r2, r3, r4, r6, r7, lr}
    8F04F3DE            subs    pc, lr, #0x4
    BF00                nop
    BF00                nop
    BF00                nop
  • Hi Khalil,

    Let me discuss this with other experts and get back early next week

    Regards,
    Shaunak

  • Hi Khalil,

    Apologies for a delayed response, Can you please help me with the following:

    1. Do you see this issue across different compiler flags? The core issue can be that the compiler generates prologue/epilogue code in your FIQ handler that uses FPU registers as scratch space before the SDK's Hwip_save_fpu_context() executes and after Hwip_restore_fpu_context() completes.

    2. Do you see this issue every single execution cycle? can you share a sample project that I can try out?

    ___

    From the dissassembly, i see a likely root-cause, the saved FPU context is overwritten by the FIQ handler's own local variables.On the AM263Px/AM261x R5F (VFPv3-D16), s0-s31 are the same storage as d0-d15: s(2n) is the low half of d(n) and s(2n+1) is the high half. Restoring d0-d15 restores every s register, so you don't need to refresh anything. The s registers look wrong only because the saved d data was already corrupted.

    One fix we can try:

    - Replace the attached modified files and then build the NoRTOS or FreeRTOS library from command line

    FreeRTOS:

    /*
     *  Copyright (C) 2018-2023 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <kernel/dpl/HwiP.h>
    #include <kernel/nortos/dpl/r5/HwiP_armv7r_vim.h>
    #include <drivers/hw_include/csl_types.h>
    #include <drivers/hw_include/soc_config.h>
    #include <drivers/pmu.h>
    #include <FreeRTOSConfig.h>
    
    #define TEXT_HWI    __attribute__((section(".text.hwi")))
    #define WEAK        __attribute__((weak))
    
    static volatile uint32_t gdummy;
    
    /* Save FPU context, used in FIQ Handler */
    static inline  void Hwip_save_fpu_context(void)
    {
    #if defined(__ICCARM__)
        __asm volatile ( "FMRX  R0, FPSCR"  "\n\t": : : "memory");
        __asm volatile ( "VPUSH {D0-D15}"  "\n\t": : : "memory");
        __asm volatile ( "PUSH  {R0}"  "\n\t": : : "memory");
    #else
        __asm__ __volatile__ ( "FMRX  R0, FPSCR"  "\n\t": : : "memory");
        __asm__ __volatile__ ( "VPUSH {D0-D15}"  "\n\t": : : "memory");
        __asm__ __volatile__ ( "PUSH  {R0}"  "\n\t": : : "memory");
    #endif
    }
    
    /* Restore FPU context, used in FIQ Handler */
    static inline  void Hwip_restore_fpu_context(void)
    {
    #if defined(__ICCARM__)
    
        __asm volatile ( "POP   {R0}"  "\n\t": : : "memory");
        __asm volatile ( "VPOP  {D0-D15}"  "\n\t": : : "memory");
        __asm volatile ( "VMSR  FPSCR, R0"  "\n\t": : : "memory");
    #else
        __asm__ __volatile__ ( "POP   {R0}"  "\n\t": : : "memory");
        __asm__ __volatile__ ( "VPOP  {D0-D15}"  "\n\t": : : "memory");
        __asm__ __volatile__ ( "VMSR  FPSCR, R0"  "\n\t": : : "memory");
    #endif
    }
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #if defined(SOC_AM273X)
    /*back-2-back nesting issue (AM273x errata i2162 workaround) */
    static void Hwip_dataAndInstructionBarrier(void)
    {
    #if defined(__ICCARM__)
        __ISB();
        __DSB();
    #else
        __asm__ __volatile__ (" isb"   "\n\t": : : "memory");
        __asm__ __volatile__ (" dsb"   "\n\t": : : "memory");
    #endif
    }
    
    /* Get the status of a specific interrupt in VIM_RAW register */
    static uint32_t HWI_SECTION HwiP_get(uint32_t intNum)
    {
        volatile uint32_t *addr;
        uint32_t bitPos;
        uint32_t val;
    
        addr = (volatile uint32_t *)(gHwiConfig.intcBaseAddr + VIM_RAW(intNum));
        bitPos = VIM_BIT_POS(intNum);
    
        val = (*addr) & ((uint32_t)0x1 << bitPos);
    
        /*
         * Add delay to ensure posted interrupt is triggered before function returns.
         */
        Hwip_dataAndInstructionBarrier();
    
        return val;
    }
    
    /* Post and clear the dummy interrupt */
    static void HWI_SECTION dummyIrqNest(void)
    {
        /* Set the interrupt flag of DUMMY IRQ */
        HwiP_post(HWIP_DUMMY_INTERRUPT_NUM);
        /* Make sure the dummy interrupt has been set */
        while(HwiP_get(HWIP_DUMMY_INTERRUPT_NUM) == 0U)
        {
            /* Do nothing */
        }
        /* Get the interrupt vector */
        (void)HwiP_getIRQVecAddr();
        /* Clear the interrupt flag of DUMMY IRQ */
        HwiP_clearInt(HWIP_DUMMY_INTERRUPT_NUM);
        /* Wait until it is actually been cleared */
        while(HwiP_get(HWIP_DUMMY_INTERRUPT_NUM) != 0U)
        {
            /* Do nothing */
        }
        /* Acknowledge DUMMY IRQ */
        HwiP_ackIRQ(HWIP_DUMMY_INTERRUPT_NUM);
    }
    #endif
    
    /* Following handlers are set directly in vector table, hence use interrupt attribute */
    #if defined (__ICCARM__)
    void TEXT_HWI HwiP_reserved_handler(void);
    void TEXT_HWI HwiP_fiq_handler(void);
    #else
    /* HwiP_fiq_handler is a naked asm wrapper (saves FPU context) around HwiP_fiq_handler_c */
    void TEXT_HWI __attribute__((interrupt("UNDEF"))) HwiP_reserved_handler(void);
    void TEXT_HWI __attribute__((naked)) HwiP_fiq_handler(void);
    void TEXT_HWI HwiP_fiq_handler_c(void);
    #endif
    
    /** Following handlers starts in assembly and switch to C implementation. 
     * Hence DON'T use interrupt attribute. Else it will result in re-entry */ 
    void TEXT_HWI HwiP_irq_handler_c(void);
    void TEXT_HWI HwiP_undefined_handler_c(volatile uint32_t LR);
    void TEXT_HWI HwiP_prefetch_abort_handler_c(volatile uint32_t LR);
    void TEXT_HWI HwiP_data_abort_handler_c(volatile uint32_t LR);
    /* Use weak attribute with user handler so that applications can override with its own implementation */
    void TEXT_HWI WEAK HwiP_user_data_abort_handler_c(DFSR dfsr, ADFSR adfsr, volatile uint32_t DFAR, 
                                                      volatile uint32_t LR,volatile uint32_t SPSR);
    void TEXT_HWI WEAK HwiP_user_prefetch_abort_handler_c(IFSR ifsr, AIFSR aifsr, volatile uint32_t IFAR, 
                                                          volatile uint32_t LR,volatile uint32_t SPSR);
    void TEXT_HWI WEAK HwiP_user_undefined_handler_c(volatile uint32_t LR,volatile uint32_t SPSR);
    
    uint32_t GET_DFSR(void);
    uint32_t GET_ADFSR(void);
    uint32_t GET_DFAR(void);
    uint32_t GET_IFSR(void);
    uint32_t GET_AIFSR(void);
    uint32_t GET_IFAR(void);
    uint32_t GET_SPSR(void);
    uint32_t GET_LR(void);
    #ifdef __cplusplus
    }
    #endif
    
    #ifdef INTR_PROF
    void TEXT_HWI HwiP_irq_profile_c(uint32_t intNum)
    {
        uint32_t idx = 0, exists = 1;
    
        for(idx = 0; idx <= gHwiCtrlProf.traceInterruptedISRIndex; idx++)
        {
            if(gHwiCtrlProf.traceInterruptedISR[idx] == intNum)
            {
                gHwiCtrlProf.traceInterruptedISR[idx] = 0;
                gHwiCtrlProf.traceInterruptedISRIndex --;
                if(gHwiCtrlProf.traceInterruptedISRIndex == 0)
                {
                    gHwiCtrlProf.readCounterStop = CSL_armR5PmuReadCntr(CSL_ARM_R5_PMU_CYCLE_COUNTER_NUM);
                    if(gHwiCtrlProf.readCounterStop > gHwiCtrlProf.readCounterStart)
                    {
                        gHwiCtrlProf.pmuCountVal += gHwiCtrlProf.readCounterStop - gHwiCtrlProf.readCounterStart - gHwiCtrlProf.pmuCalibration;
                    }
                    else
                    {
                        gHwiCtrlProf.pmuCountVal += (0xFFFFFFFFU - gHwiCtrlProf.readCounterStart) + gHwiCtrlProf.readCounterStop - gHwiCtrlProf.pmuCalibration;
                    }
                }
                exists = 0;
                break;
            }
        }
        if(exists)
        {
            gHwiCtrlProf.traceInterruptedISR[(gHwiCtrlProf.traceInterruptedISRIndex)] = intNum;
            gHwiCtrlProf.traceInterruptedISRIndex ++;
            gHwiCtrlProf.readCounterStart = CSL_armR5PmuReadCntr(CSL_ARM_R5_PMU_CYCLE_COUNTER_NUM);
        }
    }
    #endif
    
    /* IRQ handler starts execution in HwiP_irq_handler, defined in portASM.S
     * After some initial assembly logic it then branches to this function.
     * After exiting this function it does some more assembly including
     * doing task switch if requested.
     */
    void TEXT_HWI HwiP_irq_handler_c(void)
    {
        int32_t status;
        uint32_t intNum, priority;
    
        #if defined(SOC_AM273X)
        /* call dummy interrupt nesting at the beginning of IRQ handler */
        /* IRQs are already disabled by hardware when entering interrupt handler */
        dummyIrqNest();
        #endif
    
        #ifndef HWIP_VIM_VIC_ENABLE
    
        /* Read to force prioritization logic to take effect */
        HwiP_getIRQVecAddr();
        #endif
    
        status = HwiP_getIRQ(&intNum, &priority);
        if(status==SystemP_SUCCESS)
        {
            /* Store the current active interrupt priority in software,
            *  This is required for usecases like `vPortValidateInterruptPriority`.
             * `oldPriority` will be used to restore upon exiting from this handler. */
            uint32_t oldPriority = HwiP_updateActivePrioritySW(priority);
            
            #if (configUSE_INTERRUPT_PRIORITY_BASED_CRITICAL_SECTIONS==1)
            uint32_t priMaskKey;
            #endif
    
            #ifdef INTR_PROF
            if(gHwiCtrlProf.profileIntr == 1)
            {
                HwiP_irq_profile_c(intNum);
            }
            #endif
    
            uint32_t isPulse = HwiP_isPulse(intNum);
            HwiP_FxnCallback isr;
            void *args;
    
            if(isPulse != 0U)
            {
                HwiP_clearInt(intNum);
            }
    
            isr = gHwiCtrl.isr[intNum];
            args = gHwiCtrl.isrArgs[intNum];
    
            #if (configUSE_INTERRUPT_PRIORITY_BASED_CRITICAL_SECTIONS==1)
            priMaskKey = HwiP_setVimIrqPriMaskAtomic(priority);
            #endif
    
            #ifdef HWIP_NESTED_INTERRUPTS_IRQ_ENABLE
            /* allow nesting of interrupts */
            HwiP_enable();
            #endif
    
            if(isr!=NULL)
            {
                isr(args);
            }
    
            /* disallow nesting of interrupts */
            (void)HwiP_disable();
    
            if(isPulse == 0U)
            {
                HwiP_clearInt(intNum);
            }
    
            #if (configUSE_INTERRUPT_PRIORITY_BASED_CRITICAL_SECTIONS==1)
            /* Note: Restore the priority mask only after clearing the interrupt. 
             *       Else VIM would fire this again. */
            HwiP_restoreVimIrqPriMask(priMaskKey);
            #endif
            
            HwiP_ackIRQ(intNum);
    
            #ifdef INTR_PROF
            if(gHwiCtrlProf.profileIntr == 1)
            {
                HwiP_irq_profile_c(intNum);
            }
            #endif
    
            HwiP_restoreActivePrioritySW(oldPriority);
        }
        else
        {
            /* spurious interrupt */
            gHwiCtrl.spuriousIRQCount++;
            HwiP_ackIRQ(0);
        }
    }
    #if defined (__ICCARM__)
    void TEXT_HWI HwiP_fiq_handler(void)
    #else
    /* FIQ body, called from the naked HwiP_fiq_handler below as a normal AAPCS function */
    void TEXT_HWI HwiP_fiq_handler_c(void)
    #endif
    {
        int32_t status;
        uint32_t intNum;
    
        #if defined(HWIP_FPU_CONTEXT_SAVE_RESTORE_ENABLE) && defined(__ICCARM__)
        Hwip_save_fpu_context();
        #endif
    
        /* Read to force prioritization logic to take effect */
        gdummy = HwiP_getFIQVecAddr();
    
        status = HwiP_getFIQ(&intNum);
        if(status==SystemP_SUCCESS)
        {
            uint32_t isPulse = HwiP_isPulse(intNum);
            HwiP_FxnCallback isr;
            void *args;
    
            if(isPulse != 0U)
            {
                HwiP_clearInt(intNum);
            }
    
            isr = gHwiCtrl.isr[intNum];
            args = gHwiCtrl.isrArgs[intNum];
    
            #if 0   /* FIQ interrupt nesting not supported */
            /* allow nesting of interrupts */
            HwiP_enableFIQ();
            #endif
    
            if(isr!=NULL)
            {
                isr(args);
            }
    
            /* disallow nesting of interrupts */
            (void)HwiP_disableFIQ();
    
            if(isPulse == 0U)
            {
                HwiP_clearInt(intNum);
            }
            HwiP_ackFIQ(intNum);
        }
        else
        {
            /* spurious interrupt */
            gHwiCtrl.spuriousFIQCount++;
            HwiP_ackFIQ(0);
        }
    
        #if defined(HWIP_FPU_CONTEXT_SAVE_RESTORE_ENABLE) && defined(__ICCARM__)
        Hwip_restore_fpu_context();
        #endif
    }
    
    #if !defined (__ICCARM__)
    /* The FPU context must be saved/restored outside of any compiler generated frame.
     * Pushing from inline asm inside a C handler moves SP under the compiler, whose
     * SP relative locals then overwrite the saved context.
     * This naked wrapper saves r0-r5, lr, FPSCR and d0-d15 (s0-s31 alias d0-d15),
     * calls HwiP_fiq_handler_c() as a normal C function and returns from FIQ. */
    void TEXT_HWI __attribute__((naked)) HwiP_fiq_handler(void)
    {
        __asm__ __volatile__ (
            "push   {r0-r5, lr}          \n\t"  /* r8-r12 are banked in FIQ mode */
            "mov    r5, sp               \n\t"  /* remember original SP */
            "mov    r4, sp               \n\t"
            "bic    r4, r4, #7           \n\t"  /* 8 byte align SP for AAPCS */
            "mov    sp, r4               \n\t"
            "vmrs   r0, fpscr            \n\t"
            "vpush  {d0-d15}             \n\t"
            "push   {r0, r1}             \n\t"  /* 2 regs keeps SP 8 byte aligned */
            "bl     HwiP_fiq_handler_c   \n\t"
            "pop    {r0, r1}             \n\t"
            "vpop   {d0-d15}             \n\t"
            "vmsr   fpscr, r0            \n\t"
            "mov    sp, r5               \n\t"
            "pop    {r0-r5, lr}          \n\t"
            "subs   pc, lr, #4           \n\t"
        );
    }
    #endif
    
    #if defined (__ICCARM__)
    void TEXT_HWI HwiP_reserved_handler(void)
    #else
    void TEXT_HWI __attribute__((interrupt("UNDEF"))) HwiP_reserved_handler(void)
    #endif
    {
        volatile uint32_t loop = 1;
        while(loop != 0U) { ; }
    
    }
    
    /* Undefined handler starts execution in HwiP_undefined_handler, defined in
     * HwiP_armv7r_handlers_freertos_asm.S
     * After some initial assembly logic it then branches to this function.
     * After exiting this function it does some more assembly before exiting
     */
    void TEXT_HWI HwiP_undefined_handler_c(volatile uint32_t LR)
    {
        typedef struct {
            uint32_t SPSR;
            /* DFSR register */
            uint32_t LR;
            /* Instruction causing the exception*/
        }UNDEF_REG;
    
        UNDEF_REG abort_regs;
        abort_regs.SPSR = GET_SPSR();
        abort_regs.LR   = LR;
    
        HwiP_user_undefined_handler_c(abort_regs.LR, abort_regs.SPSR);
    }
    
    /* Prefetch abort handler starts execution in HwiP_prefetch_abort_handler, defined in
     * HwiP_armv7r_handlers_freertos_asm.S
     * After some initial assembly logic it then branches to this function.
     * After exiting this function it does some more assembly before exiting
     */
    void TEXT_HWI HwiP_prefetch_abort_handler_c(volatile uint32_t LR)
    {
        typedef struct {
            uint32_t IFSR;
            /* IFSR register */
            uint32_t AIFSR;
            /* AIFSR register */
            uint32_t IFAR;
            /* IFAR register */
            uint32_t LR;
            /* Instruction causing the exception*/
            uint32_t SPSR;
            /* SPSR register*/
        }PREFETCH_ABORT_REG;
    
        PREFETCH_ABORT_REG abort_regs;
    
        /*Extract register values through functions coded in ASM*/
        abort_regs.AIFSR = GET_AIFSR();
        abort_regs.IFAR  = GET_IFAR();
        abort_regs.IFSR  = GET_IFSR();
        abort_regs.LR    = LR;
        abort_regs.SPSR  = GET_SPSR();
    
        /*Extract contents of IFSR register
        1. status: indicates the type of fault generated
        2. sd: distinguishes between an AXI Decode or Slave error on an external abort.
        This bit is only valid for external aborts. For all other aborts types of abort,
        this bit is set to zero*/
        IFSR     ifsr;
        uint32_t ifsr_value = abort_regs.IFSR;
    
        ifsr.status = ((ifsr_value & 0xF) | (((ifsr_value >> 10) & 0x1) << 4));
        ifsr.sd     = ((ifsr_value >> 12) & 0x1);
    
        /*Extract contents of AIFSR register
        1. index: returns the index value for the access giving the error
        2. side_ext: value returned in this field indicates the source of the error
        3. recoverable_error:  value returned in this field indicates if the error is recoverable
            (0=Unrecoverable error, 1=Recoverable Error)
        4. cacheway: value returned in this field indicates the cache way or ways in which the error occurred*/
        AIFSR    aifsr;
        uint32_t aifsr_value = abort_regs.AIFSR;
    
        aifsr.index             = ((aifsr_value >> 5) & 0x1FF);
        aifsr.side_ext          = (((aifsr_value >> 22) & 0x3) | (((aifsr_value >> 20) & 0x1) << 2));
        aifsr.recoverable_error = ((aifsr_value >> 21) & 0x1);
        aifsr.cacheway          = ((aifsr_value >> 24) & 0xF);
    
        HwiP_user_prefetch_abort_handler_c(ifsr, aifsr, abort_regs.IFAR, abort_regs.LR, abort_regs.SPSR);
    }
    
    /* Data abort handler starts execution in HwiP_data_abort_handler, defined in
     * HwiP_armv7r_handlers_freertos_asm.S
     * After some initial assembly logic it then branches to this function.
     * After exiting this function it does some more assembly before exiting
     */
    void TEXT_HWI HwiP_data_abort_handler_c(volatile uint32_t LR)
    {
         typedef struct {
            uint32_t DFSR;
            /* DFSR register */
            uint32_t ADFSR;
            /* ADFSR register */
            uint32_t DFAR;
            /* DFAR register */
            uint32_t LR;
            /* Instruction causing the exception*/
            uint32_t SPSR;
            /* SPSR register*/
        }DATA_ABORT_REG;
    
    
        /*Extract register values through functions coded in ASM*/
        DATA_ABORT_REG abort_regs;
        abort_regs.ADFSR = GET_ADFSR();
        abort_regs.DFAR  = GET_DFAR();
        abort_regs.DFSR  = GET_DFSR();
        abort_regs.LR    = LR;
        abort_regs.SPSR  = GET_SPSR();
    
        /*Extract contents of DFSR register
        1. status: indicates the type of fault generated
        2. sd: distinguishes between an AXI Decode or Slave error on an external abort.
        This bit is only valid for external aborts. For all other aborts types of abort,
        this bit is set to zero
        3. rw:  Indicates whether a read or write access caused an abort
            (0=read abort; 1=write abort)*/
        DFSR dfsr;
        uint32_t dfsr_value = abort_regs.DFSR;
    
        dfsr.status = ((dfsr_value & 0xF) | (((dfsr_value >> 10) & 0x1) << 4));
        dfsr.rw     = ((dfsr_value >> 11) & 0x1);
        dfsr.sd     = ((dfsr_value >> 12) & 0x1);
    
        /*Extract contents of ADFSR register
        1. index: returns the index value for the access giving the error
        2. side_ext: value returned in this field indicates the source of the error
        3. recoverable_error:  value returned in this field indicates if the error is recoverable
            (0=Unrecoverable error, 1=Recoverable Error)
        4. cacheway: value returned in this field indicates the cache way or ways in which the error occurred*/
        ADFSR adfsr;
        uint32_t adfsr_value = abort_regs.ADFSR; 
    
        adfsr.index             = ((adfsr_value >> 5) & 0x1FF);
        adfsr.side_ext          = (((adfsr_value >> 22) & 0x3) | (((adfsr_value >> 20) & 0x1) << 2));
        adfsr.recoverable_error = ((adfsr_value >> 21) & 0x1);
        adfsr.cacheway          = ((adfsr_value >> 24) & 0xF);
    
        HwiP_user_data_abort_handler_c(dfsr, adfsr, abort_regs.DFAR, abort_regs.LR, abort_regs.SPSR);
    }
    
    void TEXT_HWI WEAK HwiP_user_undefined_handler_c(volatile uint32_t LR,volatile uint32_t SPSR)
    {
        volatile uint32_t loop = 1U;
        while(loop != 0U){ ; }
    }
    
    void TEXT_HWI WEAK HwiP_user_prefetch_abort_handler_c(IFSR ifsr, AIFSR aifsr, volatile uint32_t IFAR, 
                                                          volatile uint32_t LR,volatile uint32_t SPSR)
    {
        volatile uint32_t loop = 1U;
        while(loop != 0U){ ; }
    }
    
    void TEXT_HWI WEAK HwiP_user_data_abort_handler_c(DFSR dfsr, ADFSR adfsr, volatile uint32_t DFAR, 
                                                      volatile uint32_t LR,volatile uint32_t SPSR)
    {
        volatile uint32_t loop = 1U;
            while(loop != 0U){ ; }
    }
    

    gmake -sj -f makefile.am263px freertos_r5f.ti-arm-clang PROFILE=debug

    NoRTOS:

    /*
     *  Copyright (C) 2018-2023 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <kernel/dpl/HwiP.h>
    #include <kernel/nortos/dpl/r5/HwiP_armv7r_vim.h>
    #include <drivers/hw_include/csl_types.h>
    #include <kernel/dpl/DebugP.h>
    
    #define TEXT_HWI    __attribute__((section(".text.hwi")))
    #define WEAK        __attribute__((weak))
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #if defined(SOC_AM273X)
    /*back-2-back nesting issue */
    static void Hwip_dataAndInstructionBarrier(void)
    {
    #if defined(__ICCARM__)
        __ISB();
        __DSB();
    #else
        __asm__ __volatile__ (" isb"   "\n\t": : : "memory");
        __asm__ __volatile__ (" dsb"   "\n\t": : : "memory");
    #endif
    }
    #endif
    
    #if defined (__ICCARM__)
    void TEXT_HWI HwiP_reserved_handler(void);
    void TEXT_HWI HwiP_fiq_handler(void);
    void TEXT_HWI HwiP_svc_handler(void);
    #else
    /* Following handlers are set directly in vector table, hence use interrupt attribute.
     * HwiP_fiq_handler is a naked asm wrapper (saves FPU context) around HwiP_fiq_handler_c */
    void TEXT_HWI __attribute__((interrupt("UNDEF"))) HwiP_reserved_handler(void);
    void TEXT_HWI __attribute__((naked)) HwiP_fiq_handler(void);
    void TEXT_HWI HwiP_fiq_handler_c(void);
    void TEXT_HWI __attribute__((interrupt("SWI"))) HwiP_svc_handler(void);
    #endif
    
    /** Following handlers starts in assembly and switch to C implementation. 
     * Hence DON'T use interrupt attribute. Else it will result in re-entry */ 
    void TEXT_HWI HwiP_irq_handler_c(void);
    void TEXT_HWI HwiP_data_abort_handler_c(volatile uint32_t LR);
    void TEXT_HWI HwiP_prefetch_abort_handler_c(volatile uint32_t LR);
    void TEXT_HWI HwiP_undefined_handler_c(volatile uint32_t LR);
    /* Use weak attribute with user handler so that applications can override with its own implementation */
    void TEXT_HWI WEAK HwiP_user_data_abort_handler_c(DFSR dfsr, ADFSR adfsr, volatile uint32_t DFAR, 
                                                      volatile uint32_t LR,volatile uint32_t SPSR);
    void TEXT_HWI WEAK HwiP_user_prefetch_abort_handler_c(IFSR ifsr, AIFSR aifsr, volatile uint32_t IFAR, 
                                                          volatile uint32_t LR,volatile uint32_t SPSR);
    void TEXT_HWI WEAK HwiP_user_undefined_handler_c(volatile uint32_t LR, volatile uint32_t SPSR);
    
    uint32_t GET_DFSR(void);
    uint32_t GET_ADFSR(void);
    uint32_t GET_DFAR(void);
    uint32_t GET_IFSR(void);
    uint32_t GET_AIFSR(void);
    uint32_t GET_IFAR(void);
    uint32_t GET_SPSR(void);
    uint32_t GET_LR(void);
    
    #ifdef __cplusplus
    }
    #endif
    
    #if defined(SOC_AM273X)
    /* back-2-back nesting issue (AM273x errata i2162 workaround) */
    /* Get the status of a specific interrupt in VIM_RAW register */
    static uint32_t HWI_SECTION HwiP_get(uint32_t intNum)
    {
        volatile uint32_t *addr;
        uint32_t bitPos;
        uint32_t val;
    
        addr = (volatile uint32_t *)(gHwiConfig.intcBaseAddr + VIM_RAW(intNum));
        bitPos = VIM_BIT_POS(intNum);
    
        val = (*addr) & ((uint32_t)0x1 << bitPos);
    
        /*
         * Add delay to ensure posted interrupt is triggered before function returns.
         */
        Hwip_dataAndInstructionBarrier();
    
        return val;
    }
    
    /* Post and clear the dummy interrupt */
    static void HWI_SECTION dummyIrqNest(void)
    {
        /* Set the interrupt flag of DUMMY IRQ */
        HwiP_post(HWIP_DUMMY_INTERRUPT_NUM);
        /* Make sure the dummy interrupt has been set */
        while(HwiP_get(HWIP_DUMMY_INTERRUPT_NUM) == 0U)
        {
            /* Do nothing */
        }
        /* Get the interrupt vector */
        (void)HwiP_getIRQVecAddr();
        /* Clear the interrupt flag of DUMMY IRQ */
        HwiP_clearInt(HWIP_DUMMY_INTERRUPT_NUM);
        /* Wait until it is actually been cleared */
        while(HwiP_get(HWIP_DUMMY_INTERRUPT_NUM) != 0U)
        {
            /* Do nothing */
        }
        /* Acknowledge DUMMY IRQ */
        HwiP_ackIRQ(HWIP_DUMMY_INTERRUPT_NUM);
    }
    #endif
    
    /* Save FPU context, used in FIQ Handler */
    static inline  void Hwip_save_fpu_context(void)
    {
    #if defined (__ICCARM__)
    __asm volatile( "FMRX  R0, FPSCR"  "\n\t": : : "memory");
    __asm volatile( "VPUSH {D0-D15}"  "\n\t": : : "memory");
    __asm volatile( "PUSH  {R0}"  "\n\t": : : "memory");
    #else
        __asm__ __volatile__ ( "FMRX  R0, FPSCR"  "\n\t": : : "memory");
        __asm__ __volatile__ ( "VPUSH {D0-D15}"  "\n\t": : : "memory");
        __asm__ __volatile__ ( "PUSH  {R0}"  "\n\t": : : "memory");
    #endif
    }
    
    /* Restore FPU context, used in FIQ Handler */
    static inline  void Hwip_restore_fpu_context(void)
    {
    #if defined (__ICCARM__)
        __asm volatile ( "POP   {R0}"  "\n\t": : : "memory");
        __asm volatile ( "VPOP  {D0-D15}"  "\n\t": : : "memory");
        __asm volatile ( "VMSR  FPSCR, R0"  "\n\t": : : "memory");
    #else
        __asm__ __volatile__ ( "POP   {R0}"  "\n\t": : : "memory");
        __asm__ __volatile__ ( "VPOP  {D0-D15}"  "\n\t": : : "memory");
        __asm__ __volatile__ ( "VMSR  FPSCR, R0"  "\n\t": : : "memory");
    #endif
    }
    
    
    /* IRQ handler starts execution in HwiP_irq_handler, defined in
     * HwiP_armv7r_handlers_nortos_asm.S
     * After some initial assembly logic it then branches to this function.
     * After exiting this function it does some more assembly before exiting
     */
    void TEXT_HWI HwiP_irq_handler_c(void)
    {
        int32_t status;
        uint32_t intNum, priority;
    
        #if defined(SOC_AM273X)
        /* call dummy interrupt nesting at the beginning of IRQ handler */
        /* IRQs are already disabled by hardware when entering interrupt handler */
        dummyIrqNest();
        #endif
    
        #ifndef HWIP_VIM_VIC_ENABLE
    
        /* Read to force prioritization logic to take effect, in non-VIC mode */
        HwiP_getIRQVecAddr();
        #endif
    
        status = HwiP_getIRQ(&intNum, &priority);
        if(status==SystemP_SUCCESS)
        {
            /* Store the current active interrupt priority in software for any later use.
             * `oldPriority` will be used to restore upon exiting from this handler. */
            uint32_t oldPriority = HwiP_updateActivePrioritySW(priority);
    
            uint32_t isPulse = HwiP_isPulse(intNum);
            HwiP_FxnCallback isr;
            void *args;
    
            #ifdef HWIP_USE_INTERRUPT_PRIORITY_BASED_CRITICAL_SECTIONS
            uint32_t priMaskKey;
            #endif
    
            if(isPulse!=0U)
            {
                HwiP_clearInt(intNum);
            }
    
            isr = gHwiCtrl.isr[intNum];
            args = gHwiCtrl.isrArgs[intNum];
    
            #ifdef HWIP_USE_INTERRUPT_PRIORITY_BASED_CRITICAL_SECTIONS
            priMaskKey = HwiP_setVimIrqPriMaskAtomic(priority);
            #endif
    
            #ifdef HWIP_NESTED_INTERRUPTS_IRQ_ENABLE
            /* allow nesting of interrupts */
            HwiP_enable();
            #endif
    
            if(isr!=NULL)
            {
                isr(args);
            }
    
            /* disallow nesting of interrupts */
            (void) HwiP_disable();
    
            if(isPulse==0U)
            {
                HwiP_clearInt(intNum);
            }
            
            #ifdef HWIP_USE_INTERRUPT_PRIORITY_BASED_CRITICAL_SECTIONS
            /* Note: Restore the priority mask only after clearing the interrupt. 
             *       Else VIM would fire this again. */
            HwiP_restoreVimIrqPriMask(priMaskKey);
            #endif
    
            HwiP_ackIRQ(intNum);
    
            HwiP_restoreActivePrioritySW(oldPriority);
        }
        else
        {
            /* spurious interrupt */
            gHwiCtrl.spuriousIRQCount++;
            HwiP_ackIRQ(0);
        }
    }
    #if defined (__ICCARM__)
    void TEXT_HWI HwiP_fiq_handler(void)
    #else
    /* FIQ body, called from the naked HwiP_fiq_handler below as a normal AAPCS function */
    void TEXT_HWI HwiP_fiq_handler_c(void)
    #endif
    {
        int32_t status;
        uint32_t intNum;
        volatile uint32_t dummy;
    
        #if defined(HWIP_FPU_CONTEXT_SAVE_RESTORE_ENABLE) && defined(__ICCARM__)
        Hwip_save_fpu_context();
        #endif
    
        /* Read to force prioritization logic to take effect */
        dummy = HwiP_getFIQVecAddr();
        (void)dummy;
    
        status = HwiP_getFIQ(&intNum);
        if(status==SystemP_SUCCESS)
        {
            uint32_t isPulse = HwiP_isPulse(intNum);
            HwiP_FxnCallback isr;
            void *args;
    
            if(isPulse!=0U)
            {
                HwiP_clearInt(intNum);
            }
    
            isr = gHwiCtrl.isr[intNum];
            args = gHwiCtrl.isrArgs[intNum];
    
            #if 0   /* FIQ interrupt nesting not supported */
            /* allow nesting of interrupts */
            HwiP_enableFIQ();
            #endif
    
            if(isr!=NULL)
            {
                isr(args);
            }
    
            /* disallow nesting of interrupts */
            (void) HwiP_disableFIQ();
    
            if(isPulse==0U)
            {
                HwiP_clearInt(intNum);
            }
            HwiP_ackFIQ(intNum);
        }
        else
        {
            /* spurious interrupt */
            gHwiCtrl.spuriousFIQCount++;
            HwiP_ackFIQ(0);
        }
    
        #if defined(HWIP_FPU_CONTEXT_SAVE_RESTORE_ENABLE) && defined(__ICCARM__)
        Hwip_restore_fpu_context();
        #endif
    }
    
    #if !defined (__ICCARM__)
    /* The FPU context must be saved/restored outside of any compiler generated frame.
     * Pushing from inline asm inside a C handler moves SP under the compiler, whose
     * SP relative locals then overwrite the saved context.
     * This naked wrapper saves r0-r5, lr, FPSCR and d0-d15 (s0-s31 alias d0-d15),
     * calls HwiP_fiq_handler_c() as a normal C function and returns from FIQ. */
    void TEXT_HWI __attribute__((naked)) HwiP_fiq_handler(void)
    {
        __asm__ __volatile__ (
            "push   {r0-r5, lr}          \n\t"  /* r8-r12 are banked in FIQ mode */
            "mov    r5, sp               \n\t"  /* remember original SP */
            "mov    r4, sp               \n\t"
            "bic    r4, r4, #7           \n\t"  /* 8 byte align SP for AAPCS */
            "mov    sp, r4               \n\t"
            "vmrs   r0, fpscr            \n\t"
            "vpush  {d0-d15}             \n\t"
            "push   {r0, r1}             \n\t"  /* 2 regs keeps SP 8 byte aligned */
            "bl     HwiP_fiq_handler_c   \n\t"
            "pop    {r0, r1}             \n\t"
            "vpop   {d0-d15}             \n\t"
            "vmsr   fpscr, r0            \n\t"
            "mov    sp, r5               \n\t"
            "pop    {r0-r5, lr}          \n\t"
            "subs   pc, lr, #4           \n\t"
        );
    }
    #endif
    
    #if defined (__ICCARM__)
    void TEXT_HWI HwiP_reserved_handler(void)
    #else
    void TEXT_HWI __attribute__((interrupt("UNDEF"))) HwiP_reserved_handler(void)
    #endif
    {
        volatile uint32_t loop = 1;
        while(loop!=0U)
        {
            ;
        }
    }
    
    /* Undefined handler starts execution in HwiP_undefined_handler, defined in
     * HwiP_armv7r_handlers_nortos_asm.S
     * After some initial assembly logic it then branches to this function.
     * After exiting this function it does some more assembly before exiting
     */
    void TEXT_HWI HwiP_undefined_handler_c(volatile uint32_t LR)
    {
    
        typedef struct {
            uint32_t SPSR;
            /* DFSR register */
            uint32_t LR;
            /* Instruction causing the exception*/
        }UNDEF_REG;
    
        UNDEF_REG abort_regs;
        abort_regs.SPSR = GET_SPSR();
        abort_regs.LR   = LR;
    
        HwiP_user_undefined_handler_c(abort_regs.LR, abort_regs.SPSR);
    
    }
    #if defined (__ICCARM__)
    void TEXT_HWI HwiP_svc_handler(void)
    #else
    void __attribute__((interrupt("SWI"), section(".text.hwi"))) HwiP_svc_handler(void)
    #endif
    {
        volatile uint32_t loop = 1;
        while(loop!=0U)
        {
            ;
        }
    
    }
    
    /* Prefetch abort handler starts execution in HwiP_prefetch_abort_handler, defined in
     * HwiP_armv7r_handlers_nortos_asm.S
     * After some initial assembly logic it then branches to this function.
     * After exiting this function it does some more assembly before exiting
     */
    void TEXT_HWI HwiP_prefetch_abort_handler_c(volatile uint32_t LR)
    {
    
        typedef struct {
            uint32_t IFSR;
            /* IFSR register */
            uint32_t AIFSR;
            /* AIFSR register */
            uint32_t IFAR;
            /* IFAR register */
            uint32_t LR;
            /* Instruction causing the exception*/
            uint32_t SPSR;
            /* SPSR register*/
        }PREFETCH_ABORT_REG;
    
        PREFETCH_ABORT_REG abort_regs;
    
        /*Extract register values through functions coded in ASM*/
        abort_regs.AIFSR = GET_AIFSR();
        abort_regs.IFAR  = GET_IFAR();
        abort_regs.IFSR  = GET_IFSR();
        abort_regs.LR    = LR;
        abort_regs.SPSR  = GET_SPSR();
    
        /*Extract contents of IFSR register
        1. status: indicates the type of fault generated
        2. sd: distinguishes between an AXI Decode or Slave error on an external abort.
        This bit is only valid for external aborts. For all other aborts types of abort,
        this bit is set to zero*/
        IFSR     ifsr;
        uint32_t ifsr_value = abort_regs.IFSR;
    
        ifsr.status = ((ifsr_value & 0xF) | (((ifsr_value >> 10) & 0x1) << 4));
        ifsr.sd     = ((ifsr_value >> 12) & 0x1);
    
        /*Extract contents of AIFSR register
        1. index: returns the index value for the access giving the error
        2. side_ext: value returned in this field indicates the source of the error
        3. recoverable_error:  value returned in this field indicates if the error is recoverable
            (0=Unrecoverable error, 1=Recoverable Error)
        4. cacheway: value returned in this field indicates the cache way or ways in which the error occurred*/
        AIFSR    aifsr;
        uint32_t aifsr_value = abort_regs.AIFSR;
    
        aifsr.index             = ((aifsr_value >> 5) & 0x1FF);
        aifsr.side_ext          = (((aifsr_value >> 22) & 0x3) | (((aifsr_value >> 20) & 0x1) << 2));
        aifsr.recoverable_error = ((aifsr_value >> 21) & 0x1);
        aifsr.cacheway          = ((aifsr_value >> 24) & 0xF);
    
        HwiP_user_prefetch_abort_handler_c(ifsr, aifsr, abort_regs.IFAR, abort_regs.LR, abort_regs.SPSR);
    
    }
    
    /* Data abort handler starts execution in HwiP_data_abort_handler, defined in
     * HwiP_armv7r_handlers_nortos_asm.S
     * After some initial assembly logic it then branches to this function.
     * After exiting this function it does some more assembly before exiting
     */
    void TEXT_HWI HwiP_data_abort_handler_c(volatile uint32_t LR)
    {
    
        typedef struct {
            uint32_t DFSR;
            /* DFSR register */
            uint32_t ADFSR;
            /* ADFSR register */
            uint32_t DFAR;
            /* DFAR register */
            uint32_t LR;
            /* Instruction causing the exception*/
            uint32_t SPSR;
            /* SPSR register*/
        }DATA_ABORT_REG;
    
        /*Extract register values through functions coded in ASM*/
        DATA_ABORT_REG abort_regs;
        abort_regs.ADFSR = GET_ADFSR();
        abort_regs.DFAR  = GET_DFAR();
        abort_regs.DFSR  = GET_DFSR();
        abort_regs.LR    = LR;
        abort_regs.SPSR  = GET_SPSR();
    
        /*Extract contents of DFSR register
        1. status: indicates the type of fault generated
        2. sd: distinguishes between an AXI Decode or Slave error on an external abort.
        This bit is only valid for external aborts. For all other aborts types of abort,
        this bit is set to zero
        3. rw:  Indicates whether a read or write access caused an abort
            (0=read abort; 1=write abort)*/
        DFSR dfsr;
        uint32_t dfsr_value = abort_regs.DFSR;
    
        dfsr.status = ((dfsr_value & 0xF) | (((dfsr_value >> 10) & 0x1) << 4));
        dfsr.rw     = ((dfsr_value >> 11) & 0x1);
        dfsr.sd     = ((dfsr_value >> 12) & 0x1);
    
        /*Extract contents of ADFSR register
        1. index: returns the index value for the access giving the error
        2. side_ext: value returned in this field indicates the source of the error
        3. recoverable_error:  value returned in this field indicates if the error is recoverable
            (0=Unrecoverable error, 1=Recoverable Error)
        4. cacheway: value returned in this field indicates the cache way or ways in which the error occurred*/
        ADFSR adfsr;
        uint32_t adfsr_value = abort_regs.ADFSR; 
    
        adfsr.index             = ((adfsr_value >> 5) & 0x1FF);
        adfsr.side_ext          = (((adfsr_value >> 22) & 0x3) | (((adfsr_value >> 20) & 0x1) << 2));
        adfsr.recoverable_error = ((adfsr_value >> 21) & 0x1);
        adfsr.cacheway          = ((adfsr_value >> 24) & 0xF);
    
        HwiP_user_data_abort_handler_c(dfsr, adfsr, abort_regs.DFAR, abort_regs.LR, abort_regs.SPSR);
    
    }
    
    void TEXT_HWI WEAK HwiP_user_undefined_handler_c(volatile uint32_t LR, volatile uint32_t SPSR)
    {
        volatile uint32_t loop = 1U;
        while(loop != 0U){ ; }
    }
    
    void TEXT_HWI WEAK HwiP_user_prefetch_abort_handler_c(IFSR ifsr, AIFSR aifsr, volatile uint32_t IFAR, 
                                                          volatile uint32_t LR,volatile uint32_t SPSR)
    {
        volatile uint32_t loop = 1U;
        while(loop != 0U){ ; }
    }
    
    void TEXT_HWI WEAK HwiP_user_data_abort_handler_c(DFSR dfsr, ADFSR adfsr, volatile uint32_t DFAR, 
                                                      volatile uint32_t LR,volatile uint32_t SPSR)
    {
        volatile uint32_t loop = 1U;
        while(loop != 0U){ ; }
    }
    

    gmake -sj -f makefile.am263px nortos_r5f.ti-arm-clang PROFILE=debug

    In above files, The FIQ handler's FPU save was done in inline asm that moved sp under the compiler, so its sp-relative locals overwrote the saved d0-d15/FPSCR. In the nortos and FreeRTOS handlers, HwiP_fiq_handler is now a naked asm wrapper that saves r0-r5, lr, FPSCR and d0-d15, calls the old body as HwiP_fiq_handler_c(), then restores and returns.

    Regards,
    Shaunak

  • Hi Shaunak,

    I tried the FreeRTOS handlers file you provided and it seems to fix the issue with the exact same build settings, the float variables are not corrupted anymore due the FIQ. I am not sure if I still need to answer any of the questions you have asked

    I would hope that the fix would be integrated at some point in the SDK release so we don't have to use a modified version of it.

    Thank you very much for your help, very much appreciated

    Kind regards,

    Khalil

  • Hi Khalil,

    Thanks for confirming. Let me check internally how we should integrate it for our next SDK release.

    Regards,
    Shaunak

  • Hi Shaunak,

    Sorry I didn't detect this earlier but it seems that the new code is somehow interfering with the IRQs, I guess it's corrupting the stack which leads to a data-abort event.

    I am using the RP-Messages notify callback for the inter-processor communication which seems to be a long ISR that gets corrupted by the FIQ.

    This is what I get in the HwiP_user_data_abort_handler_c handler

  • Hi Khalil,

    Please allow me some time to look into this.

    Regards,
    Shaunak

  • Hi Khalil,

    The team is working on it. There has been a JIRA raised for this: https://jira.itg.ti.com/browse/MCUSDK-16027 (internal tracking link)

    Meanwhile, can you share a test-case with us with which we can reproduce this on our end.

    Regards,
    Shaunak

  • Hi Shaunak,

    I am really sorry but it seems that the last issue was due to the fact that I didn't increase the stack size of the FIQ that was overflowing into the IRQ stack which was leading to the abort error.

    It was difficult to catch as it only occurs when the FIQ interrupts an IRQ while the latter is deep in its stack (IPC interrupt in this instance)

    Thank you very much for your support and apologies again for the time wasted for this