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.
The attached project is a HALCoGen based project for a RM48L952, which uses an RTI interrupt. The source code was created by HALCoGen specifying "TI tools" and there are two build configurations:
a. Debug_TI_ARM_CGT using TI ARM v20.2.5
b. Debug_TI_CLANG using TI ARM Clang v1.3.0
After adding the Debug_TI_CLANG build configuration made a few adjustments to the source code and linker command file to allow to compile and run for both compilers, keeping the modifications within the HALCoGen /* USER CODE */ blocks so the modifications are preserved if HALCoGen is used to re-generate the driver code.
The source/rti.c source file contains the following HALCoGen created rtiCompare0Interrupt() interrupt handler which calls a user supplied handler:
/* USER CODE BEGIN (73) */ /* Work-around for TI ARM CLANG not understanding CODE_STATE and INTERRUPT pragmas */ void rtiCompare0Interrupt(void) __attribute__((target("arm"))) __attribute__((interrupt("IRQ"))); /* USER CODE END */ /** @fn void rtiCompare0Interrupt(void) * @brief RTI1 Compare 0 Interrupt Handler * * RTI1 Compare 0 interrupt handler * */ #pragma CODE_STATE(rtiCompare0Interrupt, 32) #pragma INTERRUPT(rtiCompare0Interrupt, IRQ) /* SourceId : RTI_SourceId_022 */ /* DesignId : RTI_DesignId_022 */ /* Requirements : HL_SR95 */ void rtiCompare0Interrupt(void) { /* USER CODE BEGIN (74) */ /* USER CODE END */ rtiREG1->INTFLAG = 1U; rtiNotification(rtiNOTIFICATION_COMPARE0); /* USER CODE BEGIN (75) */ /* USER CODE END */ }
The TI ARM v20.2.5 compiler generates the following for rtiCompare0Interrupt() which preserves the floating point registers, presumably since the TI ARM v20.2.5 doesn't know if the called function may use floating point registers:
865 { rtiCompare0Interrupt(): 08001660: E92D500F push {r0, r1, r2, r3, r12, r14} 08001664: EEF8CA10 vmrs r12, fpexc 08001668: E92D1000 stmdb r13!, {r12} 0800166c: EEF1CA10 vmrs r12, fpscr 08001670: E92D1000 stmdb r13!, {r12} 08001674: ED2D0B10 vpush {d0, d1, d2, d3, d4, d5, d6, d7} 869 rtiREG1->INTFLAG = 1U; 08001678: E30FCC88 movw r12, #0xfc88 0800167c: E34FCFFF movt r12, #0xffff 08001680: E3A00001 mov r0, #1 08001684: E58C0000 str r0, [r12] 870 rtiNotification(rtiNOTIFICATION_COMPARE0); 08001688: EBFFFF9C bl rtiNotification 0800168c: ECBD0B10 vpop {d0, d1, d2, d3, d4, d5, d6, d7} 08001690: E8BD1000 ldm r13!, {r12} 08001694: EEE1CA10 vmsr fpscr, r12 08001698: E8BD1000 ldm r13!, {r12} 0800169c: EEE8CA10 vmsr fpexc, r12 080016a0: E8BD500F pop {r0, r1, r2, r3, r12, r14} 080016a4: E25EF004 subs pc, r14, #4
Whereas the TI ARM Clang v1.3.0 compiler generates the following for rtiCompare0Interrupt() which doesn't preserve the floating point registers:
865 { rtiCompare0Interrupt(): 08001630: E92D5C0F push {r0, r1, r2, r3, r10, r11, r12, r14} 08001634: E28DB014 add r11, r13, #0x14 08001638: E7C2D01F bfc r13, #0, #3 0800163c: E30FEC88 movw r14, #0xfc88 08001640: E3A00001 mov r0, #1 08001644: E34FEFFF movt r14, #0xffff 869 rtiREG1->INTFLAG = 1U; 08001648: E58E0000 str r0, [r14] 870 rtiNotification(rtiNOTIFICATION_COMPARE0); 0800164c: E3A00001 mov r0, #1 08001650: EBFFFFAA bl rtiNotification 874 } 08001654: E24BD014 sub r13, r11, #0x14 08001658: E8BD5C0F pop {r0, r1, r2, r3, r10, r11, r12, r14} 0800165c: E25EF004 subs pc, r14, #4
The TI ARM Clang v1.3.0 compiler does produce a "call to function without interrupt attribute could clobber interruptee's VFP registers" warning for the call to rtiNotification() from rtiCompare0Interrupt():
Building file: "../source/rti.c" Invoking: Arm Compiler "C:/ti/ccs1030/ccs/tools/compiler/ti-cgt-armllvm_1.3.0-beta.1/bin/tiarmclang.exe" -c -march=armv7r -mcpu=cortex-r4 -mfloat-abi=hard -mfpu=vfpv3-d16 -mlittle-endian -marm -O2 -I"C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky" -I"C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky/include" -I"C:/ti/ccs1030/ccs/tools/compiler/ti-cgt-armllvm_1.3.0-beta.1/include" -D_INLINE -gdwarf-3 -Werror=ti-intrinsics -fno-short-wchar -fcommon -ffunction-sections -MMD -MP -MF"source/rti.d_raw" -MT"source/rti.o" -std=gnu90 -o"source/rti.o" "../source/rti.c" In file included from ../source/rti.c:54: In file included from C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky/include\rti.h:53: In file included from C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky/include/reg_rti.h:52: C:/Users/mr_halfword/E2E_example_projects/RM48L952_rtiblinky/include/sys_common.h:95:9: warning: __little_endian__ is a legacy TI macro that is not defined in clang compilers and will evaluate to 0, use '!defined(__ARM_BIG_ENDIAN)' instead [-Wti-macros] #ifndef __little_endian__ ^ ../source/rti.c:858:9: warning: pragma CODE_STATE is a legacy TI pragma and not supported in clang compilers. use '__attribute__((target("code_state")))' instead [-Wti-pragmas] #pragma CODE_STATE(rtiCompare0Interrupt, 32) ^ ../source/rti.c:859:9: warning: pragma INTERRUPT is a legacy TI pragma and not supported in clang compilers. use '__attribute__((interrupt("int_kind")))' instead [-Wti-pragmas] #pragma INTERRUPT(rtiCompare0Interrupt, IRQ) ^ ../source/rti.c:870:5: warning: call to function without interrupt attribute could clobber interruptee's VFP registers [-Wextra] rtiNotification(rtiNOTIFICATION_COMPARE0); ^ 4 warnings generated. Finished building: "../source/rti.c"
The warning suggests for safety the called rtiNotification() should be marked as an interrupt function. However, when attempted that with the following in include/rti.h the program no longer runs correctly:
/* USER CODE BEGIN (6) */ void rtiNotification(uint32 notification) __attribute((interrupt)); /* USER CODE END */
The reason is specifying the interrupt attribute for a function:
When compiling for an Arm Cortex-R processor, the compiler will generate code to preserve general purpose reguiters and a sequence of instructions to effect an appropriate exception return for the processor
When happened was that rtiCompare0Interrupt() and rtiNotification() were both marked as interrupt functions:
a. rtiCompare0Interrupt() was called from a IRQ.
b. rtiCompare0Interrupt() called rtiNotification().
c. When rtiNotification() attempted to return, since had been been marked as interrupt the compiler generated epilogue which attempted to perform an exception return the function was re-entered and the processor then spent all its time in the rtiNotification() function.
With the TI ARM Clang v1.3.0 compiler what is the correct way for an interrupt handler which calls other functions to preserve VFP registers when functions with unknown side-effects are called?
I found Warn when calling a non interrupt function from an interrupt on ARM which appears to be when the "call to function without interrupt attribute could clobber interruptee's VFP registers" warning was added to LLVM, but what is the correct way to get the same behavior as the TI ARM v20.2.5 and preserve the VFP registers (for safety) if an interrupt function calls other functions?
Also, the text of the "call to function without interrupt attribute could clobber interruptee's VFP registers" is a bit misleading since as adding an interrupt attribute to the called function can break the code.
In the tiarmclang documentation on pragmas and attributes it states ...
The tiarmclang compiler will not generate code to preserve FPU registers in a function marked with the interrupt attribute. If floating-point operations are required in the scope of an interrupt, then the FPU registers must be preserved manually.
Thanks and regards,
-George