FPU-data and context switch on Zynq

spacesickpuppy wrote on Wednesday, September 11, 2013:

Hi,
I’m trying to implement floating-point support in the context switch on the FreeRTOS  Zynq port. http://www.freertos.org/Interactive_Frames/Open_Frames.html?http://interactive.freertos.org/entries/23277857-Updated-Xilinx-FreeRTOS-port-for-Zynq-to-SDK-14-4-release

I’m running it on the ZC702 board and using GCC.

What I have tried is adding the following lines to the FIQHandler in port_asm_vectors.s and the portSAVE_CONTEXT and portRESTORE_CONTEXT  routines:

vpush {d0-d7}
vpush {d16-d31}
vmrs r1, FPSCR 
push {r1} 
vmrs r1, FPEXC 
push {r1}




pop 	{r2}
vmsr    FPEXC, r2 
pop 	{r2}
vmsr    FPSCR, r2 
vpop    {d16-d31}
vpop    {d0-d7}

The modifications seems not to help at all, floating-point values are still corrupted in tasks.

The save and restore routines look like this:

#define portSAVE_CONTEXT()												\
{																		\
extern volatile void * volatile pxCurrentTCB;							\
extern volatile unsigned portLONG ulCriticalNesting;					\
																		\
	/* Push R0 as we are going to use the register. */					\
	__asm volatile (													\
	"STMDB	SP!, {R0}											\n\t"	\
																		\
	/* Set R0 to point to the task stack pointer. */					\
	"STMDB	SP,{SP}^											\n\t"	\
	"NOP														\n\t"	\
	"SUB	SP, SP, #4											\n\t"	\
	"LDMIA	SP!,{R0}											\n\t"	\
																		\
	/* Push the return address onto the stack. */						\
	"STMDB	R0!, {LR}											\n\t"	\
																		\
	/* Now we have saved LR we can use it instead of R0. */				\
	"MOV	LR, R0												\n\t"	\
																		\
	/* Pop R0 so we can save it onto the system mode stack. */			\
	"LDMIA	SP!, {R0}											\n\t"	\
																		\
	/* Push all the system mode registers onto the task stack. */		\
	"STMDB	LR,{R0-LR}^											\n\t"	\
	"NOP														\n\t"	\
	"SUB	LR, LR, #60											\n\t"	\
                                    \
/*Save floating-point registers*/	\
  "vpush {d0-d15}	            \n\t"	\
	"vpush {d16-d31}            \n\t"	\
	"vmrs r1, FPSCR             \n\t"	\
	"push {r1}                  \n\t"	\
	"vmrs r1, FPEXC             \n\t"	\
	"push {r1}                  \n\t"	\
                                    \
	/* Push the SPSR onto the task stack. */							\
	"MRS	R0, SPSR											\n\t"	\
	"STMDB	LR!, {R0}											\n\t"	\
																		\
	"LDR	R0, =ulCriticalNesting								\n\t"	\
	"LDR	R0, [R0]											\n\t"	\
	"STMDB	LR!, {R0}											\n\t"	\
																		\
	/* Store the new top of stack for the task. */						\
	"LDR	R0, =pxCurrentTCB									\n\t"	\
	"LDR	R0, [R0]											\n\t"	\
	"STR	LR, [R0]											\n\t"	\
	);																	\
	( void ) ulCriticalNesting;											\
	( void ) pxCurrentTCB;												\
}




#define portRESTORE_CONTEXT()											\
{																		\
extern volatile void * volatile pxCurrentTCB;							\
extern volatile unsigned portLONG ulCriticalNesting;					\
																		\
	/* Set the LR to the task stack. */									\
	__asm volatile (													\
	"LDR		R0, =pxCurrentTCB								\n\t"	\
	"LDR		R0, [R0]										\n\t"	\
	"LDR		LR, [R0]										\n\t"	\
																		\
	/* The critical nesting depth is the first item on the stack. */	\
	/* Load it into the ulCriticalNesting variable. */					\
	"LDR		R0, =ulCriticalNesting							\n\t"	\
	"LDMFD	LR!, {R1}											\n\t"	\
	"STR		R1, [R0]										\n\t"	\
																		\
	/* Get the SPSR from the stack. */									\
	"LDMFD	LR!, {R0}											\n\t"	\
	"MSR		SPSR, R0										\n\t"	\
                                      \
  /*Restore floating-point registers*/	\
	"pop 	{r2}                      \n\t"	\
	"vmsr    FPEXC, r2              \n\t"	\
	"pop 	{r2}                      \n\t"	\
	"vmsr    FPSCR, r2              \n\t"	\
	"vpop    {d16-d31}              \n\t"	\
	"vpop    {d0-d15}                \n\t"	\
                                    \
	/* Restore all system mode registers for the task. */				\
	"LDMFD	LR, {R0-R14}^										\n\t"	\
	"NOP														\n\t"	\
																		\
	/* Restore the return address. */									\
	"LDR		LR, [LR, #+60]									\n\t"	\
																		\
	/* And return - correcting the offset in the LR to obtain the */	\
	/* correct address. */												\
	"SUBS	PC, LR, #4											\n\t"	\
	"NOP														\n\t"	\
	"NOP														\n\t"	\
	);																	\
	( void ) ulCriticalNesting;											\
	( void ) pxCurrentTCB;												\
}

Am I looking in the right place in the code?

rtel wrote on Wednesday, September 11, 2013:

Unfortunately we can’t support third party code.  However, the official ARM Cortex-A9 port includes FPU support.  You could try using that. http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html

Regards.

spacesickpuppy wrote on Wednesday, September 11, 2013:

I have looked at the Cortex-A9 ports in the official release. Unfortunately there is no version for GCC with FPU support.

rtel wrote on Wednesday, September 11, 2013:

If you were using GCC the C code would not change, and the assembler instructions would not change, but the assembly file would have to be in GCC format.  You can see how this is done by comparing the RVDS Cortex-M3 port layer code to the GCC Cortex-M3 port layer code.

Regards.