2 * FreeRTOS Kernel V11.2.0
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * SPDX-License-Identifier: MIT
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
29 /* Scheduler includes. */
33 /* This port uses xTaskGetCurrentTaskHandle to get TCB stack, it is required to
35 #if ( ( INCLUDE_xTaskGetCurrentTaskHandle != 1 ) && ( configNUMBER_OF_CORES == 1 ) )
36 #error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 in single core.
39 /***********************************************************
41 ***********************************************************/
43 /* Hardware specific macros */
44 #define portPSW_REGISTER_ID ( 5 )
45 #define portFPSR_REGISTER_ID ( 6 )
47 /* PSW.EBV and PSW.CUx bits are kept as current status */
48 #define portINITIAL_PSW_MASK ( 0x000f8000 )
49 #define portCURRENT_PSW_VALUE ( portSTSR( portPSW_REGISTER_ID ) )
50 #define portCURRENT_SR_ZERO_VALUE ( ( StackType_t ) 0x00000000 )
51 #define portCURRENT_FPSR_VALUE ( portSTSR( portFPSR_REGISTER_ID ) )
53 /* Mask for FPU configuration bits (FN, PEM, RM, FS) */
54 #define portINITIAL_FPSR_MASK ( 0x00ae0000 )
55 #define portPSW_ID_MASK ( 0x00000020 )
57 /* Define necessary hardware IO for OSTM timer. OSTM0 is used by default as
58 * it is common for almost device variants. If it conflicts with application,
59 * the application shall implement another timer.*/
60 #define portOSTM_EIC_ADDR ( 0xFFFFB0A8 )
61 #define portOSTM0CMP_ADDR ( 0xFFD70000 )
62 #define portOSTM0CTL_ADDR ( 0xFFD70020 )
63 #define portOSTM0TS_ADDR ( 0xFFD70014 )
65 #if ( configNUMBER_OF_CORES > 1 )
67 /* IPIR base address, the peripheral is used for Inter-Processor communication
68 * Hardware supports 4 channels which is offset by 0x0, 0x4, 0x8, 0xC bytes from
69 * base address. By default, channel 0 is selected. */
70 #ifdef configIPIR_CHANNEL
71 #define portIPIR_BASE_ADDR ( ( 0xFFFEEC80 ) + ( configIPIR_CHANNEL << 2 ) )
73 #define portIPIR_BASE_ADDR ( 0xFFFEEC80 )
76 /* Address used for exclusive control for variable shared between PEs
77 * (common resources), each CPU cores have independent access path to
78 * this address. By default, G0MEV0 register is selected*/
79 #ifdef configEXCLUSIVE_ADDRESS
80 #define portMEV_BASE_ADDR configEXCLUSIVE_ADDRESS
82 #define portMEV_BASE_ADDR ( 0xFFFEEC00 )
84 #endif /* if ( configNUMBER_OF_CORES > 1 ) */
86 /* Macros required to set up the initial stack. */
87 #define portSTACK_INITIAL_VALUE_R1 ( ( StackType_t ) 0x01010101 )
88 #define portSTACK_INITIAL_VALUE_R2 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x02 )
89 #define portSTACK_INITIAL_VALUE_R3 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x03 )
90 #define portSTACK_INITIAL_VALUE_R4 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x04 )
91 #define portSTACK_INITIAL_VALUE_R5 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x05 )
92 #define portSTACK_INITIAL_VALUE_R6 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x06 )
93 #define portSTACK_INITIAL_VALUE_R7 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x07 )
94 #define portSTACK_INITIAL_VALUE_R8 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x08 )
95 #define portSTACK_INITIAL_VALUE_R9 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x09 )
96 #define portSTACK_INITIAL_VALUE_R10 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x10 )
97 #define portSTACK_INITIAL_VALUE_R11 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x11 )
98 #define portSTACK_INITIAL_VALUE_R12 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x12 )
99 #define portSTACK_INITIAL_VALUE_R13 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x13 )
100 #define portSTACK_INITIAL_VALUE_R14 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x14 )
101 #define portSTACK_INITIAL_VALUE_R15 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x15 )
102 #define portSTACK_INITIAL_VALUE_R16 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x16 )
103 #define portSTACK_INITIAL_VALUE_R17 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x17 )
104 #define portSTACK_INITIAL_VALUE_R18 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x18 )
105 #define portSTACK_INITIAL_VALUE_R19 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x19 )
106 #define portSTACK_INITIAL_VALUE_R20 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x20 )
107 #define portSTACK_INITIAL_VALUE_R21 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x21 )
108 #define portSTACK_INITIAL_VALUE_R22 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x22 )
109 #define portSTACK_INITIAL_VALUE_R23 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x23 )
110 #define portSTACK_INITIAL_VALUE_R24 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x24 )
111 #define portSTACK_INITIAL_VALUE_R25 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x25 )
112 #define portSTACK_INITIAL_VALUE_R26 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x26 )
113 #define portSTACK_INITIAL_VALUE_R27 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x27 )
114 #define portSTACK_INITIAL_VALUE_R28 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x28 )
115 #define portSTACK_INITIAL_VALUE_R29 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x29 )
116 #define portSTACK_INITIAL_VALUE_R30 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x30 )
118 /***********************************************************
119 * Typedef definitions
120 ***********************************************************/
122 /* OSTM Count Start Trigger Register (OSTMnTS) */
123 #define portOSTM_COUNTER_START ( 0x01U ) /* Starts the counter */
125 /* OSTM Count Stop Trigger Register (OSTMnTT) */
126 #define portOSTM_COUNTER_STOP ( 0x01U ) /* Stops the counter */
128 /* OSTM Control Register (OSTMnCTL) */
129 #define portOSTM_MODE_INTERVAL_TIMER ( 0x00U )
130 #define portOSTM_MODE_FREE_RUNNING ( 0x02U )
132 /* Disables or Enable the interrupts when counting starts */
133 #define portOSTM_START_INTERRUPT_DISABLE ( 0x00U )
134 #define portOSTM_START_INTERRUPT_ENABLE ( 0x01U )
136 /* Interrupt vector method select (TBxxx) */
137 #define portINT_DIRECT_VECTOR ( 0x0U )
138 #define portINT_TABLE_VECTOR ( 0x1U )
140 /* Interrupt mask (MKxxx) */
141 #define portINT_PROCESSING_ENABLED ( 0x0U )
142 #define portINT_PROCESSING_DISABLED ( 0x1U )
144 /* Specify 16 interrupt priority levels */
145 #define portINT_PRIORITY_HIGHEST ( 0x0000U ) /* Level 0 (highest) */
146 #define portINT_PRIORITY_LEVEL1 ( 0x0001U ) /* Level 1 */
147 #define portINT_PRIORITY_LEVEL2 ( 0x0002U ) /* Level 2 */
148 #define portINT_PRIORITY_LEVEL3 ( 0x0003U ) /* Level 3 */
149 #define portINT_PRIORITY_LEVEL4 ( 0x0004U ) /* Level 4 */
150 #define portINT_PRIORITY_LEVEL5 ( 0x0005U ) /* Level 5 */
151 #define portINT_PRIORITY_LEVEL6 ( 0x0006U ) /* Level 6 */
152 #define portINT_PRIORITY_LEVEL7 ( 0x0007U ) /* Level 7 */
153 #define portINT_PRIORITY_LEVEL8 ( 0x0008U ) /* Level 8 */
154 #define portINT_PRIORITY_LEVEL9 ( 0x0009U ) /* Level 9 */
155 #define portINT_PRIORITY_LEVEL10 ( 0x000AU ) /* Level 10 */
156 #define portINT_PRIORITY_LEVEL11 ( 0x000BU ) /* Level 11 */
157 #define portINT_PRIORITY_LEVEL12 ( 0x000CU ) /* Level 12 */
158 #define portINT_PRIORITY_LEVEL13 ( 0x000DU ) /* Level 13 */
159 #define portINT_PRIORITY_LEVEL14 ( 0x000EU ) /* Level 14 */
160 #define portINT_PRIORITY_LOWEST ( 0x000FU ) /* Level 15 (lowest) */
162 /* Macros indicating status of scheduler request */
163 #define PORT_SCHEDULER_NOREQUEST 0UL
164 #define PORT_SCHEDULER_TASKSWITCH 1UL /* Do not modify */
165 #define PORT_SCHEDULER_STARTFIRSTTASK 2UL /* Do not modify */
167 #ifndef configSETUP_TICK_INTERRUPT
169 /* The user has not provided their own tick interrupt configuration so use
170 * the definition in this file (which uses the interval timer). */
171 #define configSETUP_TICK_INTERRUPT() prvSetupTimerInterrupt()
172 #endif /* configSETUP_TICK_INTERRUPT */
174 #if ( !defined( configMAX_INT_NESTING ) || ( configMAX_INT_NESTING == 0 ) )
176 /* Set the default value for depth of nested interrupt. In theory, the
177 * microcontroller have mechanism to limit number of nested level of interrupt
178 * by priority (maximum 16 levels). However, the large stack memory should be
179 * prepared for each task to save resource in interrupt handler. Therefore, it
180 * is necessary to limit depth of nesting interrupt to optimize memory usage.
181 * In addition, the execution time of interrupt handler should be very short
182 * (typically not exceed 20us), this constraint does not impact to system.
184 #define configMAX_INT_NESTING 2UL
188 * Used to catch tasks that attempt to return from their implementing function.
190 static void prvTaskExitError( void );
193 * Sets up the periodic ISR used for the RTOS tick using the OSTM.
194 * The application writer can define configSETUP_TICK_INTERRUPT() (in
195 * FreeRTOSConfig.h) such that their own tick interrupt configuration is used
196 * in place of prvSetupTimerInterrupt().
198 static void prvSetupTimerInterrupt( void );
200 #if ( configNUMBER_OF_CORES > 1 )
203 * Functions implement spin-lock between cores by atomic accesses to Exclusive
204 * Control Register (G0MEVm). There are separated access path between CPU cores,
205 * but they should wait if access to same register
207 static void prvExclusiveLock( BaseType_t xFromIsr );
208 static void prvExclusiveRelease( BaseType_t xFromIsr );
213 * Function to start the first task executing
215 extern void vPortStartFirstTask( void );
217 /* Scheduler request on each cores which are starting first task and switching
219 volatile BaseType_t xPortScheduleStatus[ configNUMBER_OF_CORES ] = { 0 };
221 /* Counts the interrupt nesting depth. A context switch is only performed if
222 * the nesting depth is 0. In addition, the interrupt shares same stack
223 * allocated for each tasks. With supporting nesting interrupt, the stack
225 * It is necessary to control maximum stack depth.
227 volatile UBaseType_t uxInterruptNesting[ configNUMBER_OF_CORES ] = { 0 };
228 volatile const UBaseType_t uxPortMaxInterruptDepth = configMAX_INT_NESTING;
230 /* Count number of nested locks by same cores. The lock is completely released
231 * only if this count is decreased to 0, the lock is separated for task
233 UBaseType_t uxLockNesting[ configNUMBER_OF_CORES ][ 2 ] = { 0 };
235 #if ( configNUMBER_OF_CORES > 1 )
237 /* Pointer to exclusive access memory */
238 volatile BaseType_t * pxPortExclusiveReg = ( volatile BaseType_t * ) ( portMEV_BASE_ADDR );
241 /* Interrupt handler for OSTM timer which handling tick increment and resulting
242 * to switch context. */
243 void vPortTickISR( void );
245 #if ( configNUMBER_OF_CORES > 1 )
247 /* Yield specific cores by send inter-processor interrupt */
248 void vPortYieldCore( uint32_t xCoreID );
251 * Inter-processor interrupt handler. The interrupt is triggered by
254 void vPortIPIHander( void );
256 /* These functions below implement recursive spinlock for exclusive access among
257 * cores. The core will wait until lock will be available, whilst the core which
258 * already had lock can acquire lock without waiting. This function could be
259 * call from task and interrupt context, the critical section is called
261 void vPortRecursiveLockAcquire( BaseType_t xCoreID, BaseType_t xFromIsr );
262 void vPortRecursiveLockRelease( BaseType_t xCoreID, BaseType_t xFromIsr );
264 #endif /* (configNUMBER_OF_CORES > 1) */
266 /*-----------------------------------------------------------*/
269 * These below functions implement interrupt mask from interrupt. They are not
270 * called in nesting, it is protected by FreeRTOS kernel.
272 portLONG xPortSetInterruptMask( void )
274 portLONG ulPSWValue = portSTSR( portPSW_REGISTER_ID );
276 portDISABLE_INTERRUPTS();
278 /* It returns current value of Program Status Word register */
282 /*-----------------------------------------------------------*/
284 void vPortClearInterruptMask( portLONG uxSavedInterruptStatus )
286 portLONG ulPSWValue = portSTSR( portPSW_REGISTER_ID );
288 /* Interrupt Disable status is indicates by bit#5 of PSW
289 * (1: Interrupt is disabled; 0: Interrupt is enabled) */
291 /* Revert to the status before interrupt mask. */
292 ulPSWValue &= ( ~( portPSW_ID_MASK ) );
293 ulPSWValue |= ( portPSW_ID_MASK & uxSavedInterruptStatus );
294 portLDSR( portPSW_REGISTER_ID, ulPSWValue );
297 /*-----------------------------------------------------------*/
300 * Using CC-RH intrinsic function to get HTCFG0 (regID, selID) = (0,2)
301 * Core ID is indicates by bit HTCFG0.PEID located at bit 18 to 16
302 * Bit 31 to 19 are read only and always be read as 0. HTCFG0.PEID is 1 and 2
303 * corresponding to core 0 (PE1) and core 1 (PE2). It is adjusted to 0 and 1.
305 BaseType_t xPortGET_CORE_ID( void )
307 #if ( configNUMBER_OF_CORES > 1 )
308 return ( portSTSR_CCRH( 0, 2 ) >> 16 ) - 1;
311 /* In single core, xPortGET_CORE_ID is used in this port only.
312 * The dummy core ID could be controlled inside this port. */
317 /*-----------------------------------------------------------*/
320 * This port supports both multi-cores and single-core, whilst TCB stack
321 * variables are different which are respectively pxCurrentTCB (single-core)
322 * and pxCurrentTCBs[] (multiple-cores). This function is defined to obtains
323 * TCBs of current cores. Also, the C function could switch to corresponding
324 * pointer by pre-compile conditions.
326 void * pvPortGetCurrentTCB( void )
328 void * pvCurrentTCB = ( void * ) xTaskGetCurrentTaskHandle();
330 configASSERT( pvCurrentTCB != NULL );
335 /*-----------------------------------------------------------*/
338 * This function checks if a context switch is required and, if so, updates
339 * the scheduler status for the core on which the function is called. The
340 * scheduler status is set to indicate that a task switch should occur.
342 void vPortSetSwitch( BaseType_t xSwitchRequired )
344 if( xSwitchRequired != pdFALSE )
346 xPortScheduleStatus[ xPortGET_CORE_ID() ] = PORT_SCHEDULER_TASKSWITCH;
350 /*-----------------------------------------------------------*/
353 * Setup the stack of a new task so it is ready to be placed under the
354 * scheduler control. The registers have to be placed on the stack in the
355 * order that the port expects to find them.
357 * @param[in] pxTopOfStack Pointer to top of this task's stack
358 * @param[in] pxCode Task function, stored as initial PC for the task
359 * @param[in] pvParameters Parameters for task
361 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
362 TaskFunction_t pxCode,
363 void * pvParameters )
365 /* Simulate the stack frame as it would be created by
366 * a context switch interrupt. */
367 *pxTopOfStack = ( StackType_t ) prvTaskExitError; /* R31 (LP) */
369 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R5; /* R5 (TP) */
371 *pxTopOfStack = ( StackType_t ) pvParameters; /* R6 */
373 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R7; /* R7 */
375 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R8; /* R8 */
377 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R9; /* R9 */
379 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R10; /* R10 */
381 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R11; /* R11 */
383 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R12; /* R12 */
385 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R13; /* R13 */
387 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R14; /* R14 */
389 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R15; /* R15 */
391 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R16; /* R16 */
393 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R17; /* R17 */
395 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R18; /* R18 */
397 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R19; /* R19 */
399 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R20; /* R20 */
401 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R21; /* R21 */
403 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R22; /* R22 */
405 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R23; /* R23 */
407 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R24; /* R24 */
409 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R25; /* R25 */
411 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R26; /* R26 */
413 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R27; /* R27 */
415 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R28; /* R28 */
417 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R29; /* R29 */
419 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R30; /* R30 (EP) */
421 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R1; /* R1 */
423 *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R2; /* R2 */
427 /* Keep System pre-configuration (HV, CUx, EBV) as current setting in
429 *pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* EIPSW */
431 *pxTopOfStack = ( StackType_t ) pxCode; /* EIPC */
433 *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* EIIC */
435 *pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* CTPSW */
437 *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* CTPC */
439 /* __FPU is defined by CCRH compiler if FPU is enabled */
440 #if ( configENABLE_FPU == 1 )
442 *pxTopOfStack = ( StackType_t ) ( portCURRENT_FPSR_VALUE & portINITIAL_FPSR_MASK ); /* FPSR */
444 *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FPEPC */
445 #endif /* (configENABLE_FPU == 1) */
450 /*-----------------------------------------------------------*/
453 * Configures the tick frequency and starts the first task.
455 BaseType_t xPortStartScheduler( void )
457 #if ( configNUMBER_OF_CORES > 1 )
458 BaseType_t xCurrentCore = xPortGET_CORE_ID();
461 /* Prevent interrupt by timer interrupt during starting first task.
462 * The interrupt shall be enabled automatically by being restored from
464 portDISABLE_INTERRUPTS();
466 /* Setup the tick interrupt */
467 configSETUP_TICK_INTERRUPT();
469 #if ( configNUMBER_OF_CORES > 1 )
470 /* Start scheduler on other cores */
471 for( uint16_t xCoreID = 0; xCoreID < configNUMBER_OF_CORES; xCoreID++ )
473 if( xCoreID != xCurrentCore )
475 /* Send yielding request to other cores with flag to start
476 * first task. TaskContextSwitch is not executed */
477 xPortScheduleStatus[ xCoreID ] = PORT_SCHEDULER_STARTFIRSTTASK;
478 vPortYieldCore( xCoreID );
482 /* Nothing to do. The first task is started in this call by
483 * below vPortStartFirstTask() */
484 xPortScheduleStatus[ xCoreID ] = PORT_SCHEDULER_NOREQUEST;
487 #endif /* if ( configNUMBER_OF_CORES > 1 ) */
489 /* Start first task in primary core */
490 vPortStartFirstTask();
492 /* Should never get here as the tasks will now be executing! */
495 /* To prevent compiler warnings in the case that the application writer
496 * overrides this functionality by defining configTASK_RETURN_ADDRESS.
497 * Call vTaskSwitchContext() so link time optimization does not remove
500 #if ( configNUMBER_OF_CORES > 1 )
508 /*-----------------------------------------------------------*/
511 * Used to catch tasks that attempt to return from their implementing function.
513 static void prvTaskExitError( void )
515 /* A function that implements a task must not exit or attempt to return to
516 * its caller as there is nothing to return to. If a task wants to exit it
517 * should instead call vTaskDelete( NULL ).
519 * Artificially force an assert() to be triggered if configASSERT() is
520 * defined, then stop here so application writers can catch the error. */
522 /* This statement will always fail, triggering the assert */
523 configASSERT( pdFALSE );
526 * The following statement may be unreachable because configASSERT(pdFALSE)
527 * always triggers an assertion failure, which typically halts program
529 * The warning may be reported to indicate to indicate that the compiler
530 * detects the subsequent code will not be executed.
531 * The warning is acceptable to ensure program is halt regardless of
532 * configASSERT(pdFALSE) implementation
534 portDISABLE_INTERRUPTS();
538 /* Infinite loop to ensure the function does not return. */
542 /*-----------------------------------------------------------*/
544 void vPortEndScheduler( void )
546 /* Not implemented in ports where there is nothing to return to.
547 * Artificially force an assert. */
548 configASSERT( pdFALSE );
551 /*-----------------------------------------------------------*/
553 #if ( configNUMBER_OF_CORES > 1 )
555 void vPortYieldCore( uint32_t xCoreID )
557 /* Check if we need to yield on a different core */
558 if( xCoreID != xPortGET_CORE_ID() )
560 volatile uint32_t * pulIPIRReg;
562 /* Determine the IPI register based on the target core ID */
563 pulIPIRReg = ( volatile uint32_t * ) ( portIPIR_BASE_ADDR );
565 /*Inter-processor interrupt generates an interrupt request by
566 * writing 1 to applicable bits of target cores. The interrupt
567 * should be enabled by application in corresponding cores
568 * including PSW.ID (EI instruction) and interrupt control setting
569 * for ICIPIRn channel (interrupt mask, vector method)
571 *pulIPIRReg = ( 1 << xCoreID );
575 /* Yielding current core */
580 /*-----------------------------------------------------------*/
583 * Handler for inter-processor interrupt in second cores. The interrupt is
584 * triggered by portYIELD_CORE(). vTaskSwitchContext() is invoked to
587 void vPortIPIHander( void )
589 BaseType_t xCurrentCore = xPortGET_CORE_ID();
591 /* 1st execution starts 1st task, TaskSwitchContext is not executed */
592 if( PORT_SCHEDULER_STARTFIRSTTASK != xPortScheduleStatus[ xCurrentCore ] )
594 xPortScheduleStatus[ xCurrentCore ] = PORT_SCHEDULER_TASKSWITCH;
598 /*-----------------------------------------------------------*/
600 #endif /* (configNUMBER_OF_CORES > 1) */
602 void vPortTickISR( void )
604 /* In case of multicores with SMP, xTaskIncrementTick is required to
605 * called in critical section to avoid conflict resource as this function
606 * could be called by xTaskResumeAll() from any cores. */
607 #if ( configNUMBER_OF_CORES > 1 )
608 BaseType_t xSavedInterruptStatus;
610 xSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR();
613 /* Increment the RTOS tick. */
614 if( xTaskIncrementTick() != pdFALSE )
616 /* Pend a context switch. */
617 xPortScheduleStatus[ xPortGET_CORE_ID() ] = PORT_SCHEDULER_TASKSWITCH;
620 #if ( configNUMBER_OF_CORES > 1 )
621 portEXIT_CRITICAL_FROM_ISR( xSavedInterruptStatus );
625 /*-----------------------------------------------------------*/
627 static void prvSetupTimerInterrupt( void )
629 volatile uint32_t * pulOSTMIntReg;
631 /* Interrupt configuration for OSTM Timer
632 * By default, the second lowest priority is set for timer interrupt to
633 * avoid blocking other interrupt. Normally, user could set the lowest
634 * priority for non-critical event. It try to keep timer on time.
635 * In addition, direct vector table is used by default.
637 pulOSTMIntReg = ( volatile uint32_t * ) portOSTM_EIC_ADDR;
638 *pulOSTMIntReg = ( portINT_PROCESSING_ENABLED | portINT_DIRECT_VECTOR | portINT_PRIORITY_LEVEL14 );
640 /* Set OSTM0 control setting */
641 *( ( volatile uint32_t * ) portOSTM0CTL_ADDR ) =
642 ( portOSTM_MODE_INTERVAL_TIMER | portOSTM_START_INTERRUPT_DISABLE );
643 *( ( volatile uint32_t * ) portOSTM0CMP_ADDR ) =
644 ( ( configCPU_CLOCK_HZ / configTIMER_PRESCALE ) / configTICK_RATE_HZ ) - 1;
646 /* Enable OSTM0 operation */
647 *( ( volatile uint32_t * ) portOSTM0TS_ADDR ) = portOSTM_COUNTER_START;
650 /*-----------------------------------------------------------*/
652 #if ( configNUMBER_OF_CORES > 1 )
655 * These functions implement spin-lock mechanism among cores using hardware
656 * exclusive control with atomic access by CLR1 and SET1 instruction.
657 * Nesting calls to these APIs are possible.
659 #pragma inline_asm prvExclusiveLock
660 static void prvExclusiveLock( BaseType_t xBitPosition )
662 /* No problem with r19, CCRH does not required to restore same value
663 * before and after function call. */
664 mov # _pxPortExclusiveReg, r19
667 prvExclusiveLock_Lock:
669 /* r6 is xBitPosition */
671 bz prvExclusiveLock_Lock_success
673 br prvExclusiveLock_Lock
675 prvExclusiveLock_Lock_success:
678 /*-----------------------------------------------------------*/
680 #pragma inline_asm prvExclusiveRelease
681 static void prvExclusiveRelease( BaseType_t xBitPosition )
683 mov # _pxPortExclusiveReg, r19
686 /* r6 is xBitPosition */
690 /*-----------------------------------------------------------*/
691 void vPortRecursiveLockAcquire( BaseType_t xCoreID, BaseType_t xFromIsr )
693 BaseType_t xSavedInterruptStatus;
694 BaseType_t xBitPosition = ( xFromIsr == pdTRUE );
696 xSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
698 if( uxLockNesting[ xCoreID ][ xBitPosition ] == 0 )
700 prvExclusiveLock( xBitPosition );
703 uxLockNesting[ xCoreID ][ xBitPosition ]++;
704 portCLEAR_INTERRUPT_MASK_FROM_ISR( xSavedInterruptStatus );
707 void vPortRecursiveLockRelease( BaseType_t xCoreID, BaseType_t xFromIsr )
709 BaseType_t xSavedInterruptStatus;
710 BaseType_t xBitPosition = ( xFromIsr == pdTRUE );
712 xSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
717 /* Error check whether vPortRecursiveLockRelease() is not called in
718 * pair with vPortRecursiveLockAcquire() */
719 configASSERT( ( uxLockNesting[ xCoreID ][ xBitPosition ] > 0 ) );
720 uxLockNesting[ xCoreID ][ xBitPosition ]--;
722 if( uxLockNesting[ xCoreID ][ xBitPosition ] == 0 )
724 prvExclusiveRelease( xBitPosition );
727 portCLEAR_INTERRUPT_MASK_FROM_ISR( xSavedInterruptStatus );
730 /*-----------------------------------------------------------*/
732 #endif /* (configNUMBER_OF_CORES > 1) */