]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/MPLAB/PIC32MX/port_asm.S
8c9ee04b0afd4bdaad519628395316a26826577e
[freertos] / FreeRTOS / Source / portable / MPLAB / PIC32MX / port_asm.S
1 /*\r
2     FreeRTOS V7.5.1 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
5 \r
6     ***************************************************************************\r
7      *                                                                       *\r
8      *    FreeRTOS provides completely free yet professionally developed,    *\r
9      *    robust, strictly quality controlled, supported, and cross          *\r
10      *    platform software that has become a de facto standard.             *\r
11      *                                                                       *\r
12      *    Help yourself get started quickly and support the FreeRTOS         *\r
13      *    project by purchasing a FreeRTOS tutorial book, reference          *\r
14      *    manual, or both from: http://www.FreeRTOS.org/Documentation        *\r
15      *                                                                       *\r
16      *    Thank you!                                                         *\r
17      *                                                                       *\r
18     ***************************************************************************\r
19 \r
20     This file is part of the FreeRTOS distribution.\r
21 \r
22     FreeRTOS is free software; you can redistribute it and/or modify it under\r
23     the terms of the GNU General Public License (version 2) as published by the\r
24     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
25 \r
26     >>! NOTE: The modification to the GPL is included to allow you to distribute\r
27     >>! a combined work that includes FreeRTOS without being obliged to provide\r
28     >>! the source code for proprietary components outside of the FreeRTOS\r
29     >>! kernel.\r
30 \r
31     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
32     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
33     FOR A PARTICULAR PURPOSE.  Full license text is available from the following\r
34     link: http://www.freertos.org/a00114.html\r
35 \r
36     1 tab == 4 spaces!\r
37 \r
38     ***************************************************************************\r
39      *                                                                       *\r
40      *    Having a problem?  Start by reading the FAQ "My application does   *\r
41      *    not run, what could be wrong?"                                     *\r
42      *                                                                       *\r
43      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
44      *                                                                       *\r
45     ***************************************************************************\r
46 \r
47     http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
48     license and Real Time Engineers Ltd. contact details.\r
49 \r
50     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
51     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
52     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
53 \r
54     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
55     Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
56     licenses offer ticketed support, indemnification and middleware.\r
57 \r
58     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
59     engineered and independently SIL3 certified version for use in safety and\r
60     mission critical applications that require provable dependability.\r
61 \r
62     1 tab == 4 spaces!\r
63 */\r
64 \r
65 #include <xc.h>\r
66 #include <sys/asm.h>\r
67 #include "ISR_Support.h"\r
68 \r
69 \r
70         .set    nomips16\r
71         .set    noreorder\r
72 \r
73         .extern pxCurrentTCB\r
74         .extern vTaskSwitchContext\r
75         .extern vPortIncrementTick\r
76         .extern xISRStackTop\r
77 \r
78         .global vPortStartFirstTask\r
79         .global vPortYieldISR\r
80         .global vPortTickInterruptHandler\r
81 \r
82 \r
83 /******************************************************************/\r
84 \r
85         .set            noreorder\r
86         .set            noat\r
87         .ent            vPortTickInterruptHandler\r
88 \r
89 vPortTickInterruptHandler:\r
90 \r
91         portSAVE_CONTEXT\r
92 \r
93         jal             vPortIncrementTick\r
94         nop\r
95 \r
96         portRESTORE_CONTEXT\r
97 \r
98         .end vPortTickInterruptHandler\r
99 \r
100 /******************************************************************/\r
101 \r
102         .set            noreorder\r
103         .set            noat\r
104         .ent            vPortStartFirstTask\r
105 \r
106 vPortStartFirstTask:\r
107 \r
108         /* Simply restore the context of the highest priority task that has been\r
109         created so far. */\r
110         portRESTORE_CONTEXT\r
111 \r
112         .end vPortStartFirstTask\r
113 \r
114 \r
115 \r
116 /*******************************************************************/\r
117 \r
118         .set            noreorder\r
119         .set            noat\r
120         .ent            vPortYieldISR\r
121 \r
122 vPortYieldISR:\r
123 \r
124         /* Make room for the context. First save the current status so it can be\r
125         manipulated, and the cause and EPC registers so thier original values are\r
126         captured. */\r
127         mfc0            k0, _CP0_CAUSE\r
128         addiu           sp,     sp, -portCONTEXT_SIZE\r
129         mfc0            k1, _CP0_STATUS\r
130 \r
131         /* Also save s6 and s5 so we can use them during this interrupt.  Any\r
132         nesting interrupts should maintain the values of these registers\r
133         across the ISR. */\r
134         sw                      s6, 44(sp)\r
135         sw                      s5, 40(sp)\r
136         sw                      k1, portSTATUS_STACK_LOCATION(sp)\r
137 \r
138         /* Interrupts above the kernel priority are going to be re-enabled. */\r
139         srl                     k0, k0, 0xa\r
140         ins             k1, k0, 10, 6\r
141         ins                     k1, zero, 1, 4\r
142 \r
143         /* s5 is used as the frame pointer. */\r
144         add                     s5, zero, sp\r
145 \r
146         /* Swap to the system stack.  This is not conditional on the nesting\r
147         count as this interrupt is always the lowest priority and therefore\r
148         the nesting is always 0. */\r
149         la                      sp, xISRStackTop\r
150         lw                      sp, (sp)\r
151 \r
152         /* Set the nesting count. */\r
153         la                      k0, uxInterruptNesting\r
154         addiu           s6, zero, 1\r
155         sw                      s6, 0(k0)\r
156 \r
157         /* s6 holds the EPC value, this is saved with the rest of the context\r
158         after interrupts are enabled. */\r
159         mfc0            s6, _CP0_EPC\r
160 \r
161         /* Re-enable interrupts. */\r
162         mtc0            k1, _CP0_STATUS\r
163 \r
164         /* Save the context into the space just created.  s6 is saved again\r
165         here as it now contains the EPC value. */\r
166         sw                      ra,     120(s5)\r
167         sw                      s8, 116(s5)\r
168         sw                      t9, 112(s5)\r
169         sw                      t8,     108(s5)\r
170         sw                      t7,     104(s5)\r
171         sw                      t6, 100(s5)\r
172         sw                      t5, 96(s5)\r
173         sw                      t4, 92(s5)\r
174         sw                      t3, 88(s5)\r
175         sw                      t2, 84(s5)\r
176         sw                      t1, 80(s5)\r
177         sw                      t0, 76(s5)\r
178         sw                      a3, 72(s5)\r
179         sw                      a2, 68(s5)\r
180         sw                      a1, 64(s5)\r
181         sw                      a0, 60(s5)\r
182         sw                      v1, 56(s5)\r
183         sw                      v0, 52(s5)\r
184         sw                      s7, 48(s5)\r
185         sw                      s6, portEPC_STACK_LOCATION(s5)\r
186         /* s5 and s6 has already been saved. */\r
187         sw                      s4,     36(s5)\r
188         sw                      s3, 32(s5)\r
189         sw                      s2, 28(s5)\r
190         sw                      s1, 24(s5)\r
191         sw                      s0, 20(s5)\r
192         sw                      $1, 16(s5)\r
193 \r
194         /* s7 is used as a scratch register as this should always be saved across\r
195         nesting interrupts. */\r
196         mfhi            s7\r
197         sw                      s7, 12(s5)\r
198         mflo            s7\r
199         sw                      s7, 8(s5)\r
200 \r
201         /* Save the stack pointer to the task. */\r
202         la                      s7, pxCurrentTCB\r
203         lw                      s7, (s7)\r
204         sw                      s5, (s7)\r
205 \r
206         /* Set the interrupt mask to the max priority that can use the API.  The\r
207         yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which\r
208         is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever\r
209         raise the IPL value and never lower it. */\r
210         di\r
211         mfc0            s7, _CP0_STATUS\r
212         ins             s7, $0, 10, 6\r
213         ori                     s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1\r
214 \r
215         /* This mtc0 re-enables interrupts, but only above\r
216         configMAX_SYSCALL_INTERRUPT_PRIORITY. */\r
217         mtc0            s6, _CP0_STATUS\r
218 \r
219         /* Clear the software interrupt in the core. */\r
220         mfc0            s6, _CP0_CAUSE\r
221         ins                     s6, zero, 8, 1\r
222         mtc0            s6, _CP0_CAUSE\r
223 \r
224         /* Clear the interrupt in the interrupt controller. */\r
225         la                      s6, IFS0CLR\r
226         addiu           s4, zero, 2\r
227         sw                      s4, (s6)\r
228 \r
229         jal                     vTaskSwitchContext\r
230         nop\r
231 \r
232         /* Clear the interrupt mask again.  The saved status value is still in s7. */\r
233         mtc0            s7, _CP0_STATUS\r
234 \r
235         /* Restore the stack pointer from the TCB. */\r
236         la                      s0, pxCurrentTCB\r
237         lw                      s0, (s0)\r
238         lw                      s5, (s0)\r
239 \r
240         /* Restore the rest of the context. */\r
241         lw                      s0, 8(s5)\r
242         mtlo            s0\r
243         lw                      s0, 12(s5)\r
244         mthi            s0\r
245         lw                      $1, 16(s5)\r
246         lw                      s0, 20(s5)\r
247         lw                      s1, 24(s5)\r
248         lw                      s2, 28(s5)\r
249         lw                      s3, 32(s5)\r
250         lw                      s4, 36(s5)\r
251         /* s5 is loaded later. */\r
252         lw                      s6, 44(s5)\r
253         lw                      s7, 48(s5)\r
254         lw                      v0, 52(s5)\r
255         lw                      v1, 56(s5)\r
256         lw                      a0, 60(s5)\r
257         lw                      a1, 64(s5)\r
258         lw                      a2, 68(s5)\r
259         lw                      a3, 72(s5)\r
260         lw                      t0, 76(s5)\r
261         lw                      t1, 80(s5)\r
262         lw                      t2, 84(s5)\r
263         lw                      t3, 88(s5)\r
264         lw                      t4, 92(s5)\r
265         lw                      t5, 96(s5)\r
266         lw                      t6, 100(s5)\r
267         lw                      t7, 104(s5)\r
268         lw                      t8, 108(s5)\r
269         lw                      t9, 112(s5)\r
270         lw                      s8, 116(s5)\r
271         lw                      ra, 120(s5)\r
272 \r
273         /* Protect access to the k registers, and others. */\r
274         di\r
275 \r
276         /* Set nesting back to zero.  As the lowest priority interrupt this\r
277         interrupt cannot have nested. */\r
278         la                      k0, uxInterruptNesting\r
279         sw                      zero, 0(k0)\r
280 \r
281         /* Switch back to use the real stack pointer. */\r
282         add                     sp, zero, s5\r
283 \r
284         /* Restore the real s5 value. */\r
285         lw                      s5, 40(sp)\r
286 \r
287         /* Pop the status and epc values. */\r
288         lw                      k1, portSTATUS_STACK_LOCATION(sp)\r
289         lw                      k0, portEPC_STACK_LOCATION(sp)\r
290 \r
291         /* Remove stack frame. */\r
292         addiu           sp,     sp,     portCONTEXT_SIZE\r
293 \r
294         mtc0            k1, _CP0_STATUS\r
295         mtc0            k0, _CP0_EPC\r
296         eret\r
297         nop\r
298 \r
299         .end            vPortYieldISR\r
300 \r
301 \r
302 \r