blob: b964d900e7d5b58654db8c3a4fb2162f1cb646d9 [file]
/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
/* This port uses xTaskGetCurrentTaskHandle to get TCB stack, it is required to enable this API. */
#if ( ( INCLUDE_xTaskGetCurrentTaskHandle != 1 ) && ( configNUMBER_OF_CORES == 1 ) )
#error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 in single core.
#endif
/***********************************************************
* Macro definitions
***********************************************************/
/* Hardware specific macros */
#define portPSW_REGISTER_ID ( 5 )
#define portFPSR_REGISTER_ID ( 6 )
#define portFXSR_REGISTER_ID ( 6 )
#define portFXSR_REGISTER_SEL ( 10 )
/* PSW.EBV and PSW.CUx bits are kept as current status */
#define portINITIAL_PSW_MASK ( 0x00078000 )
#define portCURRENT_PSW_VALUE ( portSTSR( portPSW_REGISTER_ID, portREGISTER_SEL_0 ) )
#define portCURRENT_SR_ZERO_VALUE ( ( StackType_t ) 0x00000000 )
#define portCURRENT_FPSR_VALUE ( portSTSR( portFPSR_REGISTER_ID, portREGISTER_SEL_0 ) )
#define portCURRENT_FXSR_VALUE ( portSTSR( portFXSR_REGISTER_ID, portFXSR_REGISTER_SEL ) )
/* Mask for FPU configuration bits (FN, PEM, RM, FS) */
#define portINITIAL_FPSR_MASK ( 0x00ae0000 )
#define portINITIAL_FXSR_MASK ( 0x00ee0000 )
#define portPSW_ID_MASK ( 0x00000020 )
/* Define necessary hardware IO for OSTM timer.
* - OSTM0 is used by default for device variant U2Bx.
* - OSTM1 is used by default for device variant U2Ax.
* If it conflicts with the application, the application should implement another timer. */
#if ( configDEVICE_NAME == U2Bx_DEVICES )
#define portOSTM_EIC_ADDR ( 0xfff802d0 )
#define portOSTMCMP_ADDR ( 0xffbf0000 )
#define portOSTMCTL_ADDR ( 0xffbf0020 )
#define portOSTMTS_ADDR ( 0xffbf0014 )
#elif ( configDEVICE_NAME == U2Ax_DEVICES )
#define portOSTM_EIC_ADDR ( 0xfff80190 )
#define portOSTMCMP_ADDR ( 0xffbf0100 )
#define portOSTMCTL_ADDR ( 0xffbf0120 )
#define portOSTMTS_ADDR ( 0xffbf0114 )
#endif
#if ( configNUMBER_OF_CORES > 1 )
#define portIPI1ENS_REGISTER ( *( ( volatile uint32_t * ) 0xfffb9020UL ) )
#define portIPI1FLGS_REGISTER ( *( ( volatile uint32_t * ) 0xfffb9024UL ) )
#define portIPI1FCLRS_REGISTER ( *( ( volatile uint32_t * ) 0xfffb9028UL ) )
#define portIPI1REQS_REGISTER ( *( ( volatile uint32_t * ) 0xfffb9030UL ) )
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
/* Macros required to set up the initial stack. */
#define portSTACK_INITIAL_VALUE_R1 ( ( StackType_t ) 0x01010101 )
#define portSTACK_INITIAL_VALUE_R2 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x02 )
#define portSTACK_INITIAL_VALUE_R3 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x03 )
#define portSTACK_INITIAL_VALUE_R4 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x04 )
#define portSTACK_INITIAL_VALUE_R5 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x05 )
#define portSTACK_INITIAL_VALUE_R6 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x06 )
#define portSTACK_INITIAL_VALUE_R7 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x07 )
#define portSTACK_INITIAL_VALUE_R8 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x08 )
#define portSTACK_INITIAL_VALUE_R9 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x09 )
#define portSTACK_INITIAL_VALUE_R10 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x10 )
#define portSTACK_INITIAL_VALUE_R11 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x11 )
#define portSTACK_INITIAL_VALUE_R12 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x12 )
#define portSTACK_INITIAL_VALUE_R13 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x13 )
#define portSTACK_INITIAL_VALUE_R14 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x14 )
#define portSTACK_INITIAL_VALUE_R15 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x15 )
#define portSTACK_INITIAL_VALUE_R16 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x16 )
#define portSTACK_INITIAL_VALUE_R17 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x17 )
#define portSTACK_INITIAL_VALUE_R18 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x18 )
#define portSTACK_INITIAL_VALUE_R19 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x19 )
#define portSTACK_INITIAL_VALUE_R20 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x20 )
#define portSTACK_INITIAL_VALUE_R21 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x21 )
#define portSTACK_INITIAL_VALUE_R22 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x22 )
#define portSTACK_INITIAL_VALUE_R23 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x23 )
#define portSTACK_INITIAL_VALUE_R24 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x24 )
#define portSTACK_INITIAL_VALUE_R25 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x25 )
#define portSTACK_INITIAL_VALUE_R26 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x26 )
#define portSTACK_INITIAL_VALUE_R27 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x27 )
#define portSTACK_INITIAL_VALUE_R28 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x28 )
#define portSTACK_INITIAL_VALUE_R29 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x29 )
#define portSTACK_INITIAL_VALUE_R30 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x30 )
/***********************************************************
* Typedef definitions
***********************************************************/
/* OSTM Count Start Trigger Register (OSTMnTS) */
#define portOSTM_COUNTER_START ( 0x01U ) /* Starts the counter */
/* OSTM Count Stop Trigger Register (OSTMnTT) */
#define portOSTM_COUNTER_STOP ( 0x01U ) /* Stops the counter */
/* OSTM Control Register (OSTMnCTL) */
#define portOSTM_MODE_INTERVAL_TIMER ( 0x00U )
#define portOSTM_MODE_FREE_RUNNING ( 0x02U )
/* Disables or Enable the interrupts when counting starts */
#define portOSTM_START_INTERRUPT_DISABLE ( 0x00U )
#define portOSTM_START_INTERRUPT_ENABLE ( 0x01U )
/* Enable OSTM Interrupt*/
#define portOSTM_INTERRUPT_ENABLE ( 0x80U )
/* Interrupt vector method select (TBxxx) */
#define portINT_DIRECT_VECTOR ( 0x00U )
#define portINT_TABLE_VECTOR ( 0x40U )
/* Macros indicatings status of scheduler request */
#define PORT_SCHEDULER_NOREQUEST 0UL
#define PORT_SCHEDULER_TASKSWITCH 1UL /* Do not modify */
#define PORT_SCHEDULER_STARTFIRSTTASK 2UL /* Do not modify */
#ifndef configSETUP_TICK_INTERRUPT
/* The user has not provided their own tick interrupt configuration so use
* the definition in this file (which uses the interval timer). */
#define configSETUP_TICK_INTERRUPT() prvSetupTimerInterrupt()
#endif /* configSETUP_TICK_INTERRUPT */
#if ( !defined( configMAX_INT_NESTING ) || ( configMAX_INT_NESTING == 0 ) )
/* Set the default value for depth of nested interrupt. In theory, the
* microcontroller have mechanism to limit number of nested level of interrupt
* by priority (maximum 16 levels). However, the large stack memory should be
* prepared for each task to save resource in interrupt handler. Therefore, it
* is necessary to limit depth of nesting interrupt to optimize memory usage.
* In addition, the execution time of interrupt handler should be very short
* (typically not exceed 20us), this constraint does not impact to system.
*/
#define configMAX_INT_NESTING 2UL
#endif
/*
* Used to catch tasks that attempt to return from their implementing function.
*/
static void prvTaskExitError( void );
/*
* Sets up the periodic ISR used for the RTOS tick using the OSTM.
* The application writer can define configSETUP_TICK_INTERRUPT() (in
* FreeRTOSConfig.h) such that their own tick interrupt configuration is used
* in place of prvSetupTimerInterrupt().
*/
static void prvSetupTimerInterrupt( void );
/*
* Function to start the first task executing
*/
extern void vPortStartFirstTask( void );
/* Scheduler request on each cores which are starting first task and switching context */
volatile BaseType_t xPortScheduleStatus[ configNUMBER_OF_CORES ] = { 0 };
/* Counts the interrupt nesting depth. A context switch is only performed if
* the nesting depth is 0. In addition, the interrupt shares same stack allocated
* for each tasks. With supporting nesting interrupt, the stack may be overflowed.
* It is necessary to control maximum stack depth.
*/
volatile UBaseType_t uxInterruptNesting[ configNUMBER_OF_CORES ] = { 0 };
volatile const UBaseType_t uxPortMaxInterruptDepth = configMAX_INT_NESTING;
/* Count number of nested locks by same cores. The lock is completely released
* only if this count is decreased to 0, the lock is separated for task and isr */
UBaseType_t uxLockNesting[ configNUMBER_OF_CORES ][ 2 ] = { 0 };
/* Interrupt handler for OSTM timer which handling tick increment and resulting
* to switch context. */
void vPortTickISR( void );
#if ( configNUMBER_OF_CORES > 1 )
/* Yield specific cores by send inter-processor interrupt */
void vPortYieldCore( uint32_t xCoreID );
/*
* Functions implement spin-lock between cores by atomic accesses to Exclusive
* Control. There are separated access path between CPU cores,
* but they should wait if access to same register
*/
static void prvExclusiveLock( BaseType_t xFromIsr );
static void prvExclusiveRelease( BaseType_t xFromIsr );
/*
* Inter-processos interrupt handler. The interrupt is triggered by portYIELD_CORE().
*/
void vPortIPIHander( void );
void vPortIPIRClearRequest( void );
/* These below functions implement recursive spinlock for exclusive access among
* cores. The core will wait until lock will be available, whilst the core which
* already had lock can acquire lock without waiting. This function could be
* call from task and interrupt context, the critical section is called as in ISR */
void vPortRecursiveLockAcquire( BaseType_t xCoreID, BaseType_t xFromIsr );
void vPortRecursiveLockRelease( BaseType_t xCoreID, BaseType_t xFromIsr );
#endif /* (configNUMBER_OF_CORES > 1) */
/*-----------------------------------------------------------*/
/*
* These below functions implement interrupt mask from interrupt. They are not
* called in nesting, it is protected by FreeRTOS kernel.
*/
portLONG xPortSetInterruptMask( void )
{
portLONG ulPSWValue = portSTSR( portPSW_REGISTER_ID, portREGISTER_SEL_0 );
portDISABLE_INTERRUPTS();
/* It returns current value of Program Status Word register */
return ulPSWValue;
}
/*-----------------------------------------------------------*/
void vPortClearInterruptMask( portLONG uxSavedInterruptStatus )
{
portLONG ulPSWValue = portSTSR( portPSW_REGISTER_ID, portREGISTER_SEL_0 );
/* Interrupt Disable status is indicates by bit#5 of PSW
* (1: Interrupt is disabled; 0: Interrupt is enabled) */
/* Revert to the status before interrupt mask. */
ulPSWValue &= ( ~( portPSW_ID_MASK ) );
ulPSWValue |= ( portPSW_ID_MASK & uxSavedInterruptStatus );
portLDSR( portPSW_REGISTER_ID, portREGISTER_SEL_0, ulPSWValue );
}
/*-----------------------------------------------------------*/
/*
* Using CC-RH intrinsic function to get PEID (regID, selID) = (0,2)
* Core ID is indicates by bits PEID.PEID.
*/
BaseType_t xPortGET_CORE_ID( void )
{
#if ( configNUMBER_OF_CORES > 1 )
return( portSTSR( 0, 2 ) ); /* Get PEID value */
#else
/* In single core, xPortGET_CORE_ID is used in this port only. The dummy
* core ID could be controlled inside this port. */
return 0;
#endif
}
/*-----------------------------------------------------------*/
/*
* This port supports both multi-cores and single-core, whilst TCB stack
* variables are different which are respectively pxCurrentTCB (single-core)
* and pxCurrentTCBs[] (multiple-cores). This function is defined to obtains
* TCBs of current cores. Also, the C function could switch to corresponding
* pointer by pre-compile conditions.
*/
void * pvPortGetCurrentTCB( void )
{
void * pvCurrentTCB = ( void * ) xTaskGetCurrentTaskHandle();
configASSERT( pvCurrentTCB != NULL );
return pvCurrentTCB;
}
/*-----------------------------------------------------------*/
/*
* This function checks if a context switch is required and, if so, updates
* the scheduler status for the core on which the function is called. The
* scheduler status is set to indicate that a task switch should occur.
*/
void vPortSetSwitch( BaseType_t xSwitchRequired )
{
if( xSwitchRequired != pdFALSE )
{
xPortScheduleStatus[ xPortGET_CORE_ID() ] = PORT_SCHEDULER_TASKSWITCH;
}
}
/*-----------------------------------------------------------*/
/*
* Setup the stack of a new task so it is ready to be placed under the
* scheduler control. The registers have to be placed on the stack in the
* order that the port expects to find them.
*
* @param[in] pxTopOfStack Pointer to top of this task's stack
* @param[in] pxCode Task function, stored as initial PC for the task
* @param[in] pvParameters Parameters for task
*/
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
TaskFunction_t pxCode,
void * pvParameters )
{
/* Simulate the stack frame as it would be created by a context switch interrupt. */
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* R31 (LP) */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R5; /* R5 (TP) */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pvParameters; /* R6 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R7; /* R7 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R8; /* R8 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R9; /* R9 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R10; /* R10 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R11; /* R11 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R12; /* R12 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R13; /* R13 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R14; /* R14 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R15; /* R15 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R16; /* R16 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R17; /* R17 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R18; /* R18 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R19; /* R19 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R20; /* R20 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R21; /* R21 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R22; /* R22 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R23; /* R23 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R24; /* R24 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R25; /* R25 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R26; /* R26 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R27; /* R27 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R28; /* R28 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R29; /* R29 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R30; /* R30 (EP) */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R1; /* R1 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R2; /* R2 */
pxTopOfStack--;
/* Keep System pre-configuration (HV, CUx, EBV) as current setting in PSW register */
*pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* EIPSW */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pxCode; /* EIPC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* EIIC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* CTPSW */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* CTPC */
/* if FPU is enabled, initialize the FPU registers in Stack */
#if ( configENABLE_FPU == 1 )
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) ( portCURRENT_FPSR_VALUE & portINITIAL_FPSR_MASK ); /* FPSR */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FPEPC */
#endif /* (configENABLE_FPU == 1) */
/* if FXU is enabled, initialize the FXU registers in Stack */
#if ( configENABLE_FXU == 1 )
/* FXU Unit is available in PE0 only */
if( 0 == xPortGET_CORE_ID() )
{
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) ( portCURRENT_FXSR_VALUE & portINITIAL_FXSR_MASK ); /* FXSR */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FXXP */
}
else
{
/* Do nothing */
}
#endif /* (configENABLE_FXU == 1) */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
/*
* Configures the tick frequency and starts the first task.
*/
BaseType_t xPortStartScheduler( void )
{
#if ( configNUMBER_OF_CORES > 1 )
BaseType_t xCurrentCore = xPortGET_CORE_ID();
#endif
/* Prevent interrupt by timer interrupt during starting first task. The
* interrupt shall be enabled automatically by being restored from task stack */
portDISABLE_INTERRUPTS();
/* Setup the tick interrupt */
configSETUP_TICK_INTERRUPT();
#if ( configNUMBER_OF_CORES > 1 )
/* Start scheduler on other cores */
for( uint16_t xCoreID = 0; xCoreID < configNUMBER_OF_CORES; xCoreID++ )
{
if( xCoreID != xCurrentCore )
{
/* Send yielding request to other cores with flag to start
* first task. TaskContextSwitch is not executed */
xPortScheduleStatus[ xCoreID ] = PORT_SCHEDULER_STARTFIRSTTASK;
vPortYieldCore( xCoreID );
}
else
{
/* Nothing to do. The first task is started in this call by
* below vPortStartFirstTask() */
xPortScheduleStatus[ xCoreID ] = PORT_SCHEDULER_NOREQUEST;
}
}
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
/* Start first task in primary core */
vPortStartFirstTask();
/* Should never get here as the tasks will now be executing! */
prvTaskExitError();
/* To prevent compiler warnings in the case that the application writer
* overrides this functionality by defining configTASK_RETURN_ADDRESS.
* Call vTaskSwitchContext() so link time optimization does not remove
* the symbol. */
vTaskSwitchContext(
#if ( configNUMBER_OF_CORES > 1 )
xCurrentCore
#endif
);
return pdFALSE;
}
/*-----------------------------------------------------------*/
/*
* Used to catch tasks that attempt to return from their implementing function.
*/
static void prvTaskExitError( void )
{
/* 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. */
/* This statement will always fail, triggering the assert */
configASSERT( pdFALSE );
/*
* The following statement may be unreachable because configASSERT(pdFALSE)
* always triggers an assertion failure, which typically halts program execution.
* The warning may be reported to indicate to indicate that the compiler
* detects the subsequent code will not be executed. The warning is acceptable
* to ensure program is halt regardless of configASSERT(pdFALSE) implementation
*/
portDISABLE_INTERRUPTS();
for( ; ; )
{
/* Infinite loop to ensure the function does not return. */
}
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Not implemented in ports where there is nothing to return to.
* Artificially force an assert. */
configASSERT( pdFALSE );
}
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES > 1 )
void vPortIPIRClearRequest( void )
{
uint8_t IPInFLGValue = portIPI1FLGS_REGISTER;
/* Clear IPI requests from requested PEs*/
portIPI1FCLRS_REGISTER = IPInFLGValue;
}
void vPortYieldCore( uint32_t xCoreID )
{
/* Check if we need to yield on a different core */
if( xCoreID != xPortGET_CORE_ID() )
{
/*Inter-processor interrupt generates an interrupt request by
* writing the corresponding to applicable bits of PEs. The interrupt
* should be enabled by application in corresponding cores
* including PSW.ID (EI instruction) and interrupt control setting
* for ICIPIRn channel (interrupt mask, vector method)
*/
portIPI1REQS_REGISTER |= ( 1 << xCoreID );
}
else
{
/* Yielding current core */
vPortYield();
}
}
/*-----------------------------------------------------------*/
/*
* Handler for inter-processos interrupt in second cores. The interrupt is
* triggered by portYIELD_CORE(). vTaskSwitchContext() is invoked to switch tasks
*/
void vPortIPIHander( void )
{
/* In case of multicores with SMP, xTaskIncrementTick is required to
* called in critical section to avoid conflict resource as this function
* could be called by xTaskResumeAll() from any cores. */
#if ( configNUMBER_OF_CORES > 1 )
BaseType_t xSavedInterruptStatus;
xSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
#endif
{
BaseType_t xCurrentCore = xPortGET_CORE_ID();
/* 1st execution starts 1st task, TaskSwitchContext is not executed */
if( PORT_SCHEDULER_STARTFIRSTTASK != xPortScheduleStatus[ xCurrentCore ] )
{
xPortScheduleStatus[ xCurrentCore ] = PORT_SCHEDULER_TASKSWITCH;
}
vPortIPIRClearRequest();
}
#if ( configNUMBER_OF_CORES > 1 )
portEXIT_CRITICAL_FROM_ISR( xSavedInterruptStatus );
#endif
}
/*-----------------------------------------------------------*/
#endif /* (configNUMBER_OF_CORES > 1) */
void vPortTickISR( void )
{
/* In case of multicores with SMP, xTaskIncrementTick is required to
* called in critical section to avoid conflict resource as this function
* could be called by xTaskResumeAll() from any cores. */
#if ( configNUMBER_OF_CORES > 1 )
BaseType_t xSavedInterruptStatus;
xSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
#endif
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* Pend a context switch. */
xPortScheduleStatus[ xPortGET_CORE_ID() ] = PORT_SCHEDULER_TASKSWITCH;
}
}
#if ( configNUMBER_OF_CORES > 1 )
portEXIT_CRITICAL_FROM_ISR( xSavedInterruptStatus );
#endif
}
/*-----------------------------------------------------------*/
static void prvSetupTimerInterrupt( void )
{
volatile uint32_t * pulOSTMIntReg;
/* Interrupt configuration for OSTM Timer*/
pulOSTMIntReg = ( volatile uint32_t * ) portOSTM_EIC_ADDR;
*pulOSTMIntReg = ( portINT_TABLE_VECTOR | configTIMER_INT_PRIORITY );
/* Set OSTM0 control setting */
*( ( volatile uint32_t * ) portOSTMCTL_ADDR ) = ( portOSTM_INTERRUPT_ENABLE | portOSTM_MODE_INTERVAL_TIMER | portOSTM_START_INTERRUPT_DISABLE );
*( ( volatile uint32_t * ) portOSTMCMP_ADDR ) = ( ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) ) - 1;
/* Enable OSTM0 operation */
*( ( volatile uint32_t * ) portOSTMTS_ADDR ) = portOSTM_COUNTER_START;
}
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES > 1 )
/*
* These functions implement spin-lock mechanism among cores using hardware
* exclusive control with atomic access by CLR1 and SET1 instruction.
* Nesting calls to these APIs are possible.
*/
#pragma inline_asm prvExclusiveLock
static void prvExclusiveLock( BaseType_t xBitPosition )
{
/* No problem with r20, CCRH does not required to restore same value
* before and after function call. */
push r20
mov # __s.mev_address.bss, r20
/* r6 is xBitPosition */
Lock: set1 r6, [ r20 ]
bz Lock_success
snooze
br Lock
Lock_success:
pop r20
}
/*-----------------------------------------------------------*/
#pragma inline_asm prvExclusiveRelease
static void prvExclusiveRelease( BaseType_t xBitPosition )
{
push r20
mov # __s.mev_address.bss, r20
/* r6 is xBitPosition */
clr1 r6, [ r20 ]
pop r20
}
/*-----------------------------------------------------------*/
void vPortRecursiveLockAcquire( BaseType_t xCoreID, BaseType_t xFromIsr )
{
BaseType_t xSavedInterruptStatus;
BaseType_t xBitPosition = ( xFromIsr == pdTRUE );
xSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
if( uxLockNesting[ xCoreID ][ xBitPosition ] == 0 )
{
prvExclusiveLock( xBitPosition );
}
uxLockNesting[ xCoreID ][ xBitPosition ]++;
portCLEAR_INTERRUPT_MASK_FROM_ISR( xSavedInterruptStatus );
}
void vPortRecursiveLockRelease( BaseType_t xCoreID, BaseType_t xFromIsr )
{
BaseType_t xSavedInterruptStatus;
BaseType_t xBitPosition = ( xFromIsr == pdTRUE );
xSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
/* Sync memory */
portSYNCM();
/* Error check whether vPortRecursiveLockRelease() is not called in
* pair with vPortRecursiveLockAcquire() */
configASSERT( ( uxLockNesting[ xCoreID ][ xBitPosition ] > 0 ) );
uxLockNesting[ xCoreID ][ xBitPosition ]--;
if( uxLockNesting[ xCoreID ][ xBitPosition ] == 0 )
{
prvExclusiveRelease( xBitPosition );
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( xSavedInterruptStatus );
}
/*-----------------------------------------------------------*/
#endif /* (configNUMBER_OF_CORES > 1) */