Skip to content

Commit

Permalink
Enable building the GCC Cortex-R5 port without an FPU
Browse files Browse the repository at this point in the history
  • Loading branch information
paulbartell committed Nov 14, 2022
1 parent cd1f51c commit e46a8b7
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 91 deletions.
108 changes: 60 additions & 48 deletions portable/GCC/ARM_CR5/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@
#define portTASK_RETURN_ADDRESS prvTaskExitError
#endif

#if ( configUSE_TASK_FPU_SUPPORT != 0 )

/*
* The space on the stack required to hold the FPU registers.
*
Expand All @@ -160,7 +162,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 */

/*-----------------------------------------------------------*/

Expand All @@ -175,6 +178,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
Expand All @@ -194,7 +199,8 @@ 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 */

/*-----------------------------------------------------------*/

Expand All @@ -205,9 +211,12 @@ void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__((weak) );
* automatically be set to 0 when the first task is started. */
volatile uint32_t ulCriticalNesting = 9999UL;

#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;
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;
Expand Down Expand Up @@ -291,28 +300,28 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
* enabled. */
*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. */
* 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. */
* space for the registers - and ensure they are initialized to 0. */
pxTopOfStack -= portFPU_REGISTER_WORDS;
memset( pxTopOfStack, 0x00, portFPU_REGISTER_WORDS * sizeof( StackType_t ) );

pxTopOfStack--;
*pxTopOfStack = pdTRUE;
ulPortTaskHasFPUContext = pdTRUE;
}
#else
#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 */

Expand All @@ -337,58 +346,60 @@ 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 )
{
( void ) ulICCIAR;
configASSERT( ( volatile void * ) NULL );
}
#endif /* configUSE_TASK_FPU_SUPPORT != 0 */
/*-----------------------------------------------------------*/

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;
{
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 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;
/* 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;
/* 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 )
{
ucMaxPriorityValue >>= ( uint8_t ) 0x01;
/* Shift to the least significant bits. */
while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET )
{
ucMaxPriorityValue >>= ( uint8_t ) 0x01;

/* If ulCycles reaches 0 then ucMaxPriorityValue must have been
* read as 0, indicating a misconfiguration. */
ulCycles--;
/* If ulCycles reaches 0 then ucMaxPriorityValue must have been
* read as 0, indicating a misconfiguration. */
ulCycles--;

if( ulCycles == 0 )
{
break;
}
if( ulCycles == 0 )
{
break;
}
}

/* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
* value. */
configASSERT( ucMaxPriorityValue == portLOWEST_INTERRUPT_PRIORITY );
/* 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;
}
/* 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
Expand Down Expand Up @@ -426,6 +437,7 @@ BaseType_t xPortStartScheduler( void )
* warning about it being defined but not referenced in the case that the user
* defines their own exit address. */
( void ) prvTaskExitError;

return 0;
}
/*-----------------------------------------------------------*/
Expand Down Expand Up @@ -505,7 +517,7 @@ void FreeRTOS_Tick_Handler( void )
}
/*-----------------------------------------------------------*/

#if( configUSE_TASK_FPU_SUPPORT != 2 )
#if ( configUSE_TASK_FPU_SUPPORT == 1 )

void vPortTaskUsesFPU( void )
{
Expand All @@ -519,7 +531,7 @@ void FreeRTOS_Tick_Handler( void )
__asm volatile ( "FMXR FPSCR, %0" ::"r" ( ulInitialFPSCR ) : "memory" );
}

#endif /* configUSE_TASK_FPU_SUPPORT */
#endif /* configUSE_TASK_FPU_SUPPORT == 1 */
/*-----------------------------------------------------------*/

void vPortClearInterruptMask( uint32_t ulNewMaskValue )
Expand Down
67 changes: 38 additions & 29 deletions portable/GCC/ARM_CR5/portASM.S
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@
.extern vTaskSwitchContext
.extern vApplicationIRQHandler
.extern ulPortInterruptNesting

#if( configUSE_TASK_FPU_SUPPORT != 0 )
.extern ulPortTaskHasFPUContext
#endif /* configUSE_TASK_FPU_SUPPORT != 0 */

.global FreeRTOS_IRQ_Handler
.global FreeRTOS_SWI_Handler
Expand All @@ -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( configUSE_TASK_FPU_SUPPORT != 0 )
/* 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 /* configUSE_TASK_FPU_SUPPORT != 0 */

/* Save the stack pointer in the TCB. */
LDR R0, pxCurrentTCBConst
Expand All @@ -95,18 +99,19 @@
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( configUSE_TASK_FPU_SUPPORT != 0 )
/* 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 /* configUSE_TASK_FPU_SUPPORT != 0 */

/* Restore the critical section nesting depth. */
LDR R0, ulCriticalNestingConst
Expand All @@ -132,8 +137,6 @@
.endm




/******************************************************************************
* SVC handler is used to start the scheduler.
*****************************************************************************/
Expand Down Expand Up @@ -289,8 +292,10 @@ vApplicationIRQHandler:
VPUSH {D0-D15}
PUSH {R1}

LDR r1, vApplicationFPUSafeIRQHandlerConst
BLX r1
#if( configUSE_TASK_FPU_SUPPORT != 0 )
LDR r1, vApplicationFPUSafeIRQHandlerConst
BLX r1
#endif /* configUSE_TASK_FPU_SUPPORT != 0 */

POP {R0}
VPOP {D0-D15}
Expand All @@ -303,12 +308,16 @@ ulICCEOIRConst: .word ulICCEOIR
ulICCPMRConst: .word ulICCPMR
pxCurrentTCBConst: .word pxCurrentTCB
ulCriticalNestingConst: .word ulCriticalNesting
ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext

#if( configUSE_TASK_FPU_SUPPORT != 0 )
ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext
vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler
#endif /* configUSE_TASK_FPU_SUPPORT != 0 */

ulMaxAPIPriorityMaskConst: .word ulMaxAPIPriorityMask
vTaskSwitchContextConst: .word vTaskSwitchContext
vApplicationIRQHandlerConst: .word vApplicationIRQHandler
ulPortInterruptNestingConst: .word ulPortInterruptNesting
vApplicationFPUSafeIRQHandlerConst: .word vApplicationFPUSafeIRQHandler

.end

Expand Down
33 changes: 19 additions & 14 deletions portable/GCC/ARM_CR5/portmacro.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#define PORTMACRO_H

#ifdef __cplusplus
extern "C" {
extern "C" {
#endif

/*-----------------------------------------------------------
Expand Down Expand Up @@ -116,18 +116,23 @@
* 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 )
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 */
/*
* If configUSE_TASK_FPU_SUPPORT is set to 1 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 == 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()

#define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )
Expand Down Expand Up @@ -159,7 +164,7 @@ by default. */


#ifdef __cplusplus
} /* extern C */
} /* extern C */
#endif


Expand Down

0 comments on commit e46a8b7

Please sign in to comment.