1// Copyright (c) 2020, XMOS Ltd, All rights reserved
2
3#include "rtos_support_rtos_config.h"
4
5/* The FreeRTOS interrupt code calls vTaskSwitchContext.
6Therfore it must be added to the rtos_isr group with the
7rest of the ISR callback functions. */
8.weak _fptrgroup.rtos_isr.nstackwords.group
9.add_to_set _fptrgroup.rtos_isr.nstackwords.group, vTaskSwitchContext.nstackwords, vTaskSwitchContext
10
11.globl kexcept
12.align 128              /* align the kernel section to 128 bytes */
13.type  kexcept,@function
14.issue_mode dual
15.cc_top kexcept.function, kexcept
16kexcept:
17  bu _DoException       /* This symbol is generated by the toolchain and */
18                        /* provides graceful exception handling */
19
20_yield:
21 {set    sp,     r4                  /* Restore the task's SP to save the rest of its context. */
22  get    r11,    id}                 /* Get the logical core ID into r11. */
23  ldaw   r0,     dp[rtos_core_map]
24  ldw    r0,     r0[r11]             /* Translate to the RTOS core ID into r0 */
25  bu _yield_continue                 /* Skip the ulPortYieldRequired check and jump right to */
26                                     /* the context save and switch. Also skips saving SPC */
27                                     /* since the kcall handler has already saved it. */
28
29.align 64
30kcall:
31  /* start saving the thread's context */
32  extsp RTOS_SUPPORT_INTERRUPT_STACK_GROWTH
33  stw    r1,     sp[9]
34  stw    r11,    sp[19]
35
36  /* kcall sets SPC to the instruction of the kcall rather than the next instruction */
37  /* so we need to adjust the SPC value that we save to the stack: */
38  stw    spc,    sp[1]   /* save the saved program counter onto the stack... */
39  ldw    r1,     sp[1]   /* so that we can load it into r1 (which we have already saved). */
40  add    r1,     r1,   4 /* Add 4 to the spc to make it point to the instruction after the kcall. */
41 {stw    r1,     sp[1]   /* Now save it to the stack. */
42
43  /* kcall uses the same common function as interrupt callbacks. */
44  /* tell it to call _yield above. */
45  ldap   r11,    _yield}
46  mov    r1,     r11
47
48  /* fall into rtos_interrupt_callback_common */
49
50.globl rtos_interrupt_callback_common
51rtos_interrupt_callback_common:
52  /* This is the body of the RTOS _xcore_c_interrupt_callback_XXX functions. */
53  /* r1 = interrupt_callback_t function */
54
55  /* Save the thread's context onto the thread's stack. */
56  /* The stack was extended for this by the wrapper function. */
57  /* Begin only by saving some registers. The rest will be saved */
58  /* later if vTaskSwitchContext() needs to be called. */
59  /* DP and CP need to be saved because these are restored for the kernel ISR. */
60  /* LR needs to be saved because it is clobbered when calling the callback. */
61  /* r0-r3, and r11 need to be saved because the callback may clobber them. */
62  /* r4 is saved because it is used here to hold the task SP. */
63
64  stw    dp,     sp[5]
65  stw    cp,     sp[6]
66  stw    lr,     sp[7]
67  stw    r0,     sp[8]
68/*stw    r1,     sp[9]      already saved by the wrapper function. */
69  stw    r2,     sp[10]
70  stw    r3,     sp[11]
71 {stw    r4,     sp[12]
72/*stw    r11,    sp[19]     already saved by the wrapper function. */
73
74  ldaw   r4,     sp[0]}  /* Get value of current stackpointer into r4. */
75
76 {kentsp 0               /* switch to the kernel stack. */
77                         /* The value 0 is safe to use since we don't need the SP */
78                         /* that it saves to KSP[0]. We already have it in r4. */
79
80  get    r11,    ed}     /* Get the event data... */
81  ldw    dp,     sp[3]   /* (Restore CP and DP required for the RTOS ISR */
82  ldw    cp,     sp[4]   /* in case the active thread has modified them.) */
83 {mov    r0,     r11     /* ...into the first argument for the callback function, */
84  bla    r1}             /* and call the callback function. */
85
86 {set    sp,     r4      /* Restore the task's SP now. */
87
88  get    r11,    id}                           /* Get the logical core ID into r11. */
89  ldaw   r0,     dp[rtos_core_map]
90  ldw    r0,     r0[r11]                       /* Translate to the RTOS core ID into r0. */
91  ldaw   r2,     dp[ulPortYieldRequired]       /* Get the yield required array into r2. */
92  ldw    r1,     r2[r0]                        /* Is a yield required for this core? */
93 {bf     r1,     _freertos_restore_ctx_partial /* If not, restore the context now. */
94  ldc    r1,     0}
95  stw    r1,     r2[r0]                        /* Otherwise, clear the yield required flag. */
96
97  /* Save the rest of the current task's context. */
98
99  /* Save standard xs2 regs */
100  stw    spc,    sp[1]
101_yield_continue:
102  stw    ssr,    sp[2]
103  stw    sed,    sp[3]
104  stw    et,     sp[4]
105  stw    r5,     sp[13]
106  stw    r6,     sp[14]
107  stw    r7,     sp[15]
108  stw    r8,     sp[16]
109  stw    r9,     sp[17]
110  stw    r10,    sp[18]
111#if 1
112  /* Save VPU status and headroom */
113  vgetc  r11
114 {stw    r11,    sp[20]
115  /* Save VPU regs */
116  ldaw   r11,    sp[21]}
117 {vstr   r11[0]
118  ldaw   r11,    sp[29]}
119 {vstd   r11[0]
120  ldaw   r11,    sp[37]}
121  vstc   r11[0]
122#endif
123  ldw    r5,     dp[xcorePvtTCBContainer]
124  ldw    r1,     r5[r0]            /* Get this core's current TCB pointer into r1. */
125  stw    r4,     r1[0x0]           /* Save the current task's SP to the first */
126                                   /* word (top of stack) in the current TCB. */
127
128 {kentsp 0                         /* switch back to the kernel stack. */
129
130  mov    r6,     r0}               /* copy the RTOS core ID into r6 so we don't lose it. */
131  ldap   r11,    vTaskSwitchContext
132  bla    r11             /* Finally call vTaskSwitchContext(core_id) now that the task's */
133                         /* entire context is saved. Note the core id in r0 is the argument. */
134
135//krestsp 0              /* unnecessary since KSP is already set and the SP */
136                         /* is being restored next from the current TCB. */
137
138.globl _freertos_restore_ctx
139_freertos_restore_ctx:
140
141  ldw    r0,     r5[r6]  /* get this core's current TCB pointer into r0 */
142  ldw    r0,     r0[0x0] /* Get the top of the stack from the current TCB... */
143  set    sp,     r0      /* into the stack pointer register. */
144
145  /* Restore the current task's context */
146#if 1
147  /* Restore VPU regs */
148  ldaw   r11,    sp[37]
149 {vldc   r11[0]
150  ldaw   r11,    sp[29]}
151 {vldd   r11[0]
152  ldaw   r11,    sp[21]}
153  vldr   r11[0]
154  /* Restore VPU status and headroom */
155  ldw    r11,    sp[20]
156  vsetc  r11
157#endif
158  /* Restore standard xs2 regs */
159  ldw    spc,    sp[1]
160  ldw    ssr,    sp[2]
161  ldw    sed,    sp[3]
162  ldw    et,     sp[4]
163  ldw    r5,     sp[13]
164  ldw    r6,     sp[14]
165  ldw    r7,     sp[15]
166  ldw    r8,     sp[16]
167  ldw    r9,     sp[17]
168  ldw    r10,    sp[18]
169_freertos_restore_ctx_partial:
170  ldw    dp,     sp[5]
171  ldw    cp,     sp[6]
172  ldw    lr,     sp[7]
173  ldw    r0,     sp[8]
174  ldw    r1,     sp[9]
175  ldw    r2,     sp[10]
176  ldw    r3,     sp[11]
177  ldw    r4,     sp[12]
178 {ldw    r11,    sp[19]
179
180  /* shrink the stack by the size of the context just restored */
181  ldaw   sp,     sp[RTOS_SUPPORT_INTERRUPT_STACK_GROWTH]}
182
183  kret                   /* exit kernel mode and return to the thread */
184
185.cc_bottom kexcept.function
186
187