1 /* Copyright (c) 2019, XMOS Ltd, All rights reserved */
3 /* Scheduler includes. */
8 #include <xcore/hwtimer.h>
9 #include <xcore/triggerable.h>
11 static hwtimer_t xKernelTimer;
13 uint32_t ulPortYieldRequired[ portMAX_CORE_COUNT ] = { pdFALSE };
15 /* When this port was designed, it was assumed that pxCurrentTCBs would always
16 exist and that it would always be an array containing pointers to the current
17 TCBs for each core. In v11, this is not the case; if we are only running one
18 core, the symbol is pxCurrentTCB instead. Therefore, this port adds a layer
19 of indirection - we populate this pointer-to-pointer in the RTOS kernel entry
20 function below. This makes this port agnostic to whether it is running on SMP
21 or singlecore RTOS. */
22 void ** xcorePvtTCBContainer;
24 /*-----------------------------------------------------------*/
26 void vIntercoreInterruptISR( void )
30 /* debug_printf( "In KCALL: %u\n", ulData ); */
31 xCoreID = rtos_core_id_get();
32 ulPortYieldRequired[ xCoreID ] = pdTRUE;
34 /*-----------------------------------------------------------*/
36 DEFINE_RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR, pvData )
38 uint32_t ulLastTrigger;
41 UBaseType_t uxSavedInterruptStatus;
45 configASSERT( xCoreID == rtos_core_id_get() );
47 /* Need the next interrupt to be scheduled relative to
48 * the current trigger time, rather than the current
50 ulLastTrigger = hwtimer_get_trigger_time( xKernelTimer );
52 /* Check to see if the ISR is late. If it is, we don't
53 * want to schedule the next interrupt to be in the past. */
54 ulNow = hwtimer_get_time( xKernelTimer );
56 if( ulNow - ulLastTrigger >= configCPU_CLOCK_HZ / configTICK_RATE_HZ )
58 ulLastTrigger = ulNow;
61 ulLastTrigger += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
62 hwtimer_change_trigger_time( xKernelTimer, ulLastTrigger );
64 #if configUPDATE_RTOS_TIME_FROM_TICK_ISR == 1
65 rtos_time_increment( RTOS_TICK_PERIOD( configTICK_RATE_HZ ) );
68 uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
70 if( xTaskIncrementTick() != pdFALSE )
72 ulPortYieldRequired[ xCoreID ] = pdTRUE;
75 taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
77 /*-----------------------------------------------------------*/
79 void vPortYieldOtherCore( int xOtherCoreID )
84 * This function must be called from within a critical section.
87 xCoreID = rtos_core_id_get();
89 /* debug_printf("%d->%d\n", xCoreID, xOtherCoreID); */
91 /* debug_printf("Yield core %d from %d\n", xOtherCoreID, xCoreID ); */
93 rtos_irq( xOtherCoreID, xCoreID );
95 /*-----------------------------------------------------------*/
97 static int prvCoreInit( void )
101 xCoreID = rtos_core_register();
102 debug_printf( "Logical Core %d initializing as FreeRTOS Core %d\n", get_logical_core_id(), xCoreID );
105 "ldap r11, kexcept\n\t"
112 rtos_irq_enable( configNUMBER_OF_CORES );
115 * All threads wait here until all have enabled IRQs
117 while( rtos_irq_ready() == pdFALSE )
124 ulNow = hwtimer_get_time( xKernelTimer );
125 /* debug_printf( "The time is now (%u)\n", ulNow ); */
127 ulNow += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
129 triggerable_setup_interrupt_callback( xKernelTimer, NULL, RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR ) );
130 hwtimer_set_trigger_time( xKernelTimer, ulNow );
131 triggerable_enable_trigger( xKernelTimer );
136 /*-----------------------------------------------------------*/
138 DEFINE_RTOS_KERNEL_ENTRY( void, vPortStartSchedulerOnCore, void )
142 xCoreID = prvCoreInit();
144 #if ( configUSE_CORE_INIT_HOOK == 1 )
146 extern void vApplicationCoreInitHook( BaseType_t xCoreID );
148 vApplicationCoreInitHook( xCoreID );
152 /* Populate the TCBContainer depending on whether we're singlecore or SMP */
153 #if ( configNUMBER_OF_CORES == 1 )
156 "ldaw %0, dp[pxCurrentTCB]\n\t"
157 : "=r"(xcorePvtTCBContainer)
165 "ldaw %0, dp[pxCurrentTCBs]\n\t"
166 : "=r"(xcorePvtTCBContainer)
174 debug_printf( "FreeRTOS Core %d initialized\n", xCoreID );
177 * Restore the context of the first thread
178 * to run and jump into it.
181 "mov r6, %0\n\t" /* R6 must be the FreeRTOS core ID. In singlecore this is always 0. */
182 "ldw r5, dp[xcorePvtTCBContainer]\n\t" /* R5 must be the TCB list which is indexed by R6 */
183 "bu _freertos_restore_ctx\n\t"
189 /*-----------------------------------------------------------*/
191 /*-----------------------------------------------------------*/
192 /* Public functions required by all ports below: */
193 /*-----------------------------------------------------------*/
196 * See header file for description.
198 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
199 TaskFunction_t pxCode,
200 void * pvParameters )
202 /*debug_printf( "Top of stack was %p for task %p\n", pxTopOfStack, pxCode ); */
205 * Grow the thread's stack by portTHREAD_CONTEXT_STACK_GROWTH
206 * so we can push the context onto it.
208 pxTopOfStack -= portTHREAD_CONTEXT_STACK_GROWTH;
214 * We need to get the current CP and DP pointers.
217 "ldaw r11, cp[0]\n\t" /* get CP into R11 */
218 "mov %0, r11\n\t" /* get R11 (CP) into cp */
219 "ldaw r11, dp[0]\n\t" /* get DP into R11 */
220 "mov %1, r11\n\t" /* get R11 (DP) into dp */
221 : "=r" ( cp ), "=r" ( dp ) /* output 0 is cp, output 1 is dp */
222 : /* there are no inputs */
223 : "r11" /* R11 gets clobbered */
227 * Push the thread context onto the stack.
228 * Saved PC will point to the new thread's
230 * Interrupts will default to enabled.
231 * KEDI is also set to enable dual issue mode
234 pxTopOfStack[ 1 ] = ( StackType_t ) pxCode; /* SP[1] := SPC */
235 pxTopOfStack[ 2 ] = XS1_SR_IEBLE_MASK
236 | XS1_SR_KEDI_MASK; /* SP[2] := SSR */
237 pxTopOfStack[ 3 ] = 0x00000000; /* SP[3] := SED */
238 pxTopOfStack[ 4 ] = 0x00000000; /* SP[4] := ET */
239 pxTopOfStack[ 5 ] = dp; /* SP[5] := DP */
240 pxTopOfStack[ 6 ] = cp; /* SP[6] := CP */
241 pxTopOfStack[ 7 ] = 0x00000000; /* SP[7] := LR */
242 pxTopOfStack[ 8 ] = ( StackType_t ) pvParameters; /* SP[8] := R0 */
243 pxTopOfStack[ 9 ] = 0x01010101; /* SP[9] := R1 */
244 pxTopOfStack[ 10 ] = 0x02020202; /* SP[10] := R2 */
245 pxTopOfStack[ 11 ] = 0x03030303; /* SP[11] := R3 */
246 pxTopOfStack[ 12 ] = 0x04040404; /* SP[12] := R4 */
247 pxTopOfStack[ 13 ] = 0x05050505; /* SP[13] := R5 */
248 pxTopOfStack[ 14 ] = 0x06060606; /* SP[14] := R6 */
249 pxTopOfStack[ 15 ] = 0x07070707; /* SP[15] := R7 */
250 pxTopOfStack[ 16 ] = 0x08080808; /* SP[16] := R8 */
251 pxTopOfStack[ 17 ] = 0x09090909; /* SP[17] := R9 */
252 pxTopOfStack[ 18 ] = 0x10101010; /* SP[18] := R10 */
253 pxTopOfStack[ 19 ] = 0x11111111; /* SP[19] := R11 */
254 pxTopOfStack[ 20 ] = 0x00000000; /* SP[20] := vH and vSR */
255 memset( &pxTopOfStack[ 21 ], 0, 32 ); /* SP[21 - 28] := vR */
256 memset( &pxTopOfStack[ 29 ], 1, 32 ); /* SP[29 - 36] := vD */
257 memset( &pxTopOfStack[ 37 ], 2, 32 ); /* SP[37 - 44] := vC */
259 /*debug_printf( "Top of stack is now %p for task %p\n", pxTopOfStack, pxCode ); */
262 * Returns the new top of the stack
266 /*-----------------------------------------------------------*/
268 void vPortStartSMPScheduler( void );
271 * See header file for description.
273 BaseType_t xPortStartScheduler( void )
275 if( ( configNUMBER_OF_CORES > portMAX_CORE_COUNT ) || ( configNUMBER_OF_CORES <= 0 ) )
280 rtos_locks_initialize();
281 xKernelTimer = hwtimer_alloc();
283 vPortStartSMPScheduler();
287 /*-----------------------------------------------------------*/
289 void vPortEndScheduler( void )
291 /* Do not implement. */
293 /*-----------------------------------------------------------*/