mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-20 05:21:59 -04:00
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
This commit is contained in:
parent
1072988de7
commit
cd1f51cb5e
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
/* Standard includes. */
|
/* Standard includes. */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* Scheduler includes. */
|
/* Scheduler includes. */
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
|
@ -148,6 +149,19 @@
|
||||||
#define portTASK_RETURN_ADDRESS prvTaskExitError
|
#define portTASK_RETURN_ADDRESS prvTaskExitError
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The space on the stack required to hold the FPU registers.
|
||||||
|
*
|
||||||
|
* The ARM Cortex R5 processor implements the VFPv3-D16 FPU
|
||||||
|
* architecture. This includes only 16 double-precision registers,
|
||||||
|
* instead of 32 as is in VFPv3. The register bank can be viewed
|
||||||
|
* either as sixteen 64-bit double-word registers (D0-D15) or
|
||||||
|
* thirty-two 32-bit single-word registers (S0-S31), in both cases
|
||||||
|
* the size of the bank remains the same. The FPU has also a 32-bit
|
||||||
|
* status register.
|
||||||
|
*/
|
||||||
|
#define portFPU_REGISTER_WORDS ( ( 16 * 2 ) + 1 )
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -161,6 +175,27 @@ extern void vPortRestoreTaskContext( void );
|
||||||
*/
|
*/
|
||||||
static void prvTaskExitError( void );
|
static void prvTaskExitError( void );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the application provides an implementation of vApplicationIRQHandler(),
|
||||||
|
* then it will get called directly without saving the FPU registers on
|
||||||
|
* interrupt entry, and this weak implementation of
|
||||||
|
* vApplicationFPUSafeIRQHandler() is just provided to remove linkage errors -
|
||||||
|
* it should never actually get called so its implementation contains a
|
||||||
|
* call to configASSERT() that will always fail.
|
||||||
|
*
|
||||||
|
* If the application provides its own implementation of
|
||||||
|
* vApplicationFPUSafeIRQHandler() then the implementation of
|
||||||
|
* vApplicationIRQHandler() provided in portASM.S will save the FPU registers
|
||||||
|
* before calling it.
|
||||||
|
*
|
||||||
|
* Therefore, if the application writer wants FPU registers to be saved on
|
||||||
|
* interrupt entry their IRQ handler must be called
|
||||||
|
* vApplicationFPUSafeIRQHandler(), and if the application writer does not want
|
||||||
|
* FPU registers to be saved on interrupt entry their IRQ handler must be
|
||||||
|
* called vApplicationIRQHandler().
|
||||||
|
*/
|
||||||
|
void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__((weak) );
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* A variable is used to keep track of the critical section nesting. This
|
/* A variable is used to keep track of the critical section nesting. This
|
||||||
|
@ -255,12 +290,31 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
||||||
/* The task will start with a critical nesting count of 0 as interrupts are
|
/* The task will start with a critical nesting count of 0 as interrupts are
|
||||||
* enabled. */
|
* enabled. */
|
||||||
*pxTopOfStack = portNO_CRITICAL_NESTING;
|
*pxTopOfStack = portNO_CRITICAL_NESTING;
|
||||||
pxTopOfStack--;
|
|
||||||
|
|
||||||
/* The task will start without a floating point context. A task that uses
|
#if( configUSE_TASK_FPU_SUPPORT == 1 )
|
||||||
* the floating point hardware must call vPortTaskUsesFPU() before executing
|
{
|
||||||
* any floating point instructions. */
|
/* The task will start without a floating point context. A task that
|
||||||
*pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
|
uses the floating point hardware must call vPortTaskUsesFPU() before
|
||||||
|
executing any floating point instructions. */
|
||||||
|
pxTopOfStack--;
|
||||||
|
*pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
|
||||||
|
}
|
||||||
|
#elif( configUSE_TASK_FPU_SUPPORT == 2 )
|
||||||
|
{
|
||||||
|
/* The task will start with a floating point context. Leave enough
|
||||||
|
space for the registers - and ensure they are initialized to 0. */
|
||||||
|
pxTopOfStack -= portFPU_REGISTER_WORDS;
|
||||||
|
memset( pxTopOfStack, 0x00, portFPU_REGISTER_WORDS * sizeof( StackType_t ) );
|
||||||
|
|
||||||
|
pxTopOfStack--;
|
||||||
|
*pxTopOfStack = pdTRUE;
|
||||||
|
ulPortTaskHasFPUContext = pdTRUE;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
#error Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 1, 2, or left undefined.
|
||||||
|
}
|
||||||
|
#endif /* configUSE_TASK_FPU_SUPPORT */
|
||||||
|
|
||||||
return pxTopOfStack;
|
return pxTopOfStack;
|
||||||
}
|
}
|
||||||
|
@ -283,6 +337,13 @@ static void prvTaskExitError( void )
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR )
|
||||||
|
{
|
||||||
|
( void ) ulICCIAR;
|
||||||
|
configASSERT( ( volatile void * ) NULL );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
BaseType_t xPortStartScheduler( void )
|
BaseType_t xPortStartScheduler( void )
|
||||||
{
|
{
|
||||||
uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
|
uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
|
||||||
|
@ -444,17 +505,21 @@ void FreeRTOS_Tick_Handler( void )
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortTaskUsesFPU( void )
|
#if( configUSE_TASK_FPU_SUPPORT != 2 )
|
||||||
{
|
|
||||||
uint32_t ulInitialFPSCR = 0;
|
|
||||||
|
|
||||||
/* A task is registering the fact that it needs an FPU context. Set the
|
void vPortTaskUsesFPU( void )
|
||||||
* FPU flag (which is saved as part of the task context). */
|
{
|
||||||
ulPortTaskHasFPUContext = pdTRUE;
|
uint32_t ulInitialFPSCR = 0;
|
||||||
|
|
||||||
/* Initialise the floating point status register. */
|
/* A task is registering the fact that it needs an FPU context. Set the
|
||||||
__asm volatile ( "FMXR FPSCR, %0" ::"r" ( ulInitialFPSCR ) : "memory" );
|
* FPU flag (which is saved as part of the task context). */
|
||||||
}
|
ulPortTaskHasFPUContext = pdTRUE;
|
||||||
|
|
||||||
|
/* Initialise the floating point status register. */
|
||||||
|
__asm volatile ( "FMXR FPSCR, %0" ::"r" ( ulInitialFPSCR ) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configUSE_TASK_FPU_SUPPORT */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vPortClearInterruptMask( uint32_t ulNewMaskValue )
|
void vPortClearInterruptMask( uint32_t ulNewMaskValue )
|
||||||
|
|
|
@ -262,6 +262,42 @@ switch_before_exit:
|
||||||
next. */
|
next. */
|
||||||
portRESTORE_CONTEXT
|
portRESTORE_CONTEXT
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* If the application provides an implementation of vApplicationIRQHandler(),
|
||||||
|
* then it will get called directly without saving the FPU registers on
|
||||||
|
* interrupt entry, and this weak implementation of
|
||||||
|
* vApplicationIRQHandler() will not get called.
|
||||||
|
*
|
||||||
|
* If the application provides its own implementation of
|
||||||
|
* vApplicationFPUSafeIRQHandler() then this implementation of
|
||||||
|
* vApplicationIRQHandler() will be called, save the FPU registers, and then
|
||||||
|
* call vApplicationFPUSafeIRQHandler().
|
||||||
|
*
|
||||||
|
* Therefore, if the application writer wants FPU registers to be saved on
|
||||||
|
* interrupt entry their IRQ handler must be called
|
||||||
|
* vApplicationFPUSafeIRQHandler(), and if the application writer does not want
|
||||||
|
* FPU registers to be saved on interrupt entry their IRQ handler must be
|
||||||
|
* called vApplicationIRQHandler().
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.weak vApplicationIRQHandler
|
||||||
|
.type vApplicationIRQHandler, %function
|
||||||
|
vApplicationIRQHandler:
|
||||||
|
PUSH {LR}
|
||||||
|
FMRX R1, FPSCR
|
||||||
|
VPUSH {D0-D15}
|
||||||
|
PUSH {R1}
|
||||||
|
|
||||||
|
LDR r1, vApplicationFPUSafeIRQHandlerConst
|
||||||
|
BLX r1
|
||||||
|
|
||||||
|
POP {R0}
|
||||||
|
VPOP {D0-D15}
|
||||||
|
VMSR FPSCR, R0
|
||||||
|
|
||||||
|
POP {PC}
|
||||||
|
|
||||||
ulICCIARConst: .word ulICCIAR
|
ulICCIARConst: .word ulICCIAR
|
||||||
ulICCEOIRConst: .word ulICCEOIR
|
ulICCEOIRConst: .word ulICCEOIR
|
||||||
ulICCPMRConst: .word ulICCPMR
|
ulICCPMRConst: .word ulICCPMR
|
||||||
|
@ -272,6 +308,7 @@ ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask
|
||||||
vTaskSwitchContextConst: .word vTaskSwitchContext
|
vTaskSwitchContextConst: .word vTaskSwitchContext
|
||||||
vApplicationIRQHandlerConst: .word vApplicationIRQHandler
|
vApplicationIRQHandlerConst: .word vApplicationIRQHandler
|
||||||
ulPortInterruptNestingConst: .word ulPortInterruptNesting
|
ulPortInterruptNestingConst: .word ulPortInterruptNesting
|
||||||
|
vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler
|
||||||
|
|
||||||
.end
|
.end
|
||||||
|
|
||||||
|
|
|
@ -116,9 +116,18 @@
|
||||||
* handler for whichever peripheral is used to generate the RTOS tick. */
|
* handler for whichever peripheral is used to generate the RTOS tick. */
|
||||||
void FreeRTOS_Tick_Handler( void );
|
void FreeRTOS_Tick_Handler( void );
|
||||||
|
|
||||||
/* Any task that uses the floating point unit MUST call vPortTaskUsesFPU()
|
/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or left undefined) then tasks are
|
||||||
* before any floating point instructions are executed. */
|
created without an FPU context and must call vPortTaskUsesFPU() to give
|
||||||
|
themselves an FPU context before using any FPU instructions. If
|
||||||
|
configUSE_TASK_FPU_SUPPORT is set to 2 then all tasks will have an FPU context
|
||||||
|
by default. */
|
||||||
|
#if( configUSE_TASK_FPU_SUPPORT != 2 )
|
||||||
void vPortTaskUsesFPU( void );
|
void vPortTaskUsesFPU( void );
|
||||||
|
#else
|
||||||
|
/* Each task has an FPU context already, so define this function away to
|
||||||
|
nothing to prevent it being called accidentally. */
|
||||||
|
#define vPortTaskUsesFPU()
|
||||||
|
#endif /* configUSE_TASK_FPU_SUPPORT */
|
||||||
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
|
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
|
||||||
|
|
||||||
#define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )
|
#define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )
|
||||||
|
|
Loading…
Reference in a new issue