]> begriffs open source - freertos/blob - portable/MPLAB/PIC32MZ/ISR_Support.h
Update SMP branch readme for port migration (#999)
[freertos] / portable / MPLAB / PIC32MZ / ISR_Support.h
1 /*
2  * FreeRTOS SMP Kernel V202110.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 #include "FreeRTOSConfig.h"
29
30 #define portCONTEXT_SIZE                160
31 #define portEPC_STACK_LOCATION          152
32 #define portSTATUS_STACK_LOCATION       156
33 #define portFPCSR_STACK_LOCATION        0
34 #define portTASK_HAS_FPU_STACK_LOCATION     0
35 #define portFPU_CONTEXT_SIZE            264
36
37 /******************************************************************/
38 .macro  portSAVE_FPU_REGS    offset, base
39     /* Macro to assist with saving just the FPU registers to the
40      * specified address and base offset,
41      * offset is a constant, base is the base pointer register  */
42
43         sdc1            $f31, \offset + 248(\base)
44         sdc1            $f30, \offset + 240(\base)
45         sdc1            $f29, \offset + 232(\base)
46         sdc1            $f28, \offset + 224(\base)
47         sdc1            $f27, \offset + 216(\base)
48         sdc1            $f26, \offset + 208(\base)
49         sdc1            $f25, \offset + 200(\base)
50         sdc1            $f24, \offset + 192(\base)
51         sdc1            $f23, \offset + 184(\base)
52         sdc1            $f22, \offset + 176(\base)
53         sdc1            $f21, \offset + 168(\base)
54         sdc1            $f20, \offset + 160(\base)
55         sdc1            $f19, \offset + 152(\base)
56         sdc1            $f18, \offset + 144(\base)
57         sdc1            $f17, \offset + 136(\base)
58         sdc1            $f16, \offset + 128(\base)
59         sdc1            $f15, \offset + 120(\base)
60         sdc1            $f14, \offset + 112(\base)
61         sdc1            $f13, \offset + 104(\base)
62         sdc1            $f12, \offset + 96(\base)
63         sdc1            $f11, \offset + 88(\base)
64         sdc1            $f10, \offset + 80(\base)
65         sdc1            $f9, \offset + 72(\base)
66         sdc1            $f8, \offset + 64(\base)
67         sdc1            $f7, \offset + 56(\base)
68         sdc1            $f6, \offset + 48(\base)
69         sdc1            $f5, \offset + 40(\base)
70         sdc1            $f4, \offset + 32(\base)
71         sdc1            $f3, \offset + 24(\base)
72         sdc1            $f2, \offset + 16(\base)
73         sdc1            $f1, \offset + 8(\base)
74         sdc1            $f0, \offset + 0(\base)
75
76     .endm
77
78 /******************************************************************/
79 .macro  portLOAD_FPU_REGS    offset, base
80     /* Macro to assist with loading just the FPU registers from the
81      * specified address and base offset, offset is a constant,
82      * base is the base pointer register  */
83
84         ldc1            $f0, \offset + 0(\base)
85         ldc1            $f1, \offset + 8(\base)
86         ldc1            $f2, \offset + 16(\base)
87         ldc1            $f3, \offset + 24(\base)
88         ldc1            $f4, \offset + 32(\base)
89         ldc1            $f5, \offset + 40(\base)
90         ldc1            $f6, \offset + 48(\base)
91         ldc1            $f7, \offset + 56(\base)
92         ldc1            $f8, \offset + 64(\base)
93         ldc1            $f9, \offset + 72(\base)
94         ldc1            $f10, \offset + 80(\base)
95         ldc1            $f11, \offset + 88(\base)
96         ldc1            $f12, \offset + 96(\base)
97         ldc1            $f13, \offset + 104(\base)
98         ldc1            $f14, \offset + 112(\base)
99         ldc1            $f15, \offset + 120(\base)
100         ldc1            $f16, \offset + 128(\base)
101         ldc1            $f17, \offset + 136(\base)
102         ldc1            $f18, \offset + 144(\base)
103         ldc1            $f19, \offset + 152(\base)
104         ldc1            $f20, \offset + 160(\base)
105         ldc1            $f21, \offset + 168(\base)
106         ldc1            $f22, \offset + 176(\base)
107         ldc1            $f23, \offset + 184(\base)
108         ldc1            $f24, \offset + 192(\base)
109         ldc1            $f25, \offset + 200(\base)
110         ldc1            $f26, \offset + 208(\base)
111         ldc1            $f27, \offset + 216(\base)
112         ldc1            $f28, \offset + 224(\base)
113         ldc1            $f29, \offset + 232(\base)
114         ldc1            $f30, \offset + 240(\base)
115         ldc1            $f31, \offset + 248(\base)
116
117     .endm
118
119 /******************************************************************/
120 .macro  portSAVE_CONTEXT
121
122         /* Make room for the context. First save the current status so it can be
123         manipulated, and the cause and EPC registers so their original values are
124         captured. */
125         mfc0            k0, _CP0_CAUSE
126         addiu           sp, sp, -portCONTEXT_SIZE
127
128         #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
129                 /* Test if we are already using the system stack. Only tasks may use the
130                 FPU so if we are already in a nested interrupt then the FPU context does
131                 not require saving. */
132                 la                      k1, uxInterruptNesting
133                 lw                      k1, 0(k1)
134                 bne                     k1, zero, 2f
135                 nop
136
137                 /* Test if the current task needs the FPU context saving. */
138                 la                      k1, ulTaskHasFPUContext
139                 lw                      k1, 0(k1)
140                 beq                     k1, zero, 1f
141                 nop
142
143                 /* Adjust the stack to account for the additional FPU context.*/
144                 addiu           sp, sp, -portFPU_CONTEXT_SIZE
145
146         1:
147                 /* Save the ulTaskHasFPUContext flag. */
148                 sw                      k1, portTASK_HAS_FPU_STACK_LOCATION(sp)
149
150         2:
151         #endif
152
153         mfc0            k1, _CP0_STATUS
154
155         /* Also save s7, s6 and s5 so they can be used.  Any nesting interrupts
156         should maintain the values of these registers across the ISR. */
157         sw                      s7, 48(sp)
158         sw                      s6, 44(sp)
159         sw                      s5, 40(sp)
160         sw                      k1, portSTATUS_STACK_LOCATION(sp)
161
162         /* Prepare to enable interrupts above the current priority. */
163         srl                     k0, k0, 0xa
164         ins             k1, k0, 10, 7
165         srl                     k0, k0, 0x7 /* This copies the MSB of the IPL, but it would be an error if it was set anyway. */
166         ins             k1, k0, 18, 1
167         ins                     k1, zero, 1, 4
168
169         /* s5 is used as the frame pointer. */
170         add                     s5, zero, sp
171
172         /* Check the nesting count value. */
173         la                      k0, uxInterruptNesting
174         lw                      s6, (k0)
175
176         /* If the nesting count is 0 then swap to the the system stack, otherwise
177         the system stack is already being used. */
178         bne                     s6, zero, 1f
179         nop
180
181         /* Swap to the system stack. */
182         la                      sp, xISRStackTop
183         lw                      sp, (sp)
184
185         /* Increment and save the nesting count. */
186 1:      addiu           s6, s6, 1
187         sw                      s6, 0(k0)
188
189         /* s6 holds the EPC value, this is saved after interrupts are re-enabled. */
190         mfc0            s6, _CP0_EPC
191
192         /* Re-enable interrupts. */
193         mtc0            k1, _CP0_STATUS
194
195         /* Save the context into the space just created.  s6 is saved again
196         here as it now contains the EPC value.  No other s registers need be
197         saved. */
198         sw                      ra, 120(s5)
199         sw                      s8, 116(s5)
200         sw                      t9, 112(s5)
201         sw                      t8, 108(s5)
202         sw                      t7, 104(s5)
203         sw                      t6, 100(s5)
204         sw                      t5, 96(s5)
205         sw                      t4, 92(s5)
206         sw                      t3, 88(s5)
207         sw                      t2, 84(s5)
208         sw                      t1, 80(s5)
209         sw                      t0, 76(s5)
210         sw                      a3, 72(s5)
211         sw                      a2, 68(s5)
212         sw                      a1, 64(s5)
213         sw                      a0, 60(s5)
214         sw                      v1, 56(s5)
215         sw                      v0, 52(s5)
216         sw                      s6, portEPC_STACK_LOCATION(s5)
217         sw                      $1, 16(s5)
218
219         /* Save the AC0, AC1, AC2, AC3 registers from the DSP.  s6 is used as a
220         scratch register. */
221         mfhi            s6, $ac1
222         sw                      s6, 128(s5)
223         mflo            s6, $ac1
224         sw                      s6, 124(s5)
225
226         mfhi            s6, $ac2
227         sw                      s6, 136(s5)
228         mflo            s6, $ac2
229         sw                      s6, 132(s5)
230
231         mfhi            s6, $ac3
232         sw                      s6, 144(s5)
233         mflo            s6, $ac3
234         sw                      s6, 140(s5)
235
236         /* Save the DSP Control register */
237         rddsp           s6
238         sw                      s6, 148(s5)
239
240         /* ac0 is done separately to match the MX port. */
241         mfhi            s6, $ac0
242         sw                      s6, 12(s5)
243         mflo            s6, $ac0
244         sw                      s6, 8(s5)
245
246         /* Save the FPU context if the nesting count was zero. */
247         #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
248                 la                      s6, uxInterruptNesting
249                 lw                      s6, 0(s6)
250                 addiu           s6, s6, -1
251                 bne                     s6, zero, 1f
252                 nop
253
254                 /* Test if the current task needs the FPU context saving. */
255                 lw                      s6, portTASK_HAS_FPU_STACK_LOCATION(s5)
256                 beq                     s6, zero, 1f
257                 nop
258
259                 /* Save the FPU registers. */
260                 portSAVE_FPU_REGS ( portCONTEXT_SIZE + 8 ), s5
261
262                 /* Save the FPU status register */
263                 cfc1            s6, $f31
264                 sw                      s6, (portCONTEXT_SIZE + portFPCSR_STACK_LOCATION)(s5)
265
266                 1:
267         #endif
268
269         /* Update the task stack pointer value if nesting is zero. */
270         la                      s6, uxInterruptNesting
271         lw                      s6, (s6)
272         addiu           s6, s6, -1
273         bne                     s6, zero, 1f
274         nop
275
276         /* Save the stack pointer. */
277         la                      s6, uxSavedTaskStackPointer
278         sw                      s5, (s6)
279 1:
280         .endm
281
282 /******************************************************************/
283 .macro  portRESTORE_CONTEXT
284
285         /* Restore the stack pointer from the TCB.  This is only done if the
286         nesting count is 1. */
287         la                      s6, uxInterruptNesting
288         lw                      s6, (s6)
289         addiu           s6, s6, -1
290         bne                     s6, zero, 1f
291         nop
292         la                      s6, uxSavedTaskStackPointer
293         lw                      s5, (s6)
294
295     #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
296                 /* Restore the FPU context if required. */
297                 lw                      s6, portTASK_HAS_FPU_STACK_LOCATION(s5)
298                 beq                     s6, zero, 1f
299                 nop
300
301                 /* Restore the FPU registers. */
302                 portLOAD_FPU_REGS   ( portCONTEXT_SIZE + 8 ), s5
303
304                 /* Restore the FPU status register. */
305                 lw                      s6, ( portCONTEXT_SIZE + portFPCSR_STACK_LOCATION )(s5)
306                 ctc1            s6, $f31
307         #endif
308
309 1:
310
311         /* Restore the context. */
312         lw                      s6, 128(s5)
313         mthi            s6, $ac1
314         lw                      s6, 124(s5)
315         mtlo            s6, $ac1
316
317         lw                      s6, 136(s5)
318         mthi            s6, $ac2
319         lw                      s6, 132(s5)
320         mtlo            s6, $ac2
321
322         lw                      s6, 144(s5)
323         mthi            s6, $ac3
324         lw                      s6, 140(s5)
325         mtlo            s6, $ac3
326
327         /* Restore DSPControl. */
328         lw                      s6, 148(s5)
329         wrdsp           s6
330
331         lw                      s6, 8(s5)
332         mtlo            s6, $ac0
333         lw                      s6, 12(s5)
334         mthi            s6, $ac0
335         lw                      $1, 16(s5)
336
337         /* s6 is loaded as it was used as a scratch register and therefore saved
338         as part of the interrupt context. */
339         lw                      s7, 48(s5)
340         lw                      s6, 44(s5)
341         lw                      v0, 52(s5)
342         lw                      v1, 56(s5)
343         lw                      a0, 60(s5)
344         lw                      a1, 64(s5)
345         lw                      a2, 68(s5)
346         lw                      a3, 72(s5)
347         lw                      t0, 76(s5)
348         lw                      t1, 80(s5)
349         lw                      t2, 84(s5)
350         lw                      t3, 88(s5)
351         lw                      t4, 92(s5)
352         lw                      t5, 96(s5)
353         lw                      t6, 100(s5)
354         lw                      t7, 104(s5)
355         lw                      t8, 108(s5)
356         lw                      t9, 112(s5)
357         lw                      s8, 116(s5)
358         lw                      ra, 120(s5)
359
360         /* Protect access to the k registers, and others. */
361         di
362         ehb
363
364         /* Decrement the nesting count. */
365         la                      k0, uxInterruptNesting
366         lw                      k1, (k0)
367         addiu           k1, k1, -1
368         sw                      k1, 0(k0)
369
370         #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
371                 /* If the nesting count is now zero then the FPU context may be restored. */
372                 bne                     k1, zero, 1f
373                 nop
374
375                 /* Restore the value of ulTaskHasFPUContext */
376                 la                      k0, ulTaskHasFPUContext
377                 lw                      k1, 0(s5)
378                 sw                      k1, 0(k0)
379
380                 /* If the task does not have an FPU context then adjust the stack normally. */
381                 beq                     k1, zero, 1f
382                 nop
383
384                 /* Restore the STATUS and EPC registers */
385                 lw                      k0, portSTATUS_STACK_LOCATION(s5)
386                 lw                      k1, portEPC_STACK_LOCATION(s5)
387
388                 /* Leave the stack in its original state.  First load sp from s5, then
389                 restore s5 from the stack. */
390                 add                     sp, zero, s5
391                 lw                      s5, 40(sp)
392
393                 /* Adjust the stack pointer to remove the FPU context */
394                 addiu           sp, sp, portFPU_CONTEXT_SIZE
395                 beq                     zero, zero, 2f
396                 nop
397
398                 1:  /* Restore the STATUS and EPC registers */
399                 lw                      k0, portSTATUS_STACK_LOCATION(s5)
400                 lw                      k1, portEPC_STACK_LOCATION(s5)
401
402                 /* Leave the stack in its original state.  First load sp from s5, then
403                 restore s5 from the stack. */
404                 add                     sp, zero, s5
405                 lw                      s5, 40(sp)
406
407                 2:  /* Adjust the stack pointer */
408                 addiu           sp, sp, portCONTEXT_SIZE
409
410         #else
411
412                 /* Restore the frame when there is no hardware FP support. */
413                 lw                      k0, portSTATUS_STACK_LOCATION(s5)
414                 lw                      k1, portEPC_STACK_LOCATION(s5)
415
416                 /* Leave the stack in its original state.  First load sp from s5, then
417                 restore s5 from the stack. */
418                 add                     sp, zero, s5
419                 lw                      s5, 40(sp)
420
421                 addiu           sp, sp, portCONTEXT_SIZE
422
423         #endif // ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
424
425         mtc0            k0, _CP0_STATUS
426         mtc0            k1, _CP0_EPC
427         ehb
428         eret
429         nop
430
431         .endm
432