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>
diff --git a/portable/GCC/ARM_CR5/port.c b/portable/GCC/ARM_CR5/port.c
index 8a9839c..0300782 100644
--- a/portable/GCC/ARM_CR5/port.c
+++ b/portable/GCC/ARM_CR5/port.c
@@ -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 @@
*/
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 @@
* 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 @@
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 @@
*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 @@
*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 @@
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 @@
}
/*-----------------------------------------------------------*/
-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 @@
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;
+ ucMaxPriorityValue >>= ( uint8_t ) 0x01;
- /* Determine how many priority bits are implemented in the GIC.
- *
- * Save the interrupt priority value that is about to be clobbered. */
- ulOriginalPriority = *pucFirstUserPriorityRegister;
+ /*
+ * If ulCycles reaches 0 then ucMaxPriorityValue must have been
+ * read as 0, indicating a misconfiguration.
+ */
+ ulCycles--;
- /* 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 )
+ 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 @@
}
}
- /* 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 @@
/* 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 @@
{
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 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 @@
}
/*-----------------------------------------------------------*/
-#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 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 @@
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 @@
* 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 @@
*
* 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 );
}
diff --git a/portable/GCC/ARM_CR5/portASM.S b/portable/GCC/ARM_CR5/portASM.S
index c44ea6b..c331057 100644
--- a/portable/GCC/ARM_CR5/portASM.S
+++ b/portable/GCC/ARM_CR5/portASM.S
@@ -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
+ #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 {D16-D31}*/
- VPOPNE {D0-D15}
- VMSRNE FPSCR, R0
+ /* 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 @@
* 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 @@
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
diff --git a/portable/GCC/ARM_CR5/portmacro.h b/portable/GCC/ARM_CR5/portmacro.h
index 4bd25bb..ff7337d 100644
--- a/portable/GCC/ARM_CR5/portmacro.h
+++ b/portable/GCC/ARM_CR5/portmacro.h
@@ -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 );
+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 )
+/*
+ * 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 )
+ * 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 );
+/*
+ * 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 )
+/*
+ * 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 vPortTaskUsesFPU()
-#endif /* configUSE_TASK_FPU_SUPPORT */
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
+#elif ( configUSE_TASK_FPU_SUPPORT == 2 )
- #define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )
- #define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL )
+/*
+ * 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 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 ) )
+ #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( uxReadyPriorities ) )
- #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
+#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
- #ifdef configASSERT
- void vPortValidateInterruptPriority( void );
- #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
- #endif /* configASSERT */
+#ifdef configASSERT
+ void vPortValidateInterruptPriority( void );
+ #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
+#endif /* configASSERT */
- #define portNOP() __asm volatile ( "NOP" )
+#define portNOP() __asm volatile ( "NOP" )
- #ifdef __cplusplus
- } /* extern C */
- #endif
-
-
-/* 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 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 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 portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+ } /* extern C */
+#endif
+/* *INDENT-ON* */
#endif /* PORTMACRO_H */