1 // Copyright (c) 2019, XMOS Ltd, All rights reserved
3 /* Scheduler includes. */
7 #include <xcore/hwtimer.h>
8 #include <xcore/triggerable.h>
10 static hwtimer_t xKernelTimer;
12 uint32_t ulPortYieldRequired[ portMAX_CORE_COUNT ] = { pdFALSE };
14 /*-----------------------------------------------------------*/
16 void vIntercoreInterruptISR( void )
20 // debug_printf( "In KCALL: %u\n", ulData );
21 xCoreID = rtos_core_id_get();
22 ulPortYieldRequired[ xCoreID ] = pdTRUE;
24 /*-----------------------------------------------------------*/
26 DEFINE_RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR, pvData )
28 uint32_t ulLastTrigger;
34 configASSERT( xCoreID == rtos_core_id_get() );
36 /* Need the next interrupt to be scheduled relative to
37 * the current trigger time, rather than the current
39 ulLastTrigger = hwtimer_get_trigger_time( xKernelTimer );
41 /* Check to see if the ISR is late. If it is, we don't
42 * want to schedule the next interrupt to be in the past. */
43 ulNow = hwtimer_get_time( xKernelTimer );
44 if( ulNow - ulLastTrigger >= configCPU_CLOCK_HZ / configTICK_RATE_HZ )
46 ulLastTrigger = ulNow;
49 ulLastTrigger += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
50 hwtimer_change_trigger_time( xKernelTimer, ulLastTrigger );
52 #if configUPDATE_RTOS_TIME_FROM_TICK_ISR == 1
53 rtos_time_increment( RTOS_TICK_PERIOD( configTICK_RATE_HZ ) );
56 if( xTaskIncrementTick() != pdFALSE )
58 ulPortYieldRequired[ xCoreID ] = pdTRUE;
61 /*-----------------------------------------------------------*/
63 void vPortYieldOtherCore( int xOtherCoreID )
68 * This function must be called from within a critical section.
71 xCoreID = rtos_core_id_get();
73 // debug_printf("%d->%d\n", xCoreID, xOtherCoreID);
75 // debug_printf("Yield core %d from %d\n", xOtherCoreID, xCoreID );
77 rtos_irq( xOtherCoreID, xCoreID );
79 /*-----------------------------------------------------------*/
81 static int prvCoreInit( void )
85 xCoreID = rtos_core_register();
86 debug_printf( "Logical Core %d initializing as FreeRTOS Core %d\n", get_logical_core_id(), xCoreID );
89 "ldap r11, kexcept\n\t"
96 rtos_irq_enable( configNUM_CORES );
99 * All threads wait here until all have enabled IRQs
101 while( rtos_irq_ready() == pdFALSE );
106 ulNow = hwtimer_get_time( xKernelTimer );
107 // debug_printf( "The time is now (%u)\n", ulNow );
109 ulNow += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
111 triggerable_setup_interrupt_callback( xKernelTimer, NULL, RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR ) );
112 hwtimer_set_trigger_time( xKernelTimer, ulNow );
113 triggerable_enable_trigger( xKernelTimer );
118 /*-----------------------------------------------------------*/
120 DEFINE_RTOS_KERNEL_ENTRY( void, vPortStartSchedulerOnCore, void )
124 xCoreID = prvCoreInit();
126 debug_printf( "FreeRTOS Core %d initialized\n", xCoreID );
129 * Restore the context of the first thread
130 * to run and jump into it.
133 "mov r6, %0\n\t" /* R6 must be the FreeRTOS core ID*/
134 "ldaw r5, dp[pxCurrentTCBs]\n\t" /* R5 must be the TCB list which is indexed by R6 */
135 "bu _freertos_restore_ctx\n\t"
141 /*-----------------------------------------------------------*/
143 /*-----------------------------------------------------------*/
144 /* Public functions required by all ports below: */
145 /*-----------------------------------------------------------*/
148 * See header file for description.
150 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
152 //debug_printf( "Top of stack was %p for task %p\n", pxTopOfStack, pxCode );
154 * Grow the thread's stack by portTHREAD_CONTEXT_STACK_GROWTH
155 * so we can push the context onto it.
157 pxTopOfStack -= portTHREAD_CONTEXT_STACK_GROWTH;
163 * We need to get the current CP and DP pointers.
166 "ldaw r11, cp[0]\n\t" /* get CP into R11 */
167 "mov %0, r11\n\t" /* get R11 (CP) into cp */
168 "ldaw r11, dp[0]\n\t" /* get DP into R11 */
169 "mov %1, r11\n\t" /* get R11 (DP) into dp */
170 : "=r"(cp), "=r"(dp) /* output 0 is cp, output 1 is dp */
171 : /* there are no inputs */
172 : "r11" /* R11 gets clobbered */
176 * Push the thread context onto the stack.
177 * Saved PC will point to the new thread's
179 * Interrupts will default to enabled.
180 * KEDI is also set to enable dual issue mode
183 pxTopOfStack[ 1 ] = ( StackType_t ) pxCode; /* SP[1] := SPC */
184 pxTopOfStack[ 2 ] = XS1_SR_IEBLE_MASK
185 | XS1_SR_KEDI_MASK; /* SP[2] := SSR */
186 pxTopOfStack[ 3 ] = 0x00000000; /* SP[3] := SED */
187 pxTopOfStack[ 4 ] = 0x00000000; /* SP[4] := ET */
188 pxTopOfStack[ 5 ] = dp; /* SP[5] := DP */
189 pxTopOfStack[ 6 ] = cp; /* SP[6] := CP */
190 pxTopOfStack[ 7 ] = 0x00000000; /* SP[7] := LR */
191 pxTopOfStack[ 8 ] = ( StackType_t ) pvParameters; /* SP[8] := R0 */
192 pxTopOfStack[ 9 ] = 0x01010101; /* SP[9] := R1 */
193 pxTopOfStack[ 10 ] = 0x02020202; /* SP[10] := R2 */
194 pxTopOfStack[ 11 ] = 0x03030303; /* SP[11] := R3 */
195 pxTopOfStack[ 12 ] = 0x04040404; /* SP[12] := R4 */
196 pxTopOfStack[ 13 ] = 0x05050505; /* SP[13] := R5 */
197 pxTopOfStack[ 14 ] = 0x06060606; /* SP[14] := R6 */
198 pxTopOfStack[ 15 ] = 0x07070707; /* SP[15] := R7 */
199 pxTopOfStack[ 16 ] = 0x08080808; /* SP[16] := R8 */
200 pxTopOfStack[ 17 ] = 0x09090909; /* SP[17] := R9 */
201 pxTopOfStack[ 18 ] = 0x10101010; /* SP[18] := R10 */
202 pxTopOfStack[ 19 ] = 0x11111111; /* SP[19] := R11 */
204 //debug_printf( "Top of stack is now %p for task %p\n", pxTopOfStack, pxCode );
207 * Returns the new top of the stack
211 /*-----------------------------------------------------------*/
213 void vPortStartSMPScheduler( void );
216 * See header file for description.
218 BaseType_t xPortStartScheduler( void )
220 if( ( configNUM_CORES > portMAX_CORE_COUNT ) || ( configNUM_CORES <= 0 ) )
225 rtos_locks_initialize();
226 xKernelTimer = hwtimer_alloc();
228 vPortStartSMPScheduler();
232 /*-----------------------------------------------------------*/
234 void vPortEndScheduler( void )
236 /* Do not implement. */
238 /*-----------------------------------------------------------*/