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