blob: 702e9a2f021aea350ea618f48ade74599b5667bd [file] [log] [blame]
// 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