xref: /Kernel-v10.6.2/portable/MPLAB/PIC32MEC14xx/port_asm.S (revision ef7b253b56c9788077f5ecd6c9deb4021923d646)
1/*
2 * FreeRTOS Kernel V10.6.2
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
26 *
27 */
28
29/* FreeRTOS includes. */
30#include "FreeRTOSConfig.h"
31#include "ISR_Support.h"
32
33/* Microchip includes. */
34#include <xc.h>
35#include <sys/asm.h>
36
37    .extern pxCurrentTCB
38    .extern vTaskSwitchContext
39    .extern vPortIncrementTick
40    .extern xISRStackTop
41
42    PORT_CPP_JTVIC_BASE = 0xBFFFC000
43    PORT_CCP_JTVIC_GIRQ24_SRC = 0xBFFFC100
44
45    .global vPortStartFirstTask .text
46    .global vPortYieldISR .text
47    .global vPortTickInterruptHandler .text
48
49
50/******************************************************************/
51
52
53/***************************************************************
54*  The following is needed to locate the
55*  vPortTickInterruptHandler function into the correct vector
56*  MEC14xx - This ISR will only be used if HW timers' interrupts
57*  in GIRQ23 are disaggregated.
58*
59***************************************************************/
60
61    .set  noreorder
62    .set  noat
63    .set  micromips
64
65    .section .text, code
66    .ent    vPortTickInterruptHandler
67
68#if configTIMERS_DISAGGREGATED_ISRS == 0
69
70    .globl girq23_isr
71
72girq23_isr:
73vPortTickInterruptHandler:
74
75    portSAVE_CONTEXT
76
77    jal     girq23_handler
78    nop
79
80    portRESTORE_CONTEXT
81
82.end vPortTickInterruptHandler
83
84#else
85
86    .globl girq23_b4
87
88girq23_b4:
89vPortTickInterruptHandler:
90
91    portSAVE_CONTEXT
92
93    jal     vPortIncrementTick
94    nop
95
96    portRESTORE_CONTEXT
97
98.end vPortTickInterruptHandler
99
100#endif /* #if configTIMERS_DISAGGREGATED_ISRS == 0 */
101
102/******************************************************************/
103
104    .set    micromips
105    .set    noreorder
106    .set    noat
107
108    .section .text, code
109    .ent    vPortStartFirstTask
110
111vPortStartFirstTask:
112
113    /* Simply restore the context of the highest priority task that has
114    been created so far. */
115    portRESTORE_CONTEXT
116
117.end vPortStartFirstTask
118
119
120
121/*******************************************************************/
122
123/***************************************************************
124*  The following is needed to locate the vPortYieldISR function into the correct
125* vector.
126***************************************************************/
127
128    .set micromips
129    .set noreorder
130    .set noat
131
132    .section .text, code
133
134    .global vPortYieldISR
135
136
137#if configCPU_DISAGGREGATED_ISRS == 0
138    .global girq24_isr
139    .ent girq24_isr
140girq24_isr:
141    la      k0, PORT_CPP_JTVIC_BASE
142    lw      k0, 0x10C(k0)
143    andi    k1, k0, 0x2
144    bgtz    k1, vPortYieldISR
145    nop
146
147    portSAVE_CONTEXT
148
149    jal     girq24_b_0_2
150
151    portRESTORE_CONTEXT
152
153    .end girq24_isr
154
155#else
156    .global girq24_b1
157girq24_b1:
158#endif
159        .ent  vPortYieldISR
160vPortYieldISR:
161
162    /* Make room for the context. First save the current status so it can be
163    manipulated, and the cause and EPC registers so thier original values
164    are captured. */
165    addiu   sp, sp, -portCONTEXT_SIZE
166    mfc0    k1, _CP0_STATUS
167
168    /* Also save s6 and s5 so they can be used.  Any nesting interrupts should
169    maintain the values of these registers across the ISR. */
170    sw      s6, 44(sp)
171    sw      s5, 40(sp)
172    sw      k1, portSTATUS_STACK_LOCATION(sp)
173
174    /* Prepare to re-enable interrupts above the kernel priority. */
175    ins     k1, zero, 10, 7      /* Clear IPL bits 0:6. */
176    ins     k1, zero, 18, 1      /* Clear IPL bit 7  */
177    ori     k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 )
178    ins     k1, zero, 1, 4        /* Clear EXL, ERL and UM. */
179
180    /* s5 is used as the frame pointer. */
181    add     s5, zero, sp
182
183    /* Swap to the system stack.  This is not conditional on the nesting
184    count as this interrupt is always the lowest priority and therefore
185    the nesting is always 0. */
186    la      sp, xISRStackTop
187    lw      sp, (sp)
188
189    /* Set the nesting count. */
190    la      k0, uxInterruptNesting
191    addiu   s6, zero, 1
192    sw      s6, 0(k0)
193
194    /* s6 holds the EPC value, this is saved with the rest of the context
195    after interrupts are enabled. */
196    mfc0    s6, _CP0_EPC
197
198    /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */
199    mtc0    k1, _CP0_STATUS
200
201    /* Save the context into the space just created.  s6 is saved again
202    here as it now contains the EPC value. */
203    sw      ra, 120(s5)
204    sw      s8, 116(s5)
205    sw      t9, 112(s5)
206    sw      t8, 108(s5)
207    sw      t7, 104(s5)
208    sw      t6, 100(s5)
209    sw      t5, 96(s5)
210    sw      t4, 92(s5)
211    sw      t3, 88(s5)
212    sw      t2, 84(s5)
213    sw      t1, 80(s5)
214    sw      t0, 76(s5)
215    sw      a3, 72(s5)
216    sw      a2, 68(s5)
217    sw      a1, 64(s5)
218    sw      a0, 60(s5)
219    sw      v1, 56(s5)
220    sw      v0, 52(s5)
221    sw      s7, 48(s5)
222    sw      s6, portEPC_STACK_LOCATION(s5)
223    /* s5 and s6 has already been saved. */
224    sw      s4, 36(s5)
225    sw      s3, 32(s5)
226    sw      s2, 28(s5)
227    sw      s1, 24(s5)
228    sw      s0, 20(s5)
229    sw      $1, 16(s5)
230
231    /* s7 is used as a scratch register as this should always be saved acro ss
232    nesting interrupts. */
233    mfhi    s7
234    sw      s7, 12(s5)
235    mflo    s7
236    sw      s7, 8(s5)
237
238    /* Save the stack pointer to the task. */
239    la      s7, pxCurrentTCB
240    lw      s7, (s7)
241    sw      s5, (s7)
242
243    /* Set the interrupt mask to the max priority that can use the API.
244    The yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY
245    which is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only
246    ever raise the IPL value and never lower it. */
247    di
248    ehb
249    mfc0    s7, _CP0_STATUS
250    ins     s7, zero, 10, 7
251    ins     s7, zero, 18, 1
252    ori     s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1
253
254    /* This mtc0 re-enables interrupts, but only above
255    configMAX_SYSCALL_INTERRUPT_PRIORITY. */
256    mtc0    s6, _CP0_STATUS
257    ehb
258
259    /* Clear the software interrupt in the core. */
260    mfc0    s6, _CP0_CAUSE
261    ins     s6, zero, 8, 1
262    mtc0    s6, _CP0_CAUSE
263    ehb
264
265    /* Clear the interrupt in the interrupt controller.
266    MEC14xx GIRQ24 Source bit[1] = 1 to clear */
267    la      s6, PORT_CCP_JTVIC_GIRQ24_SRC
268    addiu   s4, zero, 2
269    sw      s4, (s6)
270    jal     vTaskSwitchContext
271    nop
272
273    /* Clear the interrupt mask again. The saved status value is still in s7 */
274    mtc0    s7, _CP0_STATUS
275    ehb
276
277    /* Restore the stack pointer from the TCB. */
278    la      s0, pxCurrentTCB
279    lw      s0, (s0)
280    lw      s5, (s0)
281
282    /* Restore the rest of the context. */
283    lw      s0, 8(s5)
284    mtlo    s0
285    lw      s0, 12(s5)
286    mthi    s0
287
288    lw      $1, 16(s5)
289    lw      s0, 20(s5)
290    lw      s1, 24(s5)
291    lw      s2, 28(s5)
292    lw      s3, 32(s5)
293    lw      s4, 36(s5)
294
295    /* s5 is loaded later. */
296    lw      s6, 44(s5)
297    lw      s7, 48(s5)
298    lw      v0, 52(s5)
299    lw      v1, 56(s5)
300    lw      a0, 60(s5)
301    lw      a1, 64(s5)
302    lw      a2, 68(s5)
303    lw      a3, 72(s5)
304    lw      t0, 76(s5)
305    lw      t1, 80(s5)
306    lw      t2, 84(s5)
307    lw      t3, 88(s5)
308    lw      t4, 92(s5)
309    lw      t5, 96(s5)
310    lw      t6, 100(s5)
311    lw      t7, 104(s5)
312    lw      t8, 108(s5)
313    lw      t9, 112(s5)
314    lw      s8, 116(s5)
315    lw      ra, 120(s5)
316
317    /* Protect access to the k registers, and others. */
318    di
319    ehb
320
321    /* Set nesting back to zero.  As the lowest priority interrupt this
322    interrupt cannot have nested. */
323    la      k0, uxInterruptNesting
324    sw      zero, 0(k0)
325
326    /* Switch back to use the real stack pointer. */
327    add     sp, zero, s5
328
329    /* Restore the real s5 value. */
330    lw      s5, 40(sp)
331
332    /* Pop the status and epc values. */
333    lw      k1, portSTATUS_STACK_LOCATION(sp)
334    lw      k0, portEPC_STACK_LOCATION(sp)
335
336    /* Remove stack frame. */
337    addiu   sp, sp, portCONTEXT_SIZE
338
339    mtc0    k1, _CP0_STATUS
340    mtc0    k0, _CP0_EPC
341    ehb
342    eret
343    nop
344
345.end    vPortYieldISR
346