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