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