]> begriffs open source - freertos/blob - portable/ThirdParty/xClang/XCOREAI/port.c
FreeRTOS MPU: Remove MPU region number check (#1261)
[freertos] / portable / ThirdParty / xClang / XCOREAI / port.c
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 /* 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;
23
24 /*-----------------------------------------------------------*/
25
26 void vIntercoreInterruptISR( void )
27 {
28     int xCoreID;
29
30 /*      debug_printf( "In KCALL: %u\n", ulData ); */
31     xCoreID = rtos_core_id_get();
32     ulPortYieldRequired[ xCoreID ] = pdTRUE;
33 }
34 /*-----------------------------------------------------------*/
35
36 DEFINE_RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR, pvData )
37 {
38     uint32_t ulLastTrigger;
39     uint32_t ulNow;
40     int xCoreID;
41     UBaseType_t uxSavedInterruptStatus;
42
43     xCoreID = 0;
44
45     configASSERT( xCoreID == rtos_core_id_get() );
46
47     /* Need the next interrupt to be scheduled relative to
48      * the current trigger time, rather than the current
49      * time. */
50     ulLastTrigger = hwtimer_get_trigger_time( xKernelTimer );
51
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 );
55
56     if( ulNow - ulLastTrigger >= configCPU_CLOCK_HZ / configTICK_RATE_HZ )
57     {
58         ulLastTrigger = ulNow;
59     }
60
61     ulLastTrigger += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
62     hwtimer_change_trigger_time( xKernelTimer, ulLastTrigger );
63
64     #if configUPDATE_RTOS_TIME_FROM_TICK_ISR == 1
65         rtos_time_increment( RTOS_TICK_PERIOD( configTICK_RATE_HZ ) );
66     #endif
67
68     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
69
70     if( xTaskIncrementTick() != pdFALSE )
71     {
72         ulPortYieldRequired[ xCoreID ] = pdTRUE;
73     }
74
75     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
76 }
77 /*-----------------------------------------------------------*/
78
79 void vPortYieldOtherCore( int xOtherCoreID )
80 {
81     int xCoreID;
82
83     /*
84      * This function must be called from within a critical section.
85      */
86
87     xCoreID = rtos_core_id_get();
88
89 /*      debug_printf("%d->%d\n", xCoreID, xOtherCoreID); */
90
91 /*      debug_printf("Yield core %d from %d\n", xOtherCoreID, xCoreID ); */
92
93     rtos_irq( xOtherCoreID, xCoreID );
94 }
95 /*-----------------------------------------------------------*/
96
97 static int prvCoreInit( void )
98 {
99     int xCoreID;
100
101     xCoreID = rtos_core_register();
102     debug_printf( "Logical Core %d initializing as FreeRTOS Core %d\n", get_logical_core_id(), xCoreID );
103
104     asm volatile (
105         "ldap r11, kexcept\n\t"
106         "set kep, r11\n\t"
107         :
108         :
109         : "r11"
110         );
111
112     rtos_irq_enable( configNUMBER_OF_CORES );
113
114     /*
115      * All threads wait here until all have enabled IRQs
116      */
117     while( rtos_irq_ready() == pdFALSE )
118     {
119     }
120
121     if( xCoreID == 0 )
122     {
123         uint32_t ulNow;
124         ulNow = hwtimer_get_time( xKernelTimer );
125 /*              debug_printf( "The time is now (%u)\n", ulNow ); */
126
127         ulNow += configCPU_CLOCK_HZ / configTICK_RATE_HZ;
128
129         triggerable_setup_interrupt_callback( xKernelTimer, NULL, RTOS_INTERRUPT_CALLBACK( pxKernelTimerISR ) );
130         hwtimer_set_trigger_time( xKernelTimer, ulNow );
131         triggerable_enable_trigger( xKernelTimer );
132     }
133
134     return xCoreID;
135 }
136 /*-----------------------------------------------------------*/
137
138 DEFINE_RTOS_KERNEL_ENTRY( void, vPortStartSchedulerOnCore, void )
139 {
140     int xCoreID;
141
142     xCoreID = prvCoreInit();
143
144     #if ( configUSE_CORE_INIT_HOOK == 1 )
145     {
146         extern void vApplicationCoreInitHook( BaseType_t xCoreID );
147
148         vApplicationCoreInitHook( xCoreID );
149     }
150     #endif
151
152     /* Populate the TCBContainer depending on whether we're singlecore or SMP */
153     #if ( configNUMBER_OF_CORES == 1 )
154     {
155         asm volatile (
156             "ldaw %0, dp[pxCurrentTCB]\n\t"
157             : "=r"(xcorePvtTCBContainer)
158             : /* no inputs */
159             : /* no clobbers */
160             );
161     }
162     #else
163     {
164         asm volatile (
165             "ldaw %0, dp[pxCurrentTCBs]\n\t"
166             : "=r"(xcorePvtTCBContainer)
167             : /* no inputs */
168             : /* no clobbers */
169             );
170     }
171
172     #endif
173
174     debug_printf( "FreeRTOS Core %d initialized\n", xCoreID );
175
176     /*
177      * Restore the context of the first thread
178      * to run and jump into it.
179      */
180     asm volatile (
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"
184         :                                /* no outputs */
185         : "r" ( xCoreID )
186         : "r5", "r6"
187         );
188 }
189 /*-----------------------------------------------------------*/
190
191 /*-----------------------------------------------------------*/
192 /* Public functions required by all ports below:             */
193 /*-----------------------------------------------------------*/
194
195 /*
196  * See header file for description.
197  */
198 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
199                                      TaskFunction_t pxCode,
200                                      void * pvParameters )
201 {
202     /*debug_printf( "Top of stack was %p for task %p\n", pxTopOfStack, pxCode ); */
203
204     /*
205      * Grow the thread's stack by portTHREAD_CONTEXT_STACK_GROWTH
206      * so we can push the context onto it.
207      */
208     pxTopOfStack -= portTHREAD_CONTEXT_STACK_GROWTH;
209
210     uint32_t dp;
211     uint32_t cp;
212
213     /*
214      * We need to get the current CP and DP pointers.
215      */
216     asm volatile (
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 */
224         );
225
226     /*
227      * Push the thread context onto the stack.
228      * Saved PC will point to the new thread's
229      * entry pointer.
230      * Interrupts will default to enabled.
231      * KEDI is also set to enable dual issue mode
232      * upon kernel entry.
233      */
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   */
258
259     /*debug_printf( "Top of stack is now %p for task %p\n", pxTopOfStack, pxCode ); */
260
261     /*
262      * Returns the new top of the stack
263      */
264     return pxTopOfStack;
265 }
266 /*-----------------------------------------------------------*/
267
268 void vPortStartSMPScheduler( void );
269
270 /*
271  * See header file for description.
272  */
273 BaseType_t xPortStartScheduler( void )
274 {
275     if( ( configNUMBER_OF_CORES > portMAX_CORE_COUNT ) || ( configNUMBER_OF_CORES <= 0 ) )
276     {
277         return pdFAIL;
278     }
279
280     rtos_locks_initialize();
281     xKernelTimer = hwtimer_alloc();
282
283     vPortStartSMPScheduler();
284
285     return pdPASS;
286 }
287 /*-----------------------------------------------------------*/
288
289 void vPortEndScheduler( void )
290 {
291     /* Do not implement. */
292 }
293 /*-----------------------------------------------------------*/