The function printf from the new(c)lib can set the most significant 32 Bit of GPR 6. The upper 32 Bit of the GPR are normally not touched by the code emitted by the compiler. All samples initialize the upper half of the GPR to zero and this value is usually kept as long as the SW is running. Most calls of printf don't touch these bits neither but depending on the argument list it can happen. I could reduce the effect to this code fragment:
/* The first operation of the main function is the call of ihw_initMcuCoreHW(). The
assembler implemented startup code has brought the MCU in a preliminary (...) */
printf( "%.6fs: chn 1: %.3fV = %.1fC, chn 10: %.3fV (%hu), chn 15: %.3fV,"
" TSENS_0=%.1fC, TSENS_1=%.1fC\r\n"
/* Halt code execution by assertion. */
A breakpoint has been set on entry of printf and on the assertion after exit from printf. The register GPR 6 has been inspected at both breakpoints, see attached screenshots.
The call of printf changes GPR6 from 0x0000000002021000 to 0x4001fdd80000000f. The upper half of GPR6 seems to contain a stack frame pointer after return.
It is not generally an error to use the upper 32 Bit of the GPRs but it's likely undesired by the implementors of printf and by mistake only that the change of the upper 32 Bit is not undone prior to return. Regardless of the observation, my application is fine and running stable.
To my opinion, a sub-function must not return with changed upper half word of a GPR. Instead it should consider these half words as non volatile. The context switches in my application are based on the EABI conventions and do not save/restore the upper 32 Bit of the GPR. If my application code would make use of the SPE vector commands then a switch to a task using printf could make the preempted SPE task fail.
Please note, the test call of printf to reproduce the problem happens while the handling of all External Interrupts is still disabled in the MSR. The problem really is in printf itself.
The MCU is an MPC5643L in LSM, relevant linker settings are:
-mcpu=e200z4 -mbig-endian -mno-vle -mspe -misel=yes -meabi -msdata=default -G8 -mregnames -mhard-float -fshort-double -Wl,-g --sysroot=$(dir $(gcc))../powerpc-eabivle/newlib -lm
All other details can be found at https://github.com/PeterVranken/TRK-USB-MPC5643L/tree/master/LSM/ADC.
Meanwhile, I could find the answer to this question. It is due the use of the SPE instruction set. I had thought that we need to enable this set of instructions in order to get the 32 Bit floating point instructions and thus to avoid the use of floating point emulation libraries. This is however not the case. If we command the compiler not to use the SPE instruction set then it still makes use of the 32 Bit floating point instructions.
The SPE instructions are enabled by the compiler flag -mspe. If given then the compiler uses 64 Bit operations for fast memory copy code. At the same time the switch lets the linker chose the clib compiled with SPE instructions and this finally let to the made observation with the printf function.
Effectively, the observed behavior means that the use of -mspe, or of the SPE instruction set, respectively, is generally forbidden. I've seen a number of related code samples (mainly the IVOR handlers) and all of them defined a context switch only as 32 Bit. In all of these environments using the SPE instruction set becomes a hazard. The code will occasionally fail if a context is preempted while performing a 64 Bit operation by another context doing a 64 Bit operation, too. This affects all applications which either use at least one IVOR or an RTOS -- which are virtually all existing applications.
The solution would be IVOR handlers and RTOS context switching code saving all the 64 Bit of the GPR but the penalty in doing so is surely higher than the benefit from the SPE instruction set.