]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/MPLAB/PIC32MZ/port_asm.S
Prepare for V9.0.0 release:
[freertos] / FreeRTOS / Source / portable / MPLAB / PIC32MZ / port_asm.S
1 /*\r
2     FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.\r
12 \r
13     ***************************************************************************\r
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16     >>!   obliged to provide the source code for proprietary components     !<<\r
17     >>!   outside of the FreeRTOS kernel.                                   !<<\r
18     ***************************************************************************\r
19 \r
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23     link: http://www.freertos.org/a00114.html\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    FreeRTOS provides completely free yet professionally developed,    *\r
28      *    robust, strictly quality controlled, supported, and cross          *\r
29      *    platform software that is more than just the market leader, it     *\r
30      *    is the industry's de facto standard.                               *\r
31      *                                                                       *\r
32      *    Help yourself get started quickly while simultaneously helping     *\r
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34      *    tutorial book, reference manual, or both:                          *\r
35      *    http://www.FreeRTOS.org/Documentation                              *\r
36      *                                                                       *\r
37     ***************************************************************************\r
38 \r
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40     the FAQ page "My application does not run, what could be wrong?".  Have you\r
41     defined configASSERT()?\r
42 \r
43     http://www.FreeRTOS.org/support - In return for receiving this top quality\r
44     embedded software for free we request you assist our global community by\r
45     participating in the support forum.\r
46 \r
47     http://www.FreeRTOS.org/training - Investing in training allows your team to\r
48     be as productive as possible as early as possible.  Now you can receive\r
49     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50     Ltd, and the world's leading authority on the world's leading RTOS.\r
51 \r
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55 \r
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58 \r
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
61     licenses offer ticketed support, indemnification and commercial middleware.\r
62 \r
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
64     engineered and independently SIL3 certified version for use in safety and\r
65     mission critical applications that require provable dependability.\r
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 #include <xc.h>\r
71 #include <sys/asm.h>\r
72 #include "FreeRTOSConfig.h"\r
73 #include "ISR_Support.h"\r
74 \r
75         .extern pxCurrentTCB\r
76         .extern vTaskSwitchContext\r
77         .extern vPortIncrementTick\r
78         .extern xISRStackTop\r
79         .extern ulTaskHasFPUContext\r
80 \r
81         .global vPortStartFirstTask\r
82         .global vPortYieldISR\r
83         .global vPortTickInterruptHandler\r
84         .global vPortInitialiseFPSCR\r
85 \r
86 \r
87 /******************************************************************/\r
88 \r
89         .set  nomips16\r
90         .set  nomicromips\r
91         .set  noreorder\r
92         .set  noat\r
93 \r
94         /***************************************************************\r
95         *  The following is needed to locate the\r
96         *  vPortTickInterruptHandler function into the correct vector\r
97         ***************************************************************/\r
98         #ifdef configTICK_INTERRUPT_VECTOR\r
99                 #if (configTICK_INTERRUPT_VECTOR == _CORE_TIMER_VECTOR)\r
100                         .equ     __vector_dispatch_0, vPortTickInterruptHandler\r
101                         .global  __vector_dispatch_0\r
102                         .section .vector_0, code, keep\r
103                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_1_VECTOR)\r
104                         .equ     __vector_dispatch_4, vPortTickInterruptHandler\r
105                         .global  __vector_dispatch_4\r
106                         .section .vector_4, code, keep\r
107                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_2_VECTOR)\r
108                         .equ     __vector_dispatch_9, vPortTickInterruptHandler\r
109                         .global  __vector_dispatch_9\r
110                         .section .vector_9, code, keep\r
111                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_3_VECTOR)\r
112                         .equ     __vector_dispatch_14, vPortTickInterruptHandler\r
113                         .global  __vector_dispatch_14\r
114                         .section .vector_14, code, keep\r
115                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_4_VECTOR)\r
116                         .equ     __vector_dispatch_19, vPortTickInterruptHandler\r
117                         .global  __vector_dispatch_19\r
118                         .section .vector_19, code, keep\r
119                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_5_VECTOR)\r
120                         .equ     __vector_dispatch_24, vPortTickInterruptHandler\r
121                         .global  __vector_dispatch_24\r
122                         .section .vector_24, code, keep\r
123                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_6_VECTOR)\r
124                         .equ     __vector_dispatch_28, vPortTickInterruptHandler\r
125                         .global  __vector_dispatch_28\r
126                         .section .vector_28, code, keep\r
127                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_7_VECTOR)\r
128                         .equ     __vector_dispatch_32, vPortTickInterruptHandler\r
129                         .global  __vector_dispatch_32\r
130                         .section .vector_32, code, keep\r
131                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_8_VECTOR)\r
132                         .equ     __vector_dispatch_36, vPortTickInterruptHandler\r
133                         .global  __vector_dispatch_36\r
134                         .section .vector_36, code, keep\r
135                 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_9_VECTOR)\r
136                         .equ     __vector_dispatch_40, vPortTickInterruptHandler\r
137                         .global  __vector_dispatch_40\r
138                         .section .vector_40, code, keep\r
139                 #endif\r
140         #else\r
141                 .equ     __vector_dispatch_4, vPortTickInterruptHandler\r
142                 .global  __vector_dispatch_4\r
143                 .section .vector_4, code, keep\r
144         #endif\r
145 \r
146         .ent            vPortTickInterruptHandler\r
147 \r
148 vPortTickInterruptHandler:\r
149 \r
150         portSAVE_CONTEXT\r
151 \r
152         jal             vPortIncrementTick\r
153         nop\r
154 \r
155         portRESTORE_CONTEXT\r
156 \r
157         .end vPortTickInterruptHandler\r
158 \r
159 /******************************************************************/\r
160 \r
161         .set            noreorder\r
162         .set            noat\r
163         .section .text, code\r
164         .ent            vPortStartFirstTask\r
165 \r
166 vPortStartFirstTask:\r
167 \r
168         /* Simply restore the context of the highest priority task that has been\r
169         created so far. */\r
170         portRESTORE_CONTEXT\r
171 \r
172         .end vPortStartFirstTask\r
173 \r
174 \r
175 \r
176 /*******************************************************************/\r
177 \r
178         .set  nomips16\r
179         .set  nomicromips\r
180         .set  noreorder\r
181         .set  noat\r
182         /***************************************************************\r
183         *  The following is needed to locate the vPortYieldISR function\r
184         *  into the correct vector\r
185         ***************************************************************/\r
186         .equ     __vector_dispatch_1, vPortYieldISR\r
187         .global  __vector_dispatch_1\r
188         .section .vector_1, code\r
189 \r
190         .ent  vPortYieldISR\r
191 vPortYieldISR:\r
192 \r
193         #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )\r
194                 /* Code sequence for FPU support, the context save requires advance\r
195                 knowledge of the stack frame size and if the current task actually uses the \r
196                 FPU. */\r
197 \r
198                 /* Make room for the context. First save the current status so it can be\r
199                 manipulated, and the cause and EPC registers so their original values are\r
200                 captured. */\r
201                 la              k0, ulTaskHasFPUContext\r
202                 lw              k0, 0(k0)\r
203                 beq             k0, zero, 1f\r
204                 addiu   sp, sp, -portCONTEXT_SIZE       /* always reserve space for the context. */\r
205                 addiu   sp, sp, -portFPU_CONTEXT_SIZE   /* reserve additional space for the FPU context. */\r
206         1:\r
207                 mfc0    k1, _CP0_STATUS\r
208 \r
209                 /* Also save s6 and s5 so they can be used.  Any nesting interrupts should\r
210                 maintain the values of these registers across the ISR. */\r
211                 sw              s6, 44(sp)\r
212                 sw              s5, 40(sp)\r
213                 sw              k1, portSTATUS_STACK_LOCATION(sp)\r
214                 sw              k0, portTASK_HAS_FPU_STACK_LOCATION(sp)\r
215 \r
216                 /* Prepare to re-enabled interrupts above the kernel priority. */\r
217                 ins     k1, zero, 10, 7         /* Clear IPL bits 0:6. */\r
218                 ins     k1, zero, 18, 1         /* Clear IPL bit 7.  It would be an error here if this bit were set anyway. */\r
219                 ori             k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 )\r
220                 ins             k1, zero, 1, 4          /* Clear EXL, ERL and UM. */\r
221 \r
222                 /* s5 is used as the frame pointer. */\r
223                 add             s5, zero, sp\r
224 \r
225                 /* Swap to the system stack.  This is not conditional on the nesting\r
226                 count as this interrupt is always the lowest priority and therefore\r
227                 the nesting is always 0. */\r
228                 la              sp, xISRStackTop\r
229                 lw              sp, (sp)\r
230 \r
231                 /* Set the nesting count. */\r
232                 la              k0, uxInterruptNesting\r
233                 addiu   s6, zero, 1\r
234                 sw              s6, 0(k0)\r
235 \r
236                 /* s6 holds the EPC value, this is saved with the rest of the context\r
237                 after interrupts are enabled. */\r
238                 mfc0    s6, _CP0_EPC\r
239 \r
240                 /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */\r
241                 mtc0    k1, _CP0_STATUS\r
242 \r
243                 /* Save the context into the space just created.  s6 is saved again\r
244                 here as it now contains the EPC value. */\r
245                 sw              ra, 120(s5)\r
246                 sw              s8, 116(s5)\r
247                 sw              t9, 112(s5)\r
248                 sw              t8, 108(s5)\r
249                 sw              t7, 104(s5)\r
250                 sw              t6, 100(s5)\r
251                 sw              t5, 96(s5)\r
252                 sw              t4, 92(s5)\r
253                 sw              t3, 88(s5)\r
254                 sw              t2, 84(s5)\r
255                 sw              t1, 80(s5)\r
256                 sw              t0, 76(s5)\r
257                 sw              a3, 72(s5)\r
258                 sw              a2, 68(s5)\r
259                 sw              a1, 64(s5)\r
260                 sw              a0, 60(s5)\r
261                 sw              v1, 56(s5)\r
262                 sw              v0, 52(s5)\r
263                 sw              s7, 48(s5)\r
264                 sw              s6, portEPC_STACK_LOCATION(s5)\r
265                 /* s5 and s6 has already been saved. */\r
266                 sw              s4, 36(s5)\r
267                 sw              s3, 32(s5)\r
268                 sw              s2, 28(s5)\r
269                 sw              s1, 24(s5)\r
270                 sw              s0, 20(s5)\r
271                 sw              $1, 16(s5)\r
272 \r
273                 /* s7 is used as a scratch register as this should always be saved across\r
274                 nesting interrupts. */\r
275 \r
276                 /* Save the AC0, AC1, AC2 and AC3. */\r
277                 mfhi    s7, $ac1\r
278                 sw              s7, 128(s5)\r
279                 mflo    s7, $ac1\r
280                 sw              s7, 124(s5)\r
281 \r
282                 mfhi    s7, $ac2\r
283                 sw              s7, 136(s5)\r
284                 mflo    s7, $ac2\r
285                 sw              s7, 132(s5)\r
286 \r
287                 mfhi    s7, $ac3\r
288                 sw              s7, 144(s5)\r
289                 mflo    s7, $ac3\r
290                 sw              s7, 140(s5)\r
291 \r
292                 rddsp   s7\r
293                 sw              s7, 148(s5)\r
294 \r
295                 mfhi    s7, $ac0\r
296                 sw              s7, 12(s5)\r
297                 mflo    s7, $ac0\r
298                 sw              s7, 8(s5)\r
299 \r
300                 /* Test if FPU context save is required. */\r
301                 lw              s7, portTASK_HAS_FPU_STACK_LOCATION(s5)\r
302                 beq             s7, zero, 1f\r
303                 nop\r
304 \r
305                 /* Save the FPU registers above the normal context. */\r
306                 portSAVE_FPU_REGS   (portCONTEXT_SIZE + 8), s5\r
307 \r
308                 /* Save the FPU status register */\r
309                 cfc1    s7, $f31\r
310                 sw              s7, ( portCONTEXT_SIZE + portFPCSR_STACK_LOCATION )(s5)\r
311 \r
312         1:\r
313                 /* Save the stack pointer to the task. */\r
314                 la              s7, pxCurrentTCB\r
315                 lw              s7, (s7)\r
316                 sw              s5, (s7)\r
317 \r
318                 /* Set the interrupt mask to the max priority that can use the API.  The\r
319                 yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which\r
320                 is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever\r
321                 raise the IPL value and never lower it. */\r
322                 di\r
323                 ehb\r
324                 mfc0    s7, _CP0_STATUS\r
325                 ins     s7, zero, 10, 7\r
326                 ins     s7, zero, 18, 1\r
327                 ori             s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1\r
328 \r
329                 /* This mtc0 re-enables interrupts, but only above\r
330                 configMAX_SYSCALL_INTERRUPT_PRIORITY. */\r
331                 mtc0    s6, _CP0_STATUS\r
332                 ehb\r
333 \r
334                 /* Clear the software interrupt in the core. */\r
335                 mfc0    s6, _CP0_CAUSE\r
336                 ins             s6, zero, 8, 1\r
337                 mtc0    s6, _CP0_CAUSE\r
338                 ehb\r
339 \r
340                 /* Clear the interrupt in the interrupt controller. */\r
341                 la              s6, IFS0CLR\r
342                 addiu   s4, zero, 2\r
343                 sw              s4, (s6)\r
344 \r
345                 jal             vTaskSwitchContext\r
346                 nop\r
347 \r
348                 /* Clear the interrupt mask again.  The saved status value is still in s7. */\r
349                 mtc0    s7, _CP0_STATUS\r
350                 ehb\r
351 \r
352                 /* Restore the stack pointer from the TCB. */\r
353                 la              s0, pxCurrentTCB\r
354                 lw              s0, (s0)\r
355                 lw              s5, (s0)\r
356 \r
357                 /* Test if the FPU context needs restoring. */\r
358                 lw              s0, portTASK_HAS_FPU_STACK_LOCATION(s5)\r
359                 beq             s0, zero, 1f\r
360                 nop\r
361 \r
362                 /* Restore the FPU status register. */\r
363                 lw              s0, ( portCONTEXT_SIZE + portFPCSR_STACK_LOCATION )(s5)\r
364                 ctc1    s0, $f31\r
365 \r
366                 /* Restore the FPU registers. */\r
367                 portLOAD_FPU_REGS   ( portCONTEXT_SIZE + 8 ), s5\r
368 \r
369         1:\r
370                 /* Restore the rest of the context. */\r
371                 lw              s0, 128(s5)\r
372                 mthi    s0, $ac1\r
373                 lw              s0, 124(s5)\r
374                 mtlo            s0, $ac1\r
375 \r
376                 lw              s0, 136(s5)\r
377                 mthi    s0, $ac2\r
378                 lw              s0, 132(s5)\r
379                 mtlo    s0, $ac2\r
380 \r
381                 lw              s0, 144(s5)\r
382                 mthi    s0, $ac3\r
383                 lw              s0, 140(s5)\r
384                 mtlo    s0, $ac3\r
385 \r
386                 lw              s0, 148(s5)\r
387                 wrdsp   s0\r
388 \r
389                 lw              s0, 8(s5)\r
390                 mtlo    s0, $ac0\r
391                 lw              s0, 12(s5)\r
392                 mthi    s0, $ac0\r
393 \r
394                 lw              $1, 16(s5)\r
395                 lw              s0, 20(s5)\r
396                 lw              s1, 24(s5)\r
397                 lw              s2, 28(s5)\r
398                 lw              s3, 32(s5)\r
399                 lw              s4, 36(s5)\r
400 \r
401                 /* s5 is loaded later. */\r
402                 lw              s6, 44(s5)\r
403                 lw              s7, 48(s5)\r
404                 lw              v0, 52(s5)\r
405                 lw              v1, 56(s5)\r
406                 lw              a0, 60(s5)\r
407                 lw              a1, 64(s5)\r
408                 lw              a2, 68(s5)\r
409                 lw              a3, 72(s5)\r
410                 lw              t0, 76(s5)\r
411                 lw              t1, 80(s5)\r
412                 lw              t2, 84(s5)\r
413                 lw              t3, 88(s5)\r
414                 lw              t4, 92(s5)\r
415                 lw              t5, 96(s5)\r
416                 lw              t6, 100(s5)\r
417                 lw              t7, 104(s5)\r
418                 lw              t8, 108(s5)\r
419                 lw              t9, 112(s5)\r
420                 lw              s8, 116(s5)\r
421                 lw              ra, 120(s5)\r
422 \r
423                 /* Protect access to the k registers, and others. */\r
424                 di\r
425                 ehb\r
426 \r
427                 /* Set nesting back to zero.  As the lowest priority interrupt this\r
428                 interrupt cannot have nested. */\r
429                 la              k0, uxInterruptNesting\r
430                 sw              zero, 0(k0)\r
431 \r
432                 /* Switch back to use the real stack pointer. */\r
433                 add             sp, zero, s5\r
434 \r
435                 /* Restore the real s5 value. */\r
436                 lw              s5, 40(sp)\r
437 \r
438                 /* Pop the FPU context value from the stack */\r
439                 lw              k0, portTASK_HAS_FPU_STACK_LOCATION(sp)\r
440                 la              k1, ulTaskHasFPUContext\r
441                 sw              k0, 0(k1)\r
442                 beq             k0, zero, 1f\r
443                 nop\r
444 \r
445                 /* task has FPU context so adjust the stack frame after popping the\r
446                 status and epc values. */\r
447                 lw              k1, portSTATUS_STACK_LOCATION(sp)\r
448                 lw              k0, portEPC_STACK_LOCATION(sp)\r
449                 addiu   sp, sp, portFPU_CONTEXT_SIZE\r
450                 beq             zero, zero, 2f\r
451                 nop\r
452 \r
453         1:\r
454                 /* Pop the status and epc values. */\r
455                 lw              k1, portSTATUS_STACK_LOCATION(sp)\r
456                 lw              k0, portEPC_STACK_LOCATION(sp)\r
457 \r
458         2:\r
459                 /* Remove stack frame. */\r
460                 addiu   sp, sp, portCONTEXT_SIZE\r
461 \r
462         #else\r
463                 /* Code sequence for no FPU support, the context save requires advance\r
464                 knowledge of the stack frame size when no FPU is being used */\r
465 \r
466                 /* Make room for the context. First save the current status so it can be\r
467                 manipulated, and the cause and EPC registers so thier original values are\r
468                 captured. */\r
469                 addiu   sp, sp, -portCONTEXT_SIZE\r
470                 mfc0    k1, _CP0_STATUS\r
471 \r
472                 /* Also save s6 and s5 so they can be used.  Any nesting interrupts should\r
473                 maintain the values of these registers across the ISR. */\r
474                 sw              s6, 44(sp)\r
475                 sw              s5, 40(sp)\r
476                 sw              k1, portSTATUS_STACK_LOCATION(sp)\r
477 \r
478                 /* Prepare to re-enabled interrupts above the kernel priority. */\r
479                 ins     k1, zero, 10, 7         /* Clear IPL bits 0:6. */\r
480                 ins     k1, zero, 18, 1         /* Clear IPL bit 7.  It would be an error here if this bit were set anyway. */\r
481                 ori             k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 )\r
482                 ins             k1, zero, 1, 4          /* Clear EXL, ERL and UM. */\r
483 \r
484                 /* s5 is used as the frame pointer. */\r
485                 add             s5, zero, sp\r
486 \r
487                 /* Swap to the system stack.  This is not conditional on the nesting\r
488                 count as this interrupt is always the lowest priority and therefore\r
489                 the nesting is always 0. */\r
490                 la              sp, xISRStackTop\r
491                 lw              sp, (sp)\r
492 \r
493                 /* Set the nesting count. */\r
494                 la              k0, uxInterruptNesting\r
495                 addiu   s6, zero, 1\r
496                 sw              s6, 0(k0)\r
497 \r
498                 /* s6 holds the EPC value, this is saved with the rest of the context\r
499                 after interrupts are enabled. */\r
500                 mfc0    s6, _CP0_EPC\r
501 \r
502                 /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */\r
503                 mtc0    k1, _CP0_STATUS\r
504 \r
505                 /* Save the context into the space just created.  s6 is saved again\r
506                 here as it now contains the EPC value. */\r
507                 sw              ra, 120(s5)\r
508                 sw              s8, 116(s5)\r
509                 sw              t9, 112(s5)\r
510                 sw              t8, 108(s5)\r
511                 sw              t7, 104(s5)\r
512                 sw              t6, 100(s5)\r
513                 sw              t5, 96(s5)\r
514                 sw              t4, 92(s5)\r
515                 sw              t3, 88(s5)\r
516                 sw              t2, 84(s5)\r
517                 sw              t1, 80(s5)\r
518                 sw              t0, 76(s5)\r
519                 sw              a3, 72(s5)\r
520                 sw              a2, 68(s5)\r
521                 sw              a1, 64(s5)\r
522                 sw              a0, 60(s5)\r
523                 sw              v1, 56(s5)\r
524                 sw              v0, 52(s5)\r
525                 sw              s7, 48(s5)\r
526                 sw              s6, portEPC_STACK_LOCATION(s5)\r
527                 /* s5 and s6 has already been saved. */\r
528                 sw              s4, 36(s5)\r
529                 sw              s3, 32(s5)\r
530                 sw              s2, 28(s5)\r
531                 sw              s1, 24(s5)\r
532                 sw              s0, 20(s5)\r
533                 sw              $1, 16(s5)\r
534 \r
535                 /* s7 is used as a scratch register as this should always be saved across\r
536                 nesting interrupts. */\r
537 \r
538                 /* Save the AC0, AC1, AC2 and AC3. */\r
539                 mfhi    s7, $ac1\r
540                 sw              s7, 128(s5)\r
541                 mflo    s7, $ac1\r
542                 sw              s7, 124(s5)\r
543 \r
544                 mfhi    s7, $ac2\r
545                 sw              s7, 136(s5)\r
546                 mflo    s7, $ac2\r
547                 sw              s7, 132(s5)\r
548 \r
549                 mfhi    s7, $ac3\r
550                 sw              s7, 144(s5)\r
551                 mflo    s7, $ac3\r
552                 sw              s7, 140(s5)\r
553 \r
554                 rddsp   s7\r
555                 sw              s7, 148(s5)\r
556 \r
557                 mfhi    s7, $ac0\r
558                 sw              s7, 12(s5)\r
559                 mflo    s7, $ac0\r
560                 sw              s7, 8(s5)\r
561 \r
562                 /* Save the stack pointer to the task. */\r
563                 la              s7, pxCurrentTCB\r
564                 lw              s7, (s7)\r
565                 sw              s5, (s7)\r
566 \r
567                 /* Set the interrupt mask to the max priority that can use the API.  The\r
568                 yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which\r
569                 is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever\r
570                 raise the IPL value and never lower it. */\r
571                 di\r
572                 ehb\r
573                 mfc0    s7, _CP0_STATUS\r
574                 ins     s7, zero, 10, 7\r
575                 ins     s7, zero, 18, 1\r
576                 ori             s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1\r
577 \r
578                 /* This mtc0 re-enables interrupts, but only above\r
579                 configMAX_SYSCALL_INTERRUPT_PRIORITY. */\r
580                 mtc0    s6, _CP0_STATUS\r
581                 ehb\r
582 \r
583                 /* Clear the software interrupt in the core. */\r
584                 mfc0    s6, _CP0_CAUSE\r
585                 ins             s6, zero, 8, 1\r
586                 mtc0    s6, _CP0_CAUSE\r
587                 ehb\r
588 \r
589                 /* Clear the interrupt in the interrupt controller. */\r
590                 la              s6, IFS0CLR\r
591                 addiu   s4, zero, 2\r
592                 sw              s4, (s6)\r
593 \r
594                 jal             vTaskSwitchContext\r
595                 nop\r
596 \r
597                 /* Clear the interrupt mask again.  The saved status value is still in s7. */\r
598                 mtc0    s7, _CP0_STATUS\r
599                 ehb\r
600 \r
601                 /* Restore the stack pointer from the TCB. */\r
602                 la              s0, pxCurrentTCB\r
603                 lw              s0, (s0)\r
604                 lw              s5, (s0)\r
605 \r
606                 /* Restore the rest of the context. */\r
607                 lw              s0, 128(s5)\r
608                 mthi    s0, $ac1\r
609                 lw              s0, 124(s5)\r
610                 mtlo    s0, $ac1\r
611 \r
612                 lw              s0, 136(s5)\r
613                 mthi    s0, $ac2\r
614                 lw              s0, 132(s5)\r
615                 mtlo    s0, $ac2\r
616 \r
617                 lw              s0, 144(s5)\r
618                 mthi    s0, $ac3\r
619                 lw              s0, 140(s5)\r
620                 mtlo    s0, $ac3\r
621 \r
622                 lw              s0, 148(s5)\r
623                 wrdsp   s0\r
624 \r
625                 lw              s0, 8(s5)\r
626                 mtlo    s0, $ac0\r
627                 lw              s0, 12(s5)\r
628                 mthi    s0, $ac0\r
629 \r
630                 lw              $1, 16(s5)\r
631                 lw              s0, 20(s5)\r
632                 lw              s1, 24(s5)\r
633                 lw              s2, 28(s5)\r
634                 lw              s3, 32(s5)\r
635                 lw              s4, 36(s5)\r
636 \r
637                 /* s5 is loaded later. */\r
638                 lw              s6, 44(s5)\r
639                 lw              s7, 48(s5)\r
640                 lw              v0, 52(s5)\r
641                 lw              v1, 56(s5)\r
642                 lw              a0, 60(s5)\r
643                 lw              a1, 64(s5)\r
644                 lw              a2, 68(s5)\r
645                 lw              a3, 72(s5)\r
646                 lw              t0, 76(s5)\r
647                 lw              t1, 80(s5)\r
648                 lw              t2, 84(s5)\r
649                 lw              t3, 88(s5)\r
650                 lw              t4, 92(s5)\r
651                 lw              t5, 96(s5)\r
652                 lw              t6, 100(s5)\r
653                 lw              t7, 104(s5)\r
654                 lw              t8, 108(s5)\r
655                 lw              t9, 112(s5)\r
656                 lw              s8, 116(s5)\r
657                 lw              ra, 120(s5)\r
658 \r
659                 /* Protect access to the k registers, and others. */\r
660                 di\r
661                 ehb\r
662 \r
663                 /* Set nesting back to zero.  As the lowest priority interrupt this\r
664                 interrupt cannot have nested. */\r
665                 la              k0, uxInterruptNesting\r
666                 sw              zero, 0(k0)\r
667 \r
668                 /* Switch back to use the real stack pointer. */\r
669                 add             sp, zero, s5\r
670 \r
671                 /* Restore the real s5 value. */\r
672                 lw              s5, 40(sp)\r
673 \r
674                 /* Pop the status and epc values. */\r
675                 lw              k1, portSTATUS_STACK_LOCATION(sp)\r
676                 lw              k0, portEPC_STACK_LOCATION(sp)\r
677 \r
678                 /* Remove stack frame. */\r
679                 addiu   sp, sp, portCONTEXT_SIZE\r
680 \r
681         #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */\r
682 \r
683         /* Restore the status and EPC registers and return */\r
684         mtc0    k1, _CP0_STATUS\r
685         mtc0    k0, _CP0_EPC\r
686         ehb\r
687         eret\r
688         nop\r
689 \r
690         .end    vPortYieldISR\r
691 \r
692 /******************************************************************/\r
693 \r
694 #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )\r
695 \r
696         .macro portFPUSetAndInc reg, dest\r
697         mtc1    \reg, \dest\r
698         cvt.d.w \dest, \dest\r
699         addiu   \reg, \reg, 1\r
700         .endm\r
701 \r
702         .set    noreorder\r
703         .set    noat\r
704         .section .text, code\r
705         .ent    vPortInitialiseFPSCR\r
706 \r
707 vPortInitialiseFPSCR:\r
708 \r
709         /* Initialize the floating point status register in CP1. The initial\r
710         value is passed in a0. */\r
711         ctc1            a0, $f31\r
712 \r
713         /* Clear the FPU registers */\r
714         addiu                   a0, zero, 0x0000\r
715         portFPUSetAndInc        a0, $f0\r
716         portFPUSetAndInc        a0, $f1\r
717         portFPUSetAndInc        a0, $f2\r
718         portFPUSetAndInc        a0, $f3\r
719         portFPUSetAndInc        a0, $f4\r
720         portFPUSetAndInc        a0, $f5\r
721         portFPUSetAndInc        a0, $f6\r
722         portFPUSetAndInc        a0, $f7\r
723         portFPUSetAndInc        a0, $f8\r
724         portFPUSetAndInc        a0, $f9\r
725         portFPUSetAndInc        a0, $f10\r
726         portFPUSetAndInc        a0, $f11\r
727         portFPUSetAndInc        a0, $f12\r
728         portFPUSetAndInc        a0, $f13\r
729         portFPUSetAndInc        a0, $f14\r
730         portFPUSetAndInc        a0, $f15\r
731         portFPUSetAndInc        a0, $f16\r
732         portFPUSetAndInc        a0, $f17\r
733         portFPUSetAndInc        a0, $f18\r
734         portFPUSetAndInc        a0, $f19\r
735         portFPUSetAndInc        a0, $f20\r
736         portFPUSetAndInc        a0, $f21\r
737         portFPUSetAndInc        a0, $f22\r
738         portFPUSetAndInc        a0, $f23\r
739         portFPUSetAndInc        a0, $f24\r
740         portFPUSetAndInc        a0, $f25\r
741         portFPUSetAndInc        a0, $f26\r
742         portFPUSetAndInc        a0, $f27\r
743         portFPUSetAndInc        a0, $f28\r
744         portFPUSetAndInc        a0, $f29\r
745         portFPUSetAndInc        a0, $f30\r
746         portFPUSetAndInc        a0, $f31\r
747 \r
748         jr              ra\r
749         nop\r
750 \r
751         .end vPortInitialiseFPSCR\r
752 \r
753 #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */\r
754         \r
755 #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )\r
756 \r
757         /**********************************************************************/\r
758         /* Test read back                                                               */\r
759         /* a0 = address to store registers                              */\r
760 \r
761         .set            noreorder\r
762         .set            noat\r
763         .section        .text, code\r
764         .ent            vPortFPUReadback\r
765         .global         vPortFPUReadback\r
766 \r
767 vPortFPUReadback:\r
768         sdc1            $f0, 0(a0)\r
769         sdc1            $f1, 8(a0)\r
770         sdc1            $f2, 16(a0)\r
771         sdc1            $f3, 24(a0)\r
772         sdc1            $f4, 32(a0)\r
773         sdc1            $f5, 40(a0)\r
774         sdc1            $f6, 48(a0)\r
775         sdc1            $f7, 56(a0)\r
776         sdc1            $f8, 64(a0)\r
777         sdc1            $f9, 72(a0)\r
778         sdc1            $f10, 80(a0)\r
779         sdc1            $f11, 88(a0)\r
780         sdc1            $f12, 96(a0)\r
781         sdc1            $f13, 104(a0)\r
782         sdc1            $f14, 112(a0)\r
783         sdc1            $f15, 120(a0)\r
784         sdc1            $f16, 128(a0)\r
785         sdc1            $f17, 136(a0)\r
786         sdc1            $f18, 144(a0)\r
787         sdc1            $f19, 152(a0)\r
788         sdc1            $f20, 160(a0)\r
789         sdc1            $f21, 168(a0)\r
790         sdc1            $f22, 176(a0)\r
791         sdc1            $f23, 184(a0)\r
792         sdc1            $f24, 192(a0)\r
793         sdc1            $f25, 200(a0)\r
794         sdc1            $f26, 208(a0)\r
795         sdc1            $f27, 216(a0)\r
796         sdc1            $f28, 224(a0)\r
797         sdc1            $f29, 232(a0)\r
798         sdc1            $f30, 240(a0)\r
799         sdc1            $f31, 248(a0)\r
800 \r
801         jr              ra\r
802         nop\r
803 \r
804         .end vPortFPUReadback\r
805 \r
806 #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */\r
807 \r
808 \r
809 \r
810 \r