2828
2929/* Standard includes. */
3030#include <stdlib.h>
31+ #include <string.h>
3132
3233/* Scheduler includes. */
3334#include "FreeRTOS.h"
148149 #define portTASK_RETURN_ADDRESS prvTaskExitError
149150#endif
150151
152+ /*
153+ * The space on the stack required to hold the FPU registers.
154+ *
155+ * The ARM Cortex R5 processor implements the VFPv3-D16 FPU
156+ * architecture. This includes only 16 double-precision registers,
157+ * instead of 32 as is in VFPv3. The register bank can be viewed
158+ * either as sixteen 64-bit double-word registers (D0-D15) or
159+ * thirty-two 32-bit single-word registers (S0-S31), in both cases
160+ * the size of the bank remains the same. The FPU has also a 32-bit
161+ * status register.
162+ */
163+ #define portFPU_REGISTER_WORDS ( ( 16 * 2 ) + 1 )
164+
151165/*-----------------------------------------------------------*/
152166
153167/*
@@ -161,6 +175,27 @@ extern void vPortRestoreTaskContext( void );
161175 */
162176static void prvTaskExitError ( void );
163177
178+ /*
179+ * If the application provides an implementation of vApplicationIRQHandler(),
180+ * then it will get called directly without saving the FPU registers on
181+ * interrupt entry, and this weak implementation of
182+ * vApplicationFPUSafeIRQHandler() is just provided to remove linkage errors -
183+ * it should never actually get called so its implementation contains a
184+ * call to configASSERT() that will always fail.
185+ *
186+ * If the application provides its own implementation of
187+ * vApplicationFPUSafeIRQHandler() then the implementation of
188+ * vApplicationIRQHandler() provided in portASM.S will save the FPU registers
189+ * before calling it.
190+ *
191+ * Therefore, if the application writer wants FPU registers to be saved on
192+ * interrupt entry their IRQ handler must be called
193+ * vApplicationFPUSafeIRQHandler(), and if the application writer does not want
194+ * FPU registers to be saved on interrupt entry their IRQ handler must be
195+ * called vApplicationIRQHandler().
196+ */
197+ void vApplicationFPUSafeIRQHandler ( uint32_t ulICCIAR ) __attribute__((weak ) );
198+
164199/*-----------------------------------------------------------*/
165200
166201/* A variable is used to keep track of the critical section nesting. This
@@ -255,12 +290,31 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
255290 /* The task will start with a critical nesting count of 0 as interrupts are
256291 * enabled. */
257292 * pxTopOfStack = portNO_CRITICAL_NESTING ;
258- pxTopOfStack -- ;
259293
260- /* The task will start without a floating point context. A task that uses
261- * the floating point hardware must call vPortTaskUsesFPU() before executing
262- * any floating point instructions. */
263- * pxTopOfStack = portNO_FLOATING_POINT_CONTEXT ;
294+ #if ( configUSE_TASK_FPU_SUPPORT == 1 )
295+ {
296+ /* The task will start without a floating point context. A task that
297+ uses the floating point hardware must call vPortTaskUsesFPU() before
298+ executing any floating point instructions. */
299+ pxTopOfStack -- ;
300+ * pxTopOfStack = portNO_FLOATING_POINT_CONTEXT ;
301+ }
302+ #elif ( configUSE_TASK_FPU_SUPPORT == 2 )
303+ {
304+ /* The task will start with a floating point context. Leave enough
305+ space for the registers - and ensure they are initialized to 0. */
306+ pxTopOfStack -= portFPU_REGISTER_WORDS ;
307+ memset ( pxTopOfStack , 0x00 , portFPU_REGISTER_WORDS * sizeof ( StackType_t ) );
308+
309+ pxTopOfStack -- ;
310+ * pxTopOfStack = pdTRUE ;
311+ ulPortTaskHasFPUContext = pdTRUE ;
312+ }
313+ #else
314+ {
315+ #error Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 1, 2, or left undefined.
316+ }
317+ #endif /* configUSE_TASK_FPU_SUPPORT */
264318
265319 return pxTopOfStack ;
266320}
@@ -283,6 +337,13 @@ static void prvTaskExitError( void )
283337}
284338/*-----------------------------------------------------------*/
285339
340+ void vApplicationFPUSafeIRQHandler ( uint32_t ulICCIAR )
341+ {
342+ ( void ) ulICCIAR ;
343+ configASSERT ( ( volatile void * ) NULL );
344+ }
345+ /*-----------------------------------------------------------*/
346+
286347BaseType_t xPortStartScheduler ( void )
287348{
288349 uint32_t ulAPSR , ulCycles = 8 ; /* 8 bits per byte. */
@@ -444,17 +505,21 @@ void FreeRTOS_Tick_Handler( void )
444505}
445506/*-----------------------------------------------------------*/
446507
447- void vPortTaskUsesFPU ( void )
448- {
449- uint32_t ulInitialFPSCR = 0 ;
508+ #if ( configUSE_TASK_FPU_SUPPORT != 2 )
450509
451- /* A task is registering the fact that it needs an FPU context. Set the
452- * FPU flag (which is saved as part of the task context). */
453- ulPortTaskHasFPUContext = pdTRUE ;
510+ void vPortTaskUsesFPU ( void )
511+ {
512+ uint32_t ulInitialFPSCR = 0 ;
454513
455- /* Initialise the floating point status register. */
456- __asm volatile ( "FMXR FPSCR, %0" ::"r" ( ulInitialFPSCR ) : "memory" );
457- }
514+ /* A task is registering the fact that it needs an FPU context. Set the
515+ * FPU flag (which is saved as part of the task context). */
516+ ulPortTaskHasFPUContext = pdTRUE ;
517+
518+ /* Initialise the floating point status register. */
519+ __asm volatile ( "FMXR FPSCR, %0" ::"r" ( ulInitialFPSCR ) : "memory" );
520+ }
521+
522+ #endif /* configUSE_TASK_FPU_SUPPORT */
458523/*-----------------------------------------------------------*/
459524
460525void vPortClearInterruptMask ( uint32_t ulNewMaskValue )
0 commit comments