| // Copyright (c) 2020, XMOS Ltd, All rights reserved |
| |
| #include "rtos_support_rtos_config.h" |
| |
| /* The FreeRTOS interrupt code calls vTaskSwitchContext. |
| Therfore it must be added to the rtos_isr group with the |
| rest of the ISR callback functions. */ |
| .weak _fptrgroup.rtos_isr.nstackwords.group |
| .add_to_set _fptrgroup.rtos_isr.nstackwords.group, vTaskSwitchContext.nstackwords, vTaskSwitchContext |
| |
| .globl kexcept |
| .align 128 /* align the kernel section to 128 bytes */ |
| .type kexcept,@function |
| .issue_mode dual |
| .cc_top kexcept.function, kexcept |
| kexcept: |
| ldc r11, 0x0008 |
| shl r11, r11, 16 |
| ldc r9, 0x0080 |
| or r11, r11, r9 |
| bau r11 //_TrapHandler is at 0x00080080. TODO: Is it always? Why can't I access the symbol _TrapHandler? |
| |
| _yield: |
| {set sp, r4 /* Restore the task's SP to save the rest of its context. */ |
| get r11, id} /* Get the logical core ID into r11. */ |
| ldaw r0, dp[rtos_core_map] |
| ldw r0, r0[r11] /* Translate to the RTOS core ID into r0 */ |
| bu _yield_continue /* Skip the ulPortYieldRequired check and jump right to */ |
| /* the context save and switch. Also skips saving SPC */ |
| /* since the kcall handler has already saved it. */ |
| |
| .align 64 |
| kcall: |
| /* start saving the thread's context */ |
| extsp RTOS_SUPPORT_INTERRUPT_STACK_GROWTH |
| stw r1, sp[9] |
| stw r11, sp[19] |
| |
| /* kcall sets SPC to the instruction of the kcall rather than the next instruction */ |
| /* so we need to adjust the SPC value that we save to the stack: */ |
| stw spc, sp[1] /* save the saved program counter onto the stack... */ |
| ldw r1, sp[1] /* so that we can load it into r1 (which we have already saved). */ |
| add r1, r1, 4 /* Add 4 to the spc to make it point to the instruction after the kcall. */ |
| {stw r1, sp[1] /* Now save it to the stack. */ |
| |
| /* kcall uses the same common function as interrupt callbacks. */ |
| /* tell it to call _yield above. */ |
| ldap r11, _yield} |
| mov r1, r11 |
| |
| /* fall into rtos_interrupt_callback_common */ |
| |
| .globl rtos_interrupt_callback_common |
| rtos_interrupt_callback_common: |
| /* This is the body of the RTOS _xcore_c_interrupt_callback_XXX functions. */ |
| /* r1 = interrupt_callback_t function */ |
| |
| /* Save the thread's context onto the thread's stack. */ |
| /* The stack was extended for this by the wrapper function. */ |
| /* Begin only by saving some registers. The rest will be saved */ |
| /* later if vTaskSwitchContext() needs to be called. */ |
| /* DP and CP need to be saved because these are restored for the kernel ISR. */ |
| /* LR needs to be saved because it is clobbered when calling the callback. */ |
| /* r0-r3, and r11 need to be saved because the callback may clobber them. */ |
| /* r4 is saved because it is used here to hold the task SP. */ |
| |
| stw dp, sp[5] |
| stw cp, sp[6] |
| stw lr, sp[7] |
| stw r0, sp[8] |
| /*stw r1, sp[9] already saved by the wrapper function. */ |
| stw r2, sp[10] |
| stw r3, sp[11] |
| {stw r4, sp[12] |
| /*stw r11, sp[19] already saved by the wrapper function. */ |
| |
| ldaw r4, sp[0]} /* Get value of current stackpointer into r4. */ |
| |
| {kentsp 0 /* switch to the kernel stack. */ |
| /* The value 0 is safe to use since we don't need the SP */ |
| /* that it saves to KSP[0]. We already have it in r4. */ |
| |
| get r11, ed} /* Get the event data... */ |
| ldw dp, sp[3] /* (Restore CP and DP required for the RTOS ISR */ |
| ldw cp, sp[4] /* in case the active thread has modified them.) */ |
| {mov r0, r11 /* ...into the first argument for the callback function, */ |
| bla r1} /* and call the callback function. */ |
| |
| {set sp, r4 /* Restore the task's SP now. */ |
| |
| get r11, id} /* Get the logical core ID into r11. */ |
| ldaw r0, dp[rtos_core_map] |
| ldw r0, r0[r11] /* Translate to the RTOS core ID into r0. */ |
| ldaw r2, dp[ulPortYieldRequired] /* Get the yield required array into r2. */ |
| ldw r1, r2[r0] /* Is a yield required for this core? */ |
| {bf r1, _freertos_restore_ctx_partial /* If not, restore the context now. */ |
| ldc r1, 0} |
| stw r1, r2[r0] /* Otherwise, clear the yield required flag. */ |
| |
| /* Save the rest of the current task's context. */ |
| |
| /* Save standard xs2 regs */ |
| stw spc, sp[1] |
| _yield_continue: |
| stw ssr, sp[2] |
| stw sed, sp[3] |
| stw et, sp[4] |
| stw r5, sp[13] |
| stw r6, sp[14] |
| stw r7, sp[15] |
| stw r8, sp[16] |
| stw r9, sp[17] |
| stw r10, sp[18] |
| #if 1 |
| /* Save VPU status and headroom */ |
| vgetc r11 |
| {stw r11, sp[20] |
| /* Save VPU regs */ |
| ldaw r11, sp[21]} |
| {vstr r11[0] |
| ldaw r11, sp[29]} |
| {vstd r11[0] |
| ldaw r11, sp[37]} |
| vstc r11[0] |
| #endif |
| ldaw r5, dp[pxCurrentTCBs] /* Get the current TCB array into r5. */ |
| ldw r1, r5[r0] /* Get this core's current TCB pointer into r1. */ |
| stw r4, r1[0x0] /* Save the current task's SP to the first */ |
| /* word (top of stack) in the current TCB. */ |
| |
| {kentsp 0 /* switch back to the kernel stack. */ |
| |
| mov r6, r0} /* copy the RTOS core ID into r6 so we don't lose it. */ |
| ldap r11, vTaskSwitchContext |
| bla r11 /* Finally call vTaskSwitchContext(core_id) now that the task's */ |
| /* entire context is saved. Note the core id in r0 is the argument. */ |
| |
| //krestsp 0 /* unnecessary since KSP is already set and the SP */ |
| /* is being restored next from the current TCB. */ |
| |
| .globl _freertos_restore_ctx |
| _freertos_restore_ctx: |
| |
| ldw r0, r5[r6] /* get this core's current TCB pointer into r0 */ |
| ldw r0, r0[0x0] /* Get the top of the stack from the current TCB... */ |
| set sp, r0 /* into the stack pointer register. */ |
| |
| /* Restore the current task's context */ |
| #if 1 |
| /* Restore VPU regs */ |
| ldaw r11, sp[37] |
| {vldc r11[0] |
| ldaw r11, sp[29]} |
| {vldd r11[0] |
| ldaw r11, sp[21]} |
| vldr r11[0] |
| /* Restore VPU status and headroom */ |
| ldw r11, sp[20] |
| vsetc r11 |
| #endif |
| /* Restore standard xs2 regs */ |
| ldw spc, sp[1] |
| ldw ssr, sp[2] |
| ldw sed, sp[3] |
| ldw et, sp[4] |
| ldw r5, sp[13] |
| ldw r6, sp[14] |
| ldw r7, sp[15] |
| ldw r8, sp[16] |
| ldw r9, sp[17] |
| ldw r10, sp[18] |
| _freertos_restore_ctx_partial: |
| ldw dp, sp[5] |
| ldw cp, sp[6] |
| ldw lr, sp[7] |
| ldw r0, sp[8] |
| ldw r1, sp[9] |
| ldw r2, sp[10] |
| ldw r3, sp[11] |
| ldw r4, sp[12] |
| {ldw r11, sp[19] |
| |
| /* shrink the stack by the size of the context just restored */ |
| ldaw sp, sp[RTOS_SUPPORT_INTERRUPT_STACK_GROWTH]} |
| |
| kret /* exit kernel mode and return to the thread */ |
| |
| .cc_bottom kexcept.function |
| |