Enable building the GCC Cortex-R5 port without an FPU (#586)

* Ensure configUSE_TASK_FPU_SUPPORT option is set correctly

If one does enable the FPU of the Cortex-R5 processor, then the GCC
compiler will define the macro __ARM_FP. This can be used to ensure,
that the configUSE_TASK_FPU_SUPPORT is set accordingly.

* Enable the implementation of vPortTaskUsesFPU only if configUSE_TASK_FPU_SUPPORT is set to 1

* Remove error case in pxPortInitialiseStack

The case of configUSE_TASK_FPU_SUPPORT is 0 is now handled

* Enable access to FPU registers only if FPU is enabled

* Make minor formating changes

* Format ARM Cortex-R5 port

* Address review comments from @ChristosZosi

* Minor code review suggestions

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>

---------

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
Co-authored-by: Christos Zosimidis <christos.zosimidis@gmail.com>
Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com>
Co-authored-by: Gaurav Aggarwal <aggarg@amazon.com>
pull/640/head
Paul Bartell 2 years ago committed by GitHub
parent 563c57e7da
commit 7b26ea6263
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -74,25 +74,52 @@
#error configMAX_API_CALL_INTERRUPT_PRIORITY must be greater than ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )
#endif
/* Some vendor specific files default configCLEAR_TICK_INTERRUPT() in
* portmacro.h. */
/*
* __ARM_FP is defined by the c preprocessor when FPU support is enabled,
* usually with the -mfpu= argument and -mfloat-abi=.
*
* Note: Some implementations of the c standard library may use FPU registers
* for generic memory operations (memcpy, etc).
* When setting configUSE_TASK_FPU_SUPPORT == 1, care must be taken to
* ensure that the FPU registers are not used without an FPU context.
*/
#if ( configUSE_TASK_FPU_SUPPORT == 0 )
#ifdef __ARM_FP
#error __ARM_FP is defined, so configUSE_TASK_FPU_SUPPORT must be set to either to 1 or 2.
#endif /* __ARM_FP */
#elif ( configUSE_TASK_FPU_SUPPORT == 1 ) || ( configUSE_TASK_FPU_SUPPORT == 2 )
#ifndef __ARM_FP
#error __ARM_FP is not defined, so configUSE_TASK_FPU_SUPPORT must be set to 0.
#endif /* __ARM_FP */
#endif /* configUSE_TASK_FPU_SUPPORT */
/*
* Some vendor specific files default configCLEAR_TICK_INTERRUPT() in
* portmacro.h.
*/
#ifndef configCLEAR_TICK_INTERRUPT
#define configCLEAR_TICK_INTERRUPT()
#endif
/* A critical section is exited when the critical section nesting count reaches
* this value. */
/*
* A critical section is exited when the critical section nesting count reaches
* this value.
*/
#define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
/* In all GICs 255 can be written to the priority mask register to unmask all
* (but the lowest) interrupt priority. */
/*
* In all GICs 255 can be written to the priority mask register to unmask all
* (but the lowest) interrupt priority.
*/
#define portUNMASK_VALUE ( 0xFFUL )
/* Tasks are not created with a floating point context, but can be given a
/*
* Tasks are not created with a floating point context, but can be given a
* floating point context after they have been created. A variable is stored as
* part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
* does not have an FPU context, or any other value if the task does have an FPU
* context. */
* context.
*/
#define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
/* Constants required to setup the initial task context. */
@ -101,8 +128,10 @@
#define portINTERRUPT_ENABLE_BIT ( 0x80UL )
#define portTHUMB_MODE_ADDRESS ( 0x01UL )
/* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
* point is zero. */
/*
* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
* point is zero.
*/
#define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 )
/* Masks all bits in the APSR other than the mode bits. */
@ -140,15 +169,19 @@
#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
#define portBIT_0_SET ( ( uint8_t ) 0x01 )
/* Let the user override the pre-loading of the initial LR with the address of
/*
* Let the user override the pre-loading of the initial LR with the address of
* prvTaskExitError() in case is messes up unwinding of the stack in the
* debugger. */
* debugger.
*/
#ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else
#define portTASK_RETURN_ADDRESS prvTaskExitError
#endif
#if ( configUSE_TASK_FPU_SUPPORT != 0 )
/*
* The space on the stack required to hold the FPU registers.
*
@ -160,7 +193,8 @@
* the size of the bank remains the same. The FPU has also a 32-bit
* status register.
*/
#define portFPU_REGISTER_WORDS ( ( 16 * 2 ) + 1 )
#define portFPU_REGISTER_WORDS ( ( 16 * 2 ) + 1 )
#endif /* configUSE_TASK_FPU_SUPPORT != 0 */
/*-----------------------------------------------------------*/
@ -175,6 +209,8 @@ extern void vPortRestoreTaskContext( void );
*/
static void prvTaskExitError( void );
#if ( configUSE_TASK_FPU_SUPPORT != 0 )
/*
* If the application provides an implementation of vApplicationIRQHandler(),
* then it will get called directly without saving the FPU registers on
@ -194,26 +230,36 @@ static void prvTaskExitError( void );
* FPU registers to be saved on interrupt entry their IRQ handler must be
* called vApplicationIRQHandler().
*/
void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__((weak) );
void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__( ( weak ) );
#endif /* configUSE_TASK_FPU_SUPPORT != 0 */
/*-----------------------------------------------------------*/
/* 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
* variable has to be stored as part of the task context and must be initialised to
* a non zero value to ensure interrupts don't inadvertently become unmasked before
* the scheduler starts. As it is stored as part of the task context it will
* automatically be set to 0 when the first task is started. */
* automatically be set to 0 when the first task is started.
*/
volatile uint32_t ulCriticalNesting = 9999UL;
/* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
* a floating point context must be saved and restored for the task. */
uint32_t ulPortTaskHasFPUContext = pdFALSE;
#if ( configUSE_TASK_FPU_SUPPORT != 0 )
/*
* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
* a floating point context must be saved and restored for the task.
*/
uint32_t ulPortTaskHasFPUContext = pdFALSE;
#endif /* configUSE_TASK_FPU_SUPPORT != 0 */
/* Set to 1 to pend a context switch from an ISR. */
uint32_t ulPortYieldRequired = pdFALSE;
/* Counts the interrupt nesting depth. A context switch is only performed if
* if the nesting depth is 0. */
/*
* Counts the interrupt nesting depth. A context switch is only performed if
* if the nesting depth is 0.
*/
uint32_t ulPortInterruptNesting = 0UL;
/* Used in asm code. */
@ -231,12 +277,14 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
TaskFunction_t pxCode,
void * pvParameters )
{
/* Setup the initial stack of the task. The stack is set exactly as
/*
* Setup the initial stack of the task. The stack is set exactly as
* expected by the portRESTORE_CONTEXT() macro.
*
* The fist real value on the stack is the status register, which is set for
* system mode, with interrupts enabled. A few NULLs are added first to ensure
* GDB does not try decoding a non-existent return address. */
* GDB does not try decoding a non-existent return address.
*/
*pxTopOfStack = ( StackType_t ) NULL;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) NULL;
@ -285,24 +333,31 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
*pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
pxTopOfStack--;
/* The task will start with a critical nesting count of 0 as interrupts are
* enabled. */
/*
* The task will start with a critical nesting count of 0 as interrupts are
* enabled.
*/
pxTopOfStack--;
*pxTopOfStack = portNO_CRITICAL_NESTING;
#if( configUSE_TASK_FPU_SUPPORT == 1 )
#if ( configUSE_TASK_FPU_SUPPORT == 1 )
{
/* The task will start without a floating point context. A task that
uses 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 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 )
#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. */
/*
* 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 ) );
@ -310,9 +365,9 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
*pxTopOfStack = pdTRUE;
ulPortTaskHasFPUContext = pdTRUE;
}
#else
#elif ( configUSE_TASK_FPU_SUPPORT != 0 )
{
#error Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 1, 2, or left undefined.
#error Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 0, 1, or 2.
}
#endif /* configUSE_TASK_FPU_SUPPORT */
@ -322,12 +377,14 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
static void prvTaskExitError( void )
{
/* A function that implements a task must not exit or attempt to return to
/*
* A function that implements a task must not exit or attempt to return to
* its caller as there is nothing to return to. If a task wants to exit it
* should instead call vTaskDelete( NULL ).
*
* Artificially force an assert() to be triggered if configASSERT() is
* defined, then stop here so application writers can catch the error. */
* defined, then stop here so application writers can catch the error.
*/
configASSERT( ulPortInterruptNesting == ~0UL );
portDISABLE_INTERRUPTS();
@ -337,11 +394,15 @@ static void prvTaskExitError( void )
}
/*-----------------------------------------------------------*/
void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR )
{
( void ) ulICCIAR;
configASSERT( ( volatile void * ) NULL );
}
#if ( configUSE_TASK_FPU_SUPPORT != 0 )
void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) /* __attribute__( ( weak ) ) */
{
( void ) ulICCIAR;
configASSERT( ( volatile void * ) NULL );
}
#endif /* configUSE_TASK_FPU_SUPPORT != 0 */
/*-----------------------------------------------------------*/
BaseType_t xPortStartScheduler( void )
@ -349,67 +410,82 @@ BaseType_t xPortStartScheduler( void )
uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
#if ( configASSERT_DEFINED == 1 )
{
volatile uint32_t ulOriginalPriority;
volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portINTERRUPT_PRIORITY_REGISTER_OFFSET );
volatile uint8_t ucMaxPriorityValue;
/*
* Determine how many priority bits are implemented in the GIC.
* Save the interrupt priority value that is about to be clobbered.
*/
ulOriginalPriority = *pucFirstUserPriorityRegister;
/*
* Determine the number of priority bits available. First write to
* all possible bits.
*/
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
/* Shift to the least significant bits. */
while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET )
{
volatile uint32_t ulOriginalPriority;
volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portINTERRUPT_PRIORITY_REGISTER_OFFSET );
volatile uint8_t ucMaxPriorityValue;
/* Determine how many priority bits are implemented in the GIC.
*
* Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to
* all possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
ucMaxPriorityValue >>= ( uint8_t ) 0x01;
/* Read the value back to see how many bits stuck. */
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
/*
* If ulCycles reaches 0 then ucMaxPriorityValue must have been
* read as 0, indicating a misconfiguration.
*/
ulCycles--;
/* Shift to the least significant bits. */
while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET )
if( ulCycles == 0 )
{
ucMaxPriorityValue >>= ( uint8_t ) 0x01;
/* If ulCycles reaches 0 then ucMaxPriorityValue must have been
* read as 0, indicating a misconfiguration. */
ulCycles--;
if( ulCycles == 0 )
{
break;
}
break;
}
/* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
* value. */
configASSERT( ucMaxPriorityValue == portLOWEST_INTERRUPT_PRIORITY );
/* Restore the clobbered interrupt priority register to its original
* value. */
*pucFirstUserPriorityRegister = ulOriginalPriority;
}
/*
* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
* value.
*/
configASSERT( ucMaxPriorityValue == portLOWEST_INTERRUPT_PRIORITY );
/*
* Restore the clobbered interrupt priority register to its original
* value.
*/
*pucFirstUserPriorityRegister = ulOriginalPriority;
}
#endif /* configASSERT_DEFINED */
/* Only continue if the CPU is not in User mode. The CPU must be in a
* Privileged mode for the scheduler to start. */
/*
* Only continue if the CPU is not in User mode. The CPU must be in a
* Privileged mode for the scheduler to start.
*/
__asm volatile ( "MRS %0, APSR" : "=r" ( ulAPSR )::"memory" );
ulAPSR &= portAPSR_MODE_BITS_MASK;
configASSERT( ulAPSR != portAPSR_USER_MODE );
if( ulAPSR != portAPSR_USER_MODE )
{
/* Only continue if the binary point value is set to its lowest possible
/*
* Only continue if the binary point value is set to its lowest possible
* setting. See the comments in vPortValidateInterruptPriority() below for
* more information. */
* more information.
*/
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
{
/* Interrupts are turned off in the CPU itself to ensure tick does
/*
* Interrupts are turned off in the CPU itself to ensure tick does
* not execute while the scheduler is being started. Interrupts are
* automatically turned back on in the CPU when the first task starts
* executing. */
* executing.
*/
portCPU_IRQ_DISABLE();
/* Start the timer that generates the tick ISR. */
@ -420,20 +496,25 @@ BaseType_t xPortStartScheduler( void )
}
}
/* Will only get here if vTaskStartScheduler() was called with the CPU in
/*
* Will only get here if vTaskStartScheduler() was called with the CPU in
* a non-privileged mode or the binary point register was not set to its lowest
* possible value. prvTaskExitError() is referenced to prevent a compiler
* warning about it being defined but not referenced in the case that the user
* defines their own exit address. */
* defines their own exit address.
*/
( void ) prvTaskExitError;
return 0;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Not implemented in ports where there is nothing to return to.
* Artificially force an assert. */
/*
* Not implemented in ports where there is nothing to return to.
* Artificially force an assert.
*/
configASSERT( ulCriticalNesting == 1000UL );
}
/*-----------------------------------------------------------*/
@ -443,16 +524,20 @@ void vPortEnterCritical( void )
/* Mask interrupts up to the max syscall interrupt priority. */
ulPortSetInterruptMask();
/* Now interrupts are disabled ulCriticalNesting can be accessed
/*
* Now interrupts are disabled ulCriticalNesting can be accessed
* directly. Increment ulCriticalNesting to keep a count of how many times
* portENTER_CRITICAL() has been called. */
* portENTER_CRITICAL() has been called.
*/
ulCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so
/*
* This is not the interrupt safe version of the enter critical function so
* assert() if it is being called from an interrupt context. Only API
* functions that end in "FromISR" can be used in an interrupt. Only assert if
* the critical nesting count is 1 to protect against recursive calls if the
* assert function also uses a critical section. */
* assert function also uses a critical section.
*/
if( ulCriticalNesting == 1 )
{
configASSERT( ulPortInterruptNesting == 0 );
@ -464,16 +549,19 @@ void vPortExitCritical( void )
{
if( ulCriticalNesting > portNO_CRITICAL_NESTING )
{
/* Decrement the nesting count as the critical section is being
* exited. */
/* Decrement the nesting count as the critical section is being exited. */
ulCriticalNesting--;
/* If the nesting level has reached zero then all interrupt
* priorities must be re-enabled. */
/*
* If the nesting level has reached zero then all interrupt
* priorities must be re-enabled.
*/
if( ulCriticalNesting == portNO_CRITICAL_NESTING )
{
/* Critical nesting has reached zero so all interrupt priorities
* should be unmasked. */
/*
* Critical nesting has reached zero so all interrupt priorities
* should be unmasked.
*/
portCLEAR_INTERRUPT_MASK();
}
}
@ -482,11 +570,13 @@ void vPortExitCritical( void )
void FreeRTOS_Tick_Handler( void )
{
/* Set interrupt mask before altering scheduler structures. The tick
/*
* Set interrupt mask before altering scheduler structures. The tick
* handler runs at the lowest priority, so interrupts cannot already be masked,
* so there is no need to save and restore the current mask value. It is
* necessary to turn off interrupts in the CPU itself while the ICCPMR is being
* updated. */
* updated.
*/
portCPU_IRQ_DISABLE();
portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
__asm volatile ( "dsb \n"
@ -505,21 +595,23 @@ void FreeRTOS_Tick_Handler( void )
}
/*-----------------------------------------------------------*/
#if( configUSE_TASK_FPU_SUPPORT != 2 )
#if ( configUSE_TASK_FPU_SUPPORT == 1 )
void vPortTaskUsesFPU( void )
{
uint32_t ulInitialFPSCR = 0;
/* A task is registering the fact that it needs an FPU context. Set the
* FPU flag (which is saved as part of the task context). */
/*
* A task is registering the fact that it needs an FPU context. Set the
* 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 */
#endif /* configUSE_TASK_FPU_SUPPORT == 1 */
/*-----------------------------------------------------------*/
void vPortClearInterruptMask( uint32_t ulNewMaskValue )
@ -535,8 +627,7 @@ uint32_t ulPortSetInterruptMask( void )
{
uint32_t ulReturn;
/* Interrupt in the CPU must be turned off while the ICCPMR is being
* updated. */
/* Interrupts must be masked while ICCPMR is updated. */
portCPU_IRQ_DISABLE();
if( portICCPMR_PRIORITY_MASK_REGISTER == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
@ -562,7 +653,8 @@ uint32_t ulPortSetInterruptMask( void )
void vPortValidateInterruptPriority( void )
{
/* The following assertion will fail if a service routine (ISR) for
/*
* The following assertion will fail if a service routine (ISR) for
* an interrupt that has been assigned a priority above
* configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
* function. ISR safe FreeRTOS API functions must *only* be called
@ -575,11 +667,13 @@ uint32_t ulPortSetInterruptMask( void )
* configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
* FreeRTOS maintains separate thread and ISR API functions to ensure
* interrupt entry is as fast and simple as possible. */
* interrupt entry is as fast and simple as possible.
*/
configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
/* Priority grouping: The interrupt controller (GIC) allows the bits
/*
* Priority grouping: The interrupt controller (GIC) allows the bits
* that define each interrupt's priority to be split between bits that
* define the interrupt's pre-emption priority bits and bits that define
* the interrupt's sub-priority. For simplicity all bits must be defined
@ -588,7 +682,8 @@ uint32_t ulPortSetInterruptMask( void )
*
* The priority grouping is configured by the GIC's binary point register
* (ICCBPR). Writing 0 to ICCBPR will ensure it is set to its lowest
* possible value (which may be above 0). */
* possible value (which may be above 0).
*/
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
}

@ -45,7 +45,10 @@
.extern vTaskSwitchContext
.extern vApplicationIRQHandler
.extern ulPortInterruptNesting
#if defined( __ARM_FP )
.extern ulPortTaskHasFPUContext
#endif /* __ARM_FP */
.global FreeRTOS_IRQ_Handler
.global FreeRTOS_SWI_Handler
@ -64,20 +67,21 @@
LDR R1, [R2]
PUSH {R1}
/* Does the task have a floating point context that needs saving? If
ulPortTaskHasFPUContext is 0 then no. */
LDR R2, ulPortTaskHasFPUContextConst
LDR R3, [R2]
CMP R3, #0
#if defined( __ARM_FP )
/* Does the task have a floating point context that needs saving? If
ulPortTaskHasFPUContext is 0 then no. */
LDR R2, ulPortTaskHasFPUContextConst
LDR R3, [R2]
CMP R3, #0
/* Save the floating point context, if any. */
FMRXNE R1, FPSCR
VPUSHNE {D0-D15}
/*VPUSHNE {D16-D31}*/
PUSHNE {R1}
/* Save the floating point context, if any. */
FMRXNE R1, FPSCR
VPUSHNE {D0-D15}
PUSHNE {R1}
/* Save ulPortTaskHasFPUContext itself. */
PUSH {R3}
/* Save ulPortTaskHasFPUContext itself. */
PUSH {R3}
#endif /* __ARM_FP */
/* Save the stack pointer in the TCB. */
LDR R0, pxCurrentTCBConst
@ -95,18 +99,21 @@
LDR R1, [R0]
LDR SP, [R1]
/* Is there a floating point context to restore? If the restored
ulPortTaskHasFPUContext is zero then no. */
LDR R0, ulPortTaskHasFPUContextConst
POP {R1}
STR R1, [R0]
CMP R1, #0
/* Restore the floating point context, if any. */
POPNE {R0}
/*VPOPNE {D16-D31}*/
VPOPNE {D0-D15}
VMSRNE FPSCR, R0
#if defined( __ARM_FP )
/*
* Is there a floating point context to restore? If the restored
* ulPortTaskHasFPUContext is zero then no.
*/
LDR R0, ulPortTaskHasFPUContextConst
POP {R1}
STR R1, [R0]
CMP R1, #0
/* Restore the floating point context, if any. */
POPNE {R0}
VPOPNE {D0-D15}
VMSRNE FPSCR, R0
#endif /* __ARM_FP */
/* Restore the critical section nesting depth. */
LDR R0, ulCriticalNestingConst
@ -132,8 +139,6 @@
.endm
/******************************************************************************
* SVC handler is used to start the scheduler.
*****************************************************************************/
@ -279,22 +284,25 @@ switch_before_exit:
* 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
#if defined( __ARM_FP )
FMRX R1, FPSCR
VPUSH {D0-D15}
PUSH {R1}
POP {R0}
VPOP {D0-D15}
VMSR FPSCR, R0
LDR r1, vApplicationFPUSafeIRQHandlerConst
BLX r1
POP {R0}
VPOP {D0-D15}
VMSR FPSCR, R0
#endif /* __ARM_FP */
POP {PC}
@ -303,11 +311,15 @@ ulICCEOIRConst: .word ulICCEOIR
ulICCPMRConst: .word ulICCPMR
pxCurrentTCBConst: .word pxCurrentTCB
ulCriticalNestingConst: .word ulCriticalNesting
ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext
#if defined( __ARM_FP )
ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext
vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler
#endif /* __ARM_FP */
ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask
vTaskSwitchContextConst: .word vTaskSwitchContext
vApplicationIRQHandlerConst: .word vApplicationIRQHandler
ulPortInterruptNestingConst: .word ulPortInterruptNesting
vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler
.end

@ -27,11 +27,13 @@
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/*-----------------------------------------------------------
* Port specific definitions.
@ -44,161 +46,175 @@
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/*-----------------------------------------------------------*/
/* Hardware specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/
/* Task utilities. */
/* Called at the end of an ISR that can cause a context switch. */
#define portEND_SWITCHING_ISR( xSwitchRequired ) \
{ \
extern uint32_t ulPortYieldRequired; \
\
if( xSwitchRequired != pdFALSE ) \
{ \
ulPortYieldRequired = pdTRUE; \
} \
#define portEND_SWITCHING_ISR( xSwitchRequired ) \
{ \
extern uint32_t ulPortYieldRequired; \
\
if( xSwitchRequired != pdFALSE ) \
{ \
ulPortYieldRequired = pdTRUE; \
} \
}
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
#define portYIELD() __asm volatile ( "SWI 0" ::: "memory" );
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
#define portYIELD() __asm volatile ( "SWI 0" ::: "memory" );
/*-----------------------------------------------------------
* Critical section control
*----------------------------------------------------------*/
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
extern uint32_t ulPortSetInterruptMask( void );
extern void vPortClearInterruptMask( uint32_t ulNewMaskValue );
extern void vPortInstallFreeRTOSVectorTable( void );
/* These macros do not globally disable/enable interrupts. They do mask off
* interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */
#define portENTER_CRITICAL() vPortEnterCritical();
#define portEXIT_CRITICAL() vPortExitCritical();
#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 )
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vPortClearInterruptMask( x )
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
extern uint32_t ulPortSetInterruptMask( void );
extern void vPortClearInterruptMask( uint32_t ulNewMaskValue );
extern void vPortInstallFreeRTOSVectorTable( void );
/*
* These macros do not globally disable/enable interrupts. They do mask off
* interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY.
*/
#define portENTER_CRITICAL() vPortEnterCritical();
#define portEXIT_CRITICAL() vPortExitCritical();
#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 )
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vPortClearInterruptMask( x )
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
/*
* Task function macros as described on the FreeRTOS.org WEB site. These are
* not required for this port but included in case common demo code that uses these
* macros is used. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/* Prototype of the FreeRTOS tick handler. This must be installed as the
* handler for whichever peripheral is used to generate the RTOS tick. */
void FreeRTOS_Tick_Handler( void );
/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or left undefined) then tasks are
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 )
* macros is used.
*/
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*
* Prototype of the FreeRTOS tick handler. This must be installed as the
* handler for whichever peripheral is used to generate the RTOS tick.
*/
void FreeRTOS_Tick_Handler( void );
/*
* If configUSE_TASK_FPU_SUPPORT is set to 1, then tasks are created without an
* FPU context and must call vPortTaskUsesFPU() to allocate an FPU context
* prior to any FPU instructions. If configUSE_TASK_FPU_SUPPORT is set to 2,
* then all tasks have an FPU context allocated by default.
*/
#if ( configUSE_TASK_FPU_SUPPORT == 1 )
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 portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
#elif ( configUSE_TASK_FPU_SUPPORT == 2 )
/*
* Each task has an FPU context already, so define this function away to
* prevent it being called accidentally.
*/
#define vPortTaskUsesFPU()
#define portTASK_USES_FLOATING_POINT()
#endif /* configUSE_TASK_FPU_SUPPORT */
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
#define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )
#define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL )
#define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )
#define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL )
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( uxReadyPriorities ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif /* configASSERT */
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( uxReadyPriorities ) )
#define portNOP() __asm volatile ( "NOP" )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif /* configASSERT */
#ifdef __cplusplus
} /* extern C */
#endif
#define portNOP() __asm volatile ( "NOP" )
/* The number of bits to shift for an interrupt priority is dependent on the
* number of bits implemented by the interrupt controller. */
#if configUNIQUE_INTERRUPT_PRIORITIES == 16
#define portPRIORITY_SHIFT 4
#define portMAX_BINARY_POINT_VALUE 3
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32
#define portPRIORITY_SHIFT 3
#define portMAX_BINARY_POINT_VALUE 2
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64
#define portPRIORITY_SHIFT 2
#define portMAX_BINARY_POINT_VALUE 1
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128
#define portPRIORITY_SHIFT 1
#define portMAX_BINARY_POINT_VALUE 0
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256
#define portPRIORITY_SHIFT 0
#define portMAX_BINARY_POINT_VALUE 0
#else /* if configUNIQUE_INTERRUPT_PRIORITIES == 16 */
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
#endif /* if configUNIQUE_INTERRUPT_PRIORITIES == 16 */
/*
* The number of bits to shift for an interrupt priority is dependent on the
* number of bits implemented by the interrupt controller.
*/
#if configUNIQUE_INTERRUPT_PRIORITIES == 16
#define portPRIORITY_SHIFT 4
#define portMAX_BINARY_POINT_VALUE 3
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32
#define portPRIORITY_SHIFT 3
#define portMAX_BINARY_POINT_VALUE 2
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64
#define portPRIORITY_SHIFT 2
#define portMAX_BINARY_POINT_VALUE 1
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128
#define portPRIORITY_SHIFT 1
#define portMAX_BINARY_POINT_VALUE 0
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256
#define portPRIORITY_SHIFT 0
#define portMAX_BINARY_POINT_VALUE 0
#else /* if configUNIQUE_INTERRUPT_PRIORITIES == 16 */
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
#endif /* if configUNIQUE_INTERRUPT_PRIORITIES == 16 */
/* Interrupt controller access addresses. */
#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )
#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )
#define portICCBPR_BINARY_POINT_OFFSET ( 0x08 )
#define portICCRPR_RUNNING_PRIORITY_OFFSET ( 0x14 )
#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )
#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )
#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )
#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )
#define portICCBPR_BINARY_POINT_OFFSET ( 0x08 )
#define portICCRPR_RUNNING_PRIORITY_OFFSET ( 0x14 )
#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )
#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )
#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
/* *INDENT-OFF* */
#ifdef __cplusplus
} /* extern C */
#endif
/* *INDENT-ON* */
#endif /* PORTMACRO_H */

Loading…
Cancel
Save