SPRZ422K August 2014 – May 2024 TMS320F28374S , TMS320F28375S , TMS320F28375S-Q1 , TMS320F28376S , TMS320F28377S , TMS320F28377S-Q1 , TMS320F28378S , TMS320F28379S
FPU: LUF, LVF Flags are Invalid for the EINVF32 and EISQRTF32 Instructions
B, C
This advisory applies to the EINVF32 and EISQRTF32 instructions. The expected results for these instructions are correct; however, the underflow (LUF) and overflow (LVF) flags are not. These flags are invalid and should not be used.
The LUF and LVF flags are not accessible using C code, so the overall impact of this advisory is expected to be small. If the user chooses to use these flags (for example, when coding a time-critical algorithm) in assembly as part of a mixed C/ASM project, the user will need to disable interrupts around the assembly code using the flags, and also preserve the flags through any use of EINVF32 or EISQRTF32 instructions.
There is no workaround for using these flags in C code, and they should be considered invalid for the reasons presented under NOTES ON COMPILER AND TOOLS USAGE.
The workaround shown here provides a way to preserve the LVF, LUF flags across the use of EISQRTF32 and EINVF32 in assembly-only code.
Do not rely on the LUF and LVF flags to catch underflow/overflow conditions resulting from the EINVF32 and EISQRTF32 instructions. Instead, check the operands for the following conditions (in code) before using each instruction:
EINVF32 | Divide by 0 | |
EISQRTF32 | Divide by 0, Divide by a negative input |
Disregard the contents of the LUF and LVF flags by saving the flags to the stack before calling the instruction, and subsequently restoring the values of the flags once the instruction completes.
MOV32 *SP++,STF ; Save off current status flags
EISQRTF32/EINVF32 ; Execute operation
NOP ; Wait for operations to complete
MOV32 STF,*--SP ; Restore previous status flags
If the PIE interrupts are tied to the LUF and LVF flags, disable the interrupts (at the PIE) before using either the EINVF32 or EISQRTF32 instruction. Check to see if the LUF and LVF flags are set; if they are, a variable can be set to indicate that a false LUF/LVF condition is detected. Clear the flags in the STF (FPU status flag) before re-enabling the interrupts.
Once the interrupts are reenabled at the PIE, the interrupt may occur (if the LUF/LVF interrupt lines were asserted by either of the two instructions) and execution branches to the Interrupt Service Routine (ISR). Check the flag to determine if a false condition has occurred; if it has, disregard the interrupt.
Do not clear the PIE IFR bits (that latch the LUF and LVF flags) directly because an interrupt event on the same PIE group (PIE group 12) may inadvertently be missed.
Here is an example:
_flag_LVFLUF_set .usect ".ebss",2,1,1
...
MOV32 *SP++,STF ; Save off current status flags
; Load the PieCtrlRegs page to the DP
MOVW DP, #_PieCtrlRegs.PIEIER12.all
; Zero out PIEIER12.7/8, i.e. disable LUF/LVF interrupts
AND @_PieCtrlRegs.PIEIER12.all, #0xFF3F
EISQRTF32/EINVF32 ; Execute operation
MOVL XAR3, #_flag_LVFLUF_set ; Wait for operation to complete
MOV32 *+XAR3[0], STF ; save STF to _flag_LVFLUF_set
AND *+XAR3[0], #0x3 ; mask everything but LUF/LVF
; Clear Latched overflow, underflow flag
SETFLG LUF=0, LVF=0
; Re-enable PIEIER12.7/8, i.e. re-enable the LUF/LVF interrupts
OR @_PieCtrlRegs.PIEIER12.all, #0x00C0
MOV32 STF,*--SP ; Restore previous status flags
In the ISR,
__interrupt void fpu32_luf_lvf_isr (void)
{
// Check the flag for whether the LUF, LVF flags set by
// either EISRTF32 or EINVF32
if((flag_LVFLUF_set & 0x3U) != 0U)
{
//Reset flag
flag_LVFLUF_set = 0U;
// Do Nothing
}
else
{
//If flag_LVFLUF_set was not set then this interrupt
// is the legitimate result of an overflow/underflow
// from an FPU operation (not EISQRTF32/EINVF32)
...
// Handle Overflow/Underflow condition
...
...
...
}
// Ack the interrupt and exit
}
NOTES ON COMPILER AND TOOLS USAGE
The compiler does not use LVF/LUF as condition codes for conditional instructions and neither does the Run Time Support (RTS) Library test LVF/LUF in any way.
The compiler may generate code that modifies LVF/LUF, meaning the value of the STF register (that contain these flags) is undefined at function boundaries. Thus, although the sqrt routine in the library may cause LVF/LUF to be set, there is no assurance in the CGT that the user can read these bits after sqrt returns.
Although the compiler does provide the __eisqrtf and __einvf32 intrinsics, it does not provide an intrinsic to read the LVF/LUF bits or the STF register. Thus, the user has no way to access these bits from C code.
The use of inline assembly code to read the STF register is unreliable and is discouraged. The workaround presented in the Workarounds section is applicable to assembly code that uses the EISQRTF32 and EINVF32 instructions and does not call any compiler-generated code. For C code, the user must consider these flags to be unreliable, and therefore, neither poll these flags in code nor trigger interrupts off of them.