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