From 7b26ea6263d795bd1090eac60d63a29080934f2f Mon Sep 17 00:00:00 2001 From: Paul Bartell Date: Mon, 6 Mar 2023 08:19:28 -0800 Subject: [PATCH] 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 --------- Signed-off-by: Gaurav Aggarwal Co-authored-by: Christos Zosimidis Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Co-authored-by: Gaurav Aggarwal --- portable/GCC/ARM_CR5/port.c | 311 ++++++++++++++++++++----------- portable/GCC/ARM_CR5/portASM.S | 86 +++++---- portable/GCC/ARM_CR5/portmacro.h | 250 +++++++++++++------------ 3 files changed, 385 insertions(+), 262 deletions(-) diff --git a/portable/GCC/ARM_CR5/port.c b/portable/GCC/ARM_CR5/port.c index 8a9839cde56..03007821967 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 @@ 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 ); } diff --git a/portable/GCC/ARM_CR5/portASM.S b/portable/GCC/ARM_CR5/portASM.S index c44ea6b7913..c331057d610 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 - - /* 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 diff --git a/portable/GCC/ARM_CR5/portmacro.h b/portable/GCC/ARM_CR5/portmacro.h index 4bd25bb048b..ff7337d1502 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 ); - -/* 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 */