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