]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/MPLAB/PIC32MX/port_asm.S
01002fc281f2fb56215edfd63918c19054a3975e
[freertos] / FreeRTOS / Source / portable / MPLAB / PIC32MX / port_asm.S
1 /*\r
2  * FreeRTOS Kernel V10.1.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.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 #include <xc.h>\r
29 #include <sys/asm.h>\r
30 #include "ISR_Support.h"\r
31 \r
32 \r
33         .set    nomips16\r
34         .set    noreorder\r
35 \r
36         .extern pxCurrentTCB\r
37         .extern vTaskSwitchContext\r
38         .extern vPortIncrementTick\r
39         .extern xISRStackTop\r
40 \r
41         .global vPortStartFirstTask\r
42         .global vPortYieldISR\r
43         .global vPortTickInterruptHandler\r
44 \r
45 \r
46 /******************************************************************/\r
47 \r
48         .set            noreorder\r
49         .set            noat\r
50         .ent            vPortTickInterruptHandler\r
51 \r
52 vPortTickInterruptHandler:\r
53 \r
54         portSAVE_CONTEXT\r
55 \r
56         jal             vPortIncrementTick\r
57         nop\r
58 \r
59         portRESTORE_CONTEXT\r
60 \r
61         .end vPortTickInterruptHandler\r
62 \r
63 /******************************************************************/\r
64 \r
65         .set            noreorder\r
66         .set            noat\r
67         .ent            vPortStartFirstTask\r
68 \r
69 vPortStartFirstTask:\r
70 \r
71         /* Simply restore the context of the highest priority task that has been\r
72         created so far. */\r
73         portRESTORE_CONTEXT\r
74 \r
75         .end vPortStartFirstTask\r
76 \r
77 \r
78 \r
79 /*******************************************************************/\r
80 \r
81         .set            noreorder\r
82         .set            noat\r
83         .ent            vPortYieldISR\r
84 \r
85 vPortYieldISR:\r
86 \r
87         /* Make room for the context. First save the current status so it can be\r
88         manipulated. */\r
89         addiu           sp, sp, -portCONTEXT_SIZE\r
90         mfc0            k1, _CP0_STATUS\r
91 \r
92         /* Also save s6 and s5 so they can be used.  Any nesting interrupts should\r
93         maintain the values of these registers across the ISR. */\r
94         sw                      s6, 44(sp)\r
95         sw                      s5, 40(sp)\r
96         sw                      k1, portSTATUS_STACK_LOCATION(sp)\r
97 \r
98         /* Prepare to re-enabled interrupt above the kernel priority. */\r
99         ins             k1, zero, 10, 6\r
100         ori                     k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 )\r
101         ins                     k1, zero, 1, 4\r
102 \r
103         /* s5 is used as the frame pointer. */\r
104         add                     s5, zero, sp\r
105 \r
106         /* Swap to the system stack.  This is not conditional on the nesting\r
107         count as this interrupt is always the lowest priority and therefore\r
108         the nesting is always 0. */\r
109         la                      sp, xISRStackTop\r
110         lw                      sp, (sp)\r
111 \r
112         /* Set the nesting count. */\r
113         la                      k0, uxInterruptNesting\r
114         addiu           s6, zero, 1\r
115         sw                      s6, 0(k0)\r
116 \r
117         /* s6 holds the EPC value, this is saved with the rest of the context\r
118         after interrupts are enabled. */\r
119         mfc0            s6, _CP0_EPC\r
120 \r
121         /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */\r
122         mtc0            k1, _CP0_STATUS\r
123 \r
124         /* Save the context into the space just created.  s6 is saved again\r
125         here as it now contains the EPC value. */\r
126         sw                      ra, 120(s5)\r
127         sw                      s8, 116(s5)\r
128         sw                      t9, 112(s5)\r
129         sw                      t8, 108(s5)\r
130         sw                      t7, 104(s5)\r
131         sw                      t6, 100(s5)\r
132         sw                      t5, 96(s5)\r
133         sw                      t4, 92(s5)\r
134         sw                      t3, 88(s5)\r
135         sw                      t2, 84(s5)\r
136         sw                      t1, 80(s5)\r
137         sw                      t0, 76(s5)\r
138         sw                      a3, 72(s5)\r
139         sw                      a2, 68(s5)\r
140         sw                      a1, 64(s5)\r
141         sw                      a0, 60(s5)\r
142         sw                      v1, 56(s5)\r
143         sw                      v0, 52(s5)\r
144         sw                      s7, 48(s5)\r
145         sw                      s6, portEPC_STACK_LOCATION(s5)\r
146         /* s5 and s6 has already been saved. */\r
147         sw                      s4, 36(s5)\r
148         sw                      s3, 32(s5)\r
149         sw                      s2, 28(s5)\r
150         sw                      s1, 24(s5)\r
151         sw                      s0, 20(s5)\r
152         sw                      $1, 16(s5)\r
153 \r
154         /* s7 is used as a scratch register as this should always be saved across\r
155         nesting interrupts. */\r
156         mfhi            s7\r
157         sw                      s7, 12(s5)\r
158         mflo            s7\r
159         sw                      s7, 8(s5)\r
160 \r
161         /* Save the stack pointer to the task. */\r
162         la                      s7, pxCurrentTCB\r
163         lw                      s7, (s7)\r
164         sw                      s5, (s7)\r
165 \r
166         /* Set the interrupt mask to the max priority that can use the API.  The\r
167         yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which\r
168         is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever\r
169         raise the IPL value and never lower it. */\r
170         di\r
171         ehb\r
172         mfc0            s7, _CP0_STATUS\r
173         ins             s7, zero, 10, 6\r
174         ori                     s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1\r
175 \r
176         /* This mtc0 re-enables interrupts, but only above\r
177         configMAX_SYSCALL_INTERRUPT_PRIORITY. */\r
178         mtc0            s6, _CP0_STATUS\r
179         ehb\r
180 \r
181         /* Clear the software interrupt in the core. */\r
182         mfc0            s6, _CP0_CAUSE\r
183         ins                     s6, zero, 8, 1\r
184         mtc0            s6, _CP0_CAUSE\r
185         ehb\r
186 \r
187         /* Clear the interrupt in the interrupt controller. */\r
188         la                      s6, IFS0CLR\r
189         addiu           s4, zero, 2\r
190         sw                      s4, (s6)\r
191 \r
192         jal                     vTaskSwitchContext\r
193         nop\r
194 \r
195         /* Clear the interrupt mask again.  The saved status value is still in s7. */\r
196         mtc0            s7, _CP0_STATUS\r
197         ehb\r
198 \r
199         /* Restore the stack pointer from the TCB. */\r
200         la                      s0, pxCurrentTCB\r
201         lw                      s0, (s0)\r
202         lw                      s5, (s0)\r
203 \r
204         /* Restore the rest of the context. */\r
205         lw                      s0, 8(s5)\r
206         mtlo            s0\r
207         lw                      s0, 12(s5)\r
208         mthi            s0\r
209         lw                      $1, 16(s5)\r
210         lw                      s0, 20(s5)\r
211         lw                      s1, 24(s5)\r
212         lw                      s2, 28(s5)\r
213         lw                      s3, 32(s5)\r
214         lw                      s4, 36(s5)\r
215         /* s5 is loaded later. */\r
216         lw                      s6, 44(s5)\r
217         lw                      s7, 48(s5)\r
218         lw                      v0, 52(s5)\r
219         lw                      v1, 56(s5)\r
220         lw                      a0, 60(s5)\r
221         lw                      a1, 64(s5)\r
222         lw                      a2, 68(s5)\r
223         lw                      a3, 72(s5)\r
224         lw                      t0, 76(s5)\r
225         lw                      t1, 80(s5)\r
226         lw                      t2, 84(s5)\r
227         lw                      t3, 88(s5)\r
228         lw                      t4, 92(s5)\r
229         lw                      t5, 96(s5)\r
230         lw                      t6, 100(s5)\r
231         lw                      t7, 104(s5)\r
232         lw                      t8, 108(s5)\r
233         lw                      t9, 112(s5)\r
234         lw                      s8, 116(s5)\r
235         lw                      ra, 120(s5)\r
236 \r
237         /* Protect access to the k registers, and others. */\r
238         di\r
239         ehb\r
240 \r
241         /* Set nesting back to zero.  As the lowest priority interrupt this\r
242         interrupt cannot have nested. */\r
243         la                      k0, uxInterruptNesting\r
244         sw                      zero, 0(k0)\r
245 \r
246         /* Switch back to use the real stack pointer. */\r
247         add                     sp, zero, s5\r
248 \r
249         /* Restore the real s5 value. */\r
250         lw                      s5, 40(sp)\r
251 \r
252         /* Pop the status and epc values. */\r
253         lw                      k1, portSTATUS_STACK_LOCATION(sp)\r
254         lw                      k0, portEPC_STACK_LOCATION(sp)\r
255 \r
256         /* Remove stack frame. */\r
257         addiu           sp, sp, portCONTEXT_SIZE\r
258 \r
259         mtc0            k1, _CP0_STATUS\r
260         mtc0            k0, _CP0_EPC\r
261         ehb\r
262         eret\r
263         nop\r
264 \r
265         .end            vPortYieldISR\r
266 \r
267 \r
268 \r