Skip to content

Commit cd1f51c

Browse files
authored
Add support for the configUSE_TASK_FPU_SUPPORT constant in the GCC/ARM_CR5 port (#584)
* Add support for the configUSE_TASK_FPU_SUPPORT in the GCC/ARM_CR5 port This is done almost identically as in the GCC/ARM_CA9 port * Adjust task stack initialitation of the GCC/ARM_CR5 port Ensure that the task stack initialization is done correctly for the different options of configUSE_TASK_FPU_SUPPORT. This is very similar to the GCC/ARM_CA9 port. The only meaningful difference is, that the FPU of the Cortex-R5 has just sixteen 64-bit floating point registers as it implements the VFPv3-D16 architecture. You may also refer to the ARM documentation * Add support for FPU safe interrupts to the GCC/ARM_CR5 port Similar to GCC/ARM_CA9 port * Clarify comment about the size of the FPU registers of Cortex R5
1 parent 1072988 commit cd1f51c

File tree

3 files changed

+127
-16
lines changed

3 files changed

+127
-16
lines changed

portable/GCC/ARM_CR5/port.c

+79-14
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
/* Standard includes. */
3030
#include <stdlib.h>
31+
#include <string.h>
3132

3233
/* Scheduler includes. */
3334
#include "FreeRTOS.h"
@@ -148,6 +149,19 @@
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
*/
162176
static 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+
286347
BaseType_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

460525
void vPortClearInterruptMask( uint32_t ulNewMaskValue )

portable/GCC/ARM_CR5/portASM.S

+37
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,42 @@ switch_before_exit:
262262
next. */
263263
portRESTORE_CONTEXT
264264

265+
/******************************************************************************
266+
* If the application provides an implementation of vApplicationIRQHandler(),
267+
* then it will get called directly without saving the FPU registers on
268+
* interrupt entry, and this weak implementation of
269+
* vApplicationIRQHandler() will not get called.
270+
*
271+
* If the application provides its own implementation of
272+
* vApplicationFPUSafeIRQHandler() then this implementation of
273+
* vApplicationIRQHandler() will be called, save the FPU registers, and then
274+
* call vApplicationFPUSafeIRQHandler().
275+
*
276+
* Therefore, if the application writer wants FPU registers to be saved on
277+
* interrupt entry their IRQ handler must be called
278+
* vApplicationFPUSafeIRQHandler(), and if the application writer does not want
279+
* FPU registers to be saved on interrupt entry their IRQ handler must be
280+
* called vApplicationIRQHandler().
281+
*****************************************************************************/
282+
283+
.align 4
284+
.weak vApplicationIRQHandler
285+
.type vApplicationIRQHandler, %function
286+
vApplicationIRQHandler:
287+
PUSH {LR}
288+
FMRX R1, FPSCR
289+
VPUSH {D0-D15}
290+
PUSH {R1}
291+
292+
LDR r1, vApplicationFPUSafeIRQHandlerConst
293+
BLX r1
294+
295+
POP {R0}
296+
VPOP {D0-D15}
297+
VMSR FPSCR, R0
298+
299+
POP {PC}
300+
265301
ulICCIARConst: .word ulICCIAR
266302
ulICCEOIRConst: .word ulICCEOIR
267303
ulICCPMRConst: .word ulICCPMR
@@ -272,6 +308,7 @@ ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask
272308
vTaskSwitchContextConst: .word vTaskSwitchContext
273309
vApplicationIRQHandlerConst: .word vApplicationIRQHandler
274310
ulPortInterruptNestingConst: .word ulPortInterruptNesting
311+
vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler
275312

276313
.end
277314

portable/GCC/ARM_CR5/portmacro.h

+11-2
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,18 @@
116116
* handler for whichever peripheral is used to generate the RTOS tick. */
117117
void FreeRTOS_Tick_Handler( void );
118118

119-
/* Any task that uses the floating point unit MUST call vPortTaskUsesFPU()
120-
* before any floating point instructions are executed. */
119+
/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or left undefined) then tasks are
120+
created without an FPU context and must call vPortTaskUsesFPU() to give
121+
themselves an FPU context before using any FPU instructions. If
122+
configUSE_TASK_FPU_SUPPORT is set to 2 then all tasks will have an FPU context
123+
by default. */
124+
#if( configUSE_TASK_FPU_SUPPORT != 2 )
121125
void vPortTaskUsesFPU( void );
126+
#else
127+
/* Each task has an FPU context already, so define this function away to
128+
nothing to prevent it being called accidentally. */
129+
#define vPortTaskUsesFPU()
130+
#endif /* configUSE_TASK_FPU_SUPPORT */
122131
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
123132

124133
#define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )

0 commit comments

Comments
 (0)