1 /* Copyright (c) 2019, XMOS Ltd, All rights reserved */
2 
3 /* Scheduler includes. */
4 #include "FreeRTOS.h"
5 #include "task.h"
6 #include <string.h>
7 #include <xs1.h>
8 #include <xcore/hwtimer.h>
9 #include <xcore/triggerable.h>
10 
11 static hwtimer_t xKernelTimer;
12 
13 uint32_t ulPortYieldRequired[ portMAX_CORE_COUNT ] = { pdFALSE };
14 
15 /*-----------------------------------------------------------*/
16 
vIntercoreInterruptISR(void)17 void vIntercoreInterruptISR( void )
18 {
19     int xCoreID;
20 
21 /*	debug_printf( "In KCALL: %u\n", ulData ); */
22     xCoreID = rtos_core_id_get();
23     ulPortYieldRequired[ xCoreID ] = pdTRUE;
24 }
25 /*-----------------------------------------------------------*/
26 
DEFINE_RTOS_INTERRUPT_CALLBACK(pxKernelTimerISR,pvData)27 DEFINE_RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR, pvData )
28 {
29     uint32_t ulLastTrigger;
30     uint32_t ulNow;
31     int xCoreID;
32     UBaseType_t uxSavedInterruptStatus;
33 
34     xCoreID = 0;
35 
36     configASSERT( xCoreID == rtos_core_id_get() );
37 
38     /* Need the next interrupt to be scheduled relative to
39      * the current trigger time, rather than the current
40      * time. */
41     ulLastTrigger = hwtimer_get_trigger_time( xKernelTimer );
42 
43     /* Check to see if the ISR is late. If it is, we don't
44      * want to schedule the next interrupt to be in the past. */
45     ulNow = hwtimer_get_time( xKernelTimer );
46 
47     if( ulNow - ulLastTrigger >= configCPU_CLOCK_HZ / configTICK_RATE_HZ )
48     {
49         ulLastTrigger = ulNow;
50     }
51 
52     ulLastTrigger += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
53     hwtimer_change_trigger_time( xKernelTimer, ulLastTrigger );
54 
55     #if configUPDATE_RTOS_TIME_FROM_TICK_ISR == 1
56         rtos_time_increment( RTOS_TICK_PERIOD( configTICK_RATE_HZ ) );
57     #endif
58 
59     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
60 
61     if( xTaskIncrementTick() != pdFALSE )
62     {
63         ulPortYieldRequired[ xCoreID ] = pdTRUE;
64     }
65 
66     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
67 }
68 /*-----------------------------------------------------------*/
69 
vPortYieldOtherCore(int xOtherCoreID)70 void vPortYieldOtherCore( int xOtherCoreID )
71 {
72     int xCoreID;
73 
74     /*
75      * This function must be called from within a critical section.
76      */
77 
78     xCoreID = rtos_core_id_get();
79 
80 /*	debug_printf("%d->%d\n", xCoreID, xOtherCoreID); */
81 
82 /*	debug_printf("Yield core %d from %d\n", xOtherCoreID, xCoreID ); */
83 
84     rtos_irq( xOtherCoreID, xCoreID );
85 }
86 /*-----------------------------------------------------------*/
87 
prvCoreInit(void)88 static int prvCoreInit( void )
89 {
90     int xCoreID;
91 
92     xCoreID = rtos_core_register();
93     debug_printf( "Logical Core %d initializing as FreeRTOS Core %d\n", get_logical_core_id(), xCoreID );
94 
95     asm volatile (
96         "ldap r11, kexcept\n\t"
97         "set kep, r11\n\t"
98         :
99         :
100         : "r11"
101         );
102 
103     rtos_irq_enable( configNUMBER_OF_CORES );
104 
105     /*
106      * All threads wait here until all have enabled IRQs
107      */
108     while( rtos_irq_ready() == pdFALSE )
109     {
110     }
111 
112     if( xCoreID == 0 )
113     {
114         uint32_t ulNow;
115         ulNow = hwtimer_get_time( xKernelTimer );
116 /*		debug_printf( "The time is now (%u)\n", ulNow ); */
117 
118         ulNow += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
119 
120         triggerable_setup_interrupt_callback( xKernelTimer, NULL, RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR ) );
121         hwtimer_set_trigger_time( xKernelTimer, ulNow );
122         triggerable_enable_trigger( xKernelTimer );
123     }
124 
125     return xCoreID;
126 }
127 /*-----------------------------------------------------------*/
128 
DEFINE_RTOS_KERNEL_ENTRY(void,vPortStartSchedulerOnCore,void)129 DEFINE_RTOS_KERNEL_ENTRY( void, vPortStartSchedulerOnCore, void )
130 {
131     int xCoreID;
132 
133     xCoreID = prvCoreInit();
134 
135     #if ( configUSE_CORE_INIT_HOOK == 1 )
136     {
137         extern void vApplicationCoreInitHook( BaseType_t xCoreID );
138 
139         vApplicationCoreInitHook( xCoreID );
140     }
141     #endif
142 
143     debug_printf( "FreeRTOS Core %d initialized\n", xCoreID );
144 
145     /*
146      * Restore the context of the first thread
147      * to run and jump into it.
148      */
149     asm volatile (
150         "mov r6, %0\n\t"                 /* R6 must be the FreeRTOS core ID*/
151         "ldaw r5, dp[pxCurrentTCBs]\n\t" /* R5 must be the TCB list which is indexed by R6 */
152         "bu _freertos_restore_ctx\n\t"
153         :                                /* no outputs */
154         : "r" ( xCoreID )
155         : "r5", "r6"
156         );
157 }
158 /*-----------------------------------------------------------*/
159 
160 /*-----------------------------------------------------------*/
161 /* Public functions required by all ports below:             */
162 /*-----------------------------------------------------------*/
163 
164 /*
165  * See header file for description.
166  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)167 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
168                                      TaskFunction_t pxCode,
169                                      void * pvParameters )
170 {
171     /*debug_printf( "Top of stack was %p for task %p\n", pxTopOfStack, pxCode ); */
172 
173     /*
174      * Grow the thread's stack by portTHREAD_CONTEXT_STACK_GROWTH
175      * so we can push the context onto it.
176      */
177     pxTopOfStack -= portTHREAD_CONTEXT_STACK_GROWTH;
178 
179     uint32_t dp;
180     uint32_t cp;
181 
182     /*
183      * We need to get the current CP and DP pointers.
184      */
185     asm volatile (
186         "ldaw r11, cp[0]\n\t"      /* get CP into R11 */
187         "mov %0, r11\n\t"          /* get R11 (CP) into cp */
188         "ldaw r11, dp[0]\n\t"      /* get DP into R11 */
189         "mov %1, r11\n\t"          /* get R11 (DP) into dp */
190         : "=r" ( cp ), "=r" ( dp ) /* output 0 is cp, output 1 is dp */
191         :                          /* there are no inputs */
192         : "r11"                    /* R11 gets clobbered */
193         );
194 
195     /*
196      * Push the thread context onto the stack.
197      * Saved PC will point to the new thread's
198      * entry pointer.
199      * Interrupts will default to enabled.
200      * KEDI is also set to enable dual issue mode
201      * upon kernel entry.
202      */
203     pxTopOfStack[ 1 ] = ( StackType_t ) pxCode;       /* SP[1]  := SPC */
204     pxTopOfStack[ 2 ] = XS1_SR_IEBLE_MASK
205                         | XS1_SR_KEDI_MASK;           /* SP[2]  := SSR */
206     pxTopOfStack[ 3 ] = 0x00000000;                   /* SP[3]  := SED */
207     pxTopOfStack[ 4 ] = 0x00000000;                   /* SP[4]  := ET */
208     pxTopOfStack[ 5 ] = dp;                           /* SP[5]  := DP */
209     pxTopOfStack[ 6 ] = cp;                           /* SP[6]  := CP */
210     pxTopOfStack[ 7 ] = 0x00000000;                   /* SP[7]  := LR */
211     pxTopOfStack[ 8 ] = ( StackType_t ) pvParameters; /* SP[8]  := R0 */
212     pxTopOfStack[ 9 ] = 0x01010101;                   /* SP[9]  := R1 */
213     pxTopOfStack[ 10 ] = 0x02020202;                  /* SP[10] := R2 */
214     pxTopOfStack[ 11 ] = 0x03030303;                  /* SP[11] := R3 */
215     pxTopOfStack[ 12 ] = 0x04040404;                  /* SP[12] := R4 */
216     pxTopOfStack[ 13 ] = 0x05050505;                  /* SP[13] := R5 */
217     pxTopOfStack[ 14 ] = 0x06060606;                  /* SP[14] := R6 */
218     pxTopOfStack[ 15 ] = 0x07070707;                  /* SP[15] := R7 */
219     pxTopOfStack[ 16 ] = 0x08080808;                  /* SP[16] := R8 */
220     pxTopOfStack[ 17 ] = 0x09090909;                  /* SP[17] := R9 */
221     pxTopOfStack[ 18 ] = 0x10101010;                  /* SP[18] := R10 */
222     pxTopOfStack[ 19 ] = 0x11111111;                  /* SP[19] := R11 */
223     pxTopOfStack[ 20 ] = 0x00000000;                  /* SP[20] := vH and vSR */
224     memset( &pxTopOfStack[ 21 ], 0, 32 );             /* SP[21 - 28] := vR   */
225     memset( &pxTopOfStack[ 29 ], 1, 32 );             /* SP[29 - 36] := vD   */
226     memset( &pxTopOfStack[ 37 ], 2, 32 );             /* SP[37 - 44] := vC   */
227 
228     /*debug_printf( "Top of stack is now %p for task %p\n", pxTopOfStack, pxCode ); */
229 
230     /*
231      * Returns the new top of the stack
232      */
233     return pxTopOfStack;
234 }
235 /*-----------------------------------------------------------*/
236 
237 void vPortStartSMPScheduler( void );
238 
239 /*
240  * See header file for description.
241  */
xPortStartScheduler(void)242 BaseType_t xPortStartScheduler( void )
243 {
244     if( ( configNUMBER_OF_CORES > portMAX_CORE_COUNT ) || ( configNUMBER_OF_CORES <= 0 ) )
245     {
246         return pdFAIL;
247     }
248 
249     rtos_locks_initialize();
250     xKernelTimer = hwtimer_alloc();
251 
252     vPortStartSMPScheduler();
253 
254     return pdPASS;
255 }
256 /*-----------------------------------------------------------*/
257 
vPortEndScheduler(void)258 void vPortEndScheduler( void )
259 {
260     /* Do not implement. */
261 }
262 /*-----------------------------------------------------------*/
263