2 * FreeRTOS Kernel V10.3.0
\r
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
29 #include <sys/asm.h>
\r
30 #include "FreeRTOSConfig.h"
\r
31 #include "ISR_Support.h"
\r
33 .extern pxCurrentTCB
\r
34 .extern vTaskSwitchContext
\r
35 .extern vPortIncrementTick
\r
36 .extern xISRStackTop
\r
37 .extern ulTaskHasFPUContext
\r
39 .global vPortStartFirstTask
\r
40 .global vPortYieldISR
\r
41 .global vPortTickInterruptHandler
\r
42 .global vPortInitialiseFPSCR
\r
45 /******************************************************************/
\r
52 /***************************************************************
\r
53 * The following is needed to locate the
\r
54 * vPortTickInterruptHandler function into the correct vector
\r
55 ***************************************************************/
\r
56 #ifdef configTICK_INTERRUPT_VECTOR
\r
57 #if (configTICK_INTERRUPT_VECTOR == _CORE_TIMER_VECTOR)
\r
58 .equ __vector_dispatch_0, vPortTickInterruptHandler
\r
59 .global __vector_dispatch_0
\r
60 .section .vector_0, code, keep
\r
61 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_1_VECTOR)
\r
62 .equ __vector_dispatch_4, vPortTickInterruptHandler
\r
63 .global __vector_dispatch_4
\r
64 .section .vector_4, code, keep
\r
65 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_2_VECTOR)
\r
66 .equ __vector_dispatch_9, vPortTickInterruptHandler
\r
67 .global __vector_dispatch_9
\r
68 .section .vector_9, code, keep
\r
69 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_3_VECTOR)
\r
70 .equ __vector_dispatch_14, vPortTickInterruptHandler
\r
71 .global __vector_dispatch_14
\r
72 .section .vector_14, code, keep
\r
73 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_4_VECTOR)
\r
74 .equ __vector_dispatch_19, vPortTickInterruptHandler
\r
75 .global __vector_dispatch_19
\r
76 .section .vector_19, code, keep
\r
77 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_5_VECTOR)
\r
78 .equ __vector_dispatch_24, vPortTickInterruptHandler
\r
79 .global __vector_dispatch_24
\r
80 .section .vector_24, code, keep
\r
81 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_6_VECTOR)
\r
82 .equ __vector_dispatch_28, vPortTickInterruptHandler
\r
83 .global __vector_dispatch_28
\r
84 .section .vector_28, code, keep
\r
85 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_7_VECTOR)
\r
86 .equ __vector_dispatch_32, vPortTickInterruptHandler
\r
87 .global __vector_dispatch_32
\r
88 .section .vector_32, code, keep
\r
89 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_8_VECTOR)
\r
90 .equ __vector_dispatch_36, vPortTickInterruptHandler
\r
91 .global __vector_dispatch_36
\r
92 .section .vector_36, code, keep
\r
93 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_9_VECTOR)
\r
94 .equ __vector_dispatch_40, vPortTickInterruptHandler
\r
95 .global __vector_dispatch_40
\r
96 .section .vector_40, code, keep
\r
99 .equ __vector_dispatch_4, vPortTickInterruptHandler
\r
100 .global __vector_dispatch_4
\r
101 .section .vector_4, code, keep
\r
104 .ent vPortTickInterruptHandler
\r
106 vPortTickInterruptHandler:
\r
110 jal vPortIncrementTick
\r
113 portRESTORE_CONTEXT
\r
115 .end vPortTickInterruptHandler
\r
117 /******************************************************************/
\r
121 .section .text, code
\r
122 .ent vPortStartFirstTask
\r
124 vPortStartFirstTask:
\r
126 /* Simply restore the context of the highest priority task that has been
\r
128 portRESTORE_CONTEXT
\r
130 .end vPortStartFirstTask
\r
134 /*******************************************************************/
\r
140 /***************************************************************
\r
141 * The following is needed to locate the vPortYieldISR function
\r
142 * into the correct vector
\r
143 ***************************************************************/
\r
144 .equ __vector_dispatch_1, vPortYieldISR
\r
145 .global __vector_dispatch_1
\r
146 .section .vector_1, code
\r
151 #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
\r
152 /* Code sequence for FPU support, the context save requires advance
\r
153 knowledge of the stack frame size and if the current task actually uses the
\r
156 /* Make room for the context. First save the current status so it can be
\r
157 manipulated, and the cause and EPC registers so their original values are
\r
159 la k0, ulTaskHasFPUContext
\r
162 addiu sp, sp, -portCONTEXT_SIZE /* always reserve space for the context. */
\r
163 addiu sp, sp, -portFPU_CONTEXT_SIZE /* reserve additional space for the FPU context. */
\r
165 mfc0 k1, _CP0_STATUS
\r
167 /* Also save s6 and s5 so they can be used. Any nesting interrupts should
\r
168 maintain the values of these registers across the ISR. */
\r
171 sw k1, portSTATUS_STACK_LOCATION(sp)
\r
172 sw k0, portTASK_HAS_FPU_STACK_LOCATION(sp)
\r
174 /* Prepare to re-enabled interrupts above the kernel priority. */
\r
175 ins k1, zero, 10, 7 /* Clear IPL bits 0:6. */
\r
176 ins k1, zero, 18, 1 /* Clear IPL bit 7. It would be an error here if this bit were set anyway. */
\r
177 ori k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 )
\r
178 ins k1, zero, 1, 4 /* Clear EXL, ERL and UM. */
\r
180 /* s5 is used as the frame pointer. */
\r
183 /* Swap to the system stack. This is not conditional on the nesting
\r
184 count as this interrupt is always the lowest priority and therefore
\r
185 the nesting is always 0. */
\r
186 la sp, xISRStackTop
\r
189 /* Set the nesting count. */
\r
190 la k0, uxInterruptNesting
\r
194 /* s6 holds the EPC value, this is saved with the rest of the context
\r
195 after interrupts are enabled. */
\r
198 /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */
\r
199 mtc0 k1, _CP0_STATUS
\r
201 /* Save the context into the space just created. s6 is saved again
\r
202 here as it now contains the EPC value. */
\r
222 sw s6, portEPC_STACK_LOCATION(s5)
\r
223 /* s5 and s6 has already been saved. */
\r
231 /* s7 is used as a scratch register as this should always be saved across
\r
232 nesting interrupts. */
\r
234 /* Save the AC0, AC1, AC2 and AC3. */
\r
258 /* Test if FPU context save is required. */
\r
259 lw s7, portTASK_HAS_FPU_STACK_LOCATION(s5)
\r
263 /* Save the FPU registers above the normal context. */
\r
264 portSAVE_FPU_REGS (portCONTEXT_SIZE + 8), s5
\r
266 /* Save the FPU status register */
\r
268 sw s7, ( portCONTEXT_SIZE + portFPCSR_STACK_LOCATION )(s5)
\r
271 /* Save the stack pointer to the task. */
\r
272 la s7, pxCurrentTCB
\r
276 /* Set the interrupt mask to the max priority that can use the API. The
\r
277 yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which
\r
278 is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever
\r
279 raise the IPL value and never lower it. */
\r
282 mfc0 s7, _CP0_STATUS
\r
283 ins s7, zero, 10, 7
\r
284 ins s7, zero, 18, 1
\r
285 ori s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1
\r
287 /* This mtc0 re-enables interrupts, but only above
\r
288 configMAX_SYSCALL_INTERRUPT_PRIORITY. */
\r
289 mtc0 s6, _CP0_STATUS
\r
292 /* Clear the software interrupt in the core. */
\r
293 mfc0 s6, _CP0_CAUSE
\r
295 mtc0 s6, _CP0_CAUSE
\r
298 /* Clear the interrupt in the interrupt controller. */
\r
303 jal vTaskSwitchContext
\r
306 /* Clear the interrupt mask again. The saved status value is still in s7. */
\r
307 mtc0 s7, _CP0_STATUS
\r
310 /* Restore the stack pointer from the TCB. */
\r
311 la s0, pxCurrentTCB
\r
315 /* Test if the FPU context needs restoring. */
\r
316 lw s0, portTASK_HAS_FPU_STACK_LOCATION(s5)
\r
320 /* Restore the FPU status register. */
\r
321 lw s0, ( portCONTEXT_SIZE + portFPCSR_STACK_LOCATION )(s5)
\r
324 /* Restore the FPU registers. */
\r
325 portLOAD_FPU_REGS ( portCONTEXT_SIZE + 8 ), s5
\r
328 /* Restore the rest of the context. */
\r
359 /* s5 is loaded later. */
\r
381 /* Protect access to the k registers, and others. */
\r
385 /* Set nesting back to zero. As the lowest priority interrupt this
\r
386 interrupt cannot have nested. */
\r
387 la k0, uxInterruptNesting
\r
390 /* Switch back to use the real stack pointer. */
\r
393 /* Restore the real s5 value. */
\r
396 /* Pop the FPU context value from the stack */
\r
397 lw k0, portTASK_HAS_FPU_STACK_LOCATION(sp)
\r
398 la k1, ulTaskHasFPUContext
\r
403 /* task has FPU context so adjust the stack frame after popping the
\r
404 status and epc values. */
\r
405 lw k1, portSTATUS_STACK_LOCATION(sp)
\r
406 lw k0, portEPC_STACK_LOCATION(sp)
\r
407 addiu sp, sp, portFPU_CONTEXT_SIZE
\r
412 /* Pop the status and epc values. */
\r
413 lw k1, portSTATUS_STACK_LOCATION(sp)
\r
414 lw k0, portEPC_STACK_LOCATION(sp)
\r
417 /* Remove stack frame. */
\r
418 addiu sp, sp, portCONTEXT_SIZE
\r
421 /* Code sequence for no FPU support, the context save requires advance
\r
422 knowledge of the stack frame size when no FPU is being used */
\r
424 /* Make room for the context. First save the current status so it can be
\r
425 manipulated, and the cause and EPC registers so thier original values are
\r
427 addiu sp, sp, -portCONTEXT_SIZE
\r
428 mfc0 k1, _CP0_STATUS
\r
430 /* Also save s6 and s5 so they can be used. Any nesting interrupts should
\r
431 maintain the values of these registers across the ISR. */
\r
434 sw k1, portSTATUS_STACK_LOCATION(sp)
\r
436 /* Prepare to re-enabled interrupts above the kernel priority. */
\r
437 ins k1, zero, 10, 7 /* Clear IPL bits 0:6. */
\r
438 ins k1, zero, 18, 1 /* Clear IPL bit 7. It would be an error here if this bit were set anyway. */
\r
439 ori k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 )
\r
440 ins k1, zero, 1, 4 /* Clear EXL, ERL and UM. */
\r
442 /* s5 is used as the frame pointer. */
\r
445 /* Swap to the system stack. This is not conditional on the nesting
\r
446 count as this interrupt is always the lowest priority and therefore
\r
447 the nesting is always 0. */
\r
448 la sp, xISRStackTop
\r
451 /* Set the nesting count. */
\r
452 la k0, uxInterruptNesting
\r
456 /* s6 holds the EPC value, this is saved with the rest of the context
\r
457 after interrupts are enabled. */
\r
460 /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */
\r
461 mtc0 k1, _CP0_STATUS
\r
463 /* Save the context into the space just created. s6 is saved again
\r
464 here as it now contains the EPC value. */
\r
484 sw s6, portEPC_STACK_LOCATION(s5)
\r
485 /* s5 and s6 has already been saved. */
\r
493 /* s7 is used as a scratch register as this should always be saved across
\r
494 nesting interrupts. */
\r
496 /* Save the AC0, AC1, AC2 and AC3. */
\r
520 /* Save the stack pointer to the task. */
\r
521 la s7, pxCurrentTCB
\r
525 /* Set the interrupt mask to the max priority that can use the API. The
\r
526 yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which
\r
527 is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever
\r
528 raise the IPL value and never lower it. */
\r
531 mfc0 s7, _CP0_STATUS
\r
532 ins s7, zero, 10, 7
\r
533 ins s7, zero, 18, 1
\r
534 ori s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1
\r
536 /* This mtc0 re-enables interrupts, but only above
\r
537 configMAX_SYSCALL_INTERRUPT_PRIORITY. */
\r
538 mtc0 s6, _CP0_STATUS
\r
541 /* Clear the software interrupt in the core. */
\r
542 mfc0 s6, _CP0_CAUSE
\r
544 mtc0 s6, _CP0_CAUSE
\r
547 /* Clear the interrupt in the interrupt controller. */
\r
552 jal vTaskSwitchContext
\r
555 /* Clear the interrupt mask again. The saved status value is still in s7. */
\r
556 mtc0 s7, _CP0_STATUS
\r
559 /* Restore the stack pointer from the TCB. */
\r
560 la s0, pxCurrentTCB
\r
564 /* Restore the rest of the context. */
\r
595 /* s5 is loaded later. */
\r
617 /* Protect access to the k registers, and others. */
\r
621 /* Set nesting back to zero. As the lowest priority interrupt this
\r
622 interrupt cannot have nested. */
\r
623 la k0, uxInterruptNesting
\r
626 /* Switch back to use the real stack pointer. */
\r
629 /* Restore the real s5 value. */
\r
632 /* Pop the status and epc values. */
\r
633 lw k1, portSTATUS_STACK_LOCATION(sp)
\r
634 lw k0, portEPC_STACK_LOCATION(sp)
\r
636 /* Remove stack frame. */
\r
637 addiu sp, sp, portCONTEXT_SIZE
\r
639 #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */
\r
641 /* Restore the status and EPC registers and return */
\r
642 mtc0 k1, _CP0_STATUS
\r
650 /******************************************************************/
\r
652 #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
\r
654 .macro portFPUSetAndInc reg, dest
\r
656 cvt.d.w \dest, \dest
\r
657 addiu \reg, \reg, 1
\r
662 .section .text, code
\r
663 .ent vPortInitialiseFPSCR
\r
665 vPortInitialiseFPSCR:
\r
667 /* Initialize the floating point status register in CP1. The initial
\r
668 value is passed in a0. */
\r
671 /* Clear the FPU registers */
\r
672 addiu a0, zero, 0x0000
\r
673 portFPUSetAndInc a0, $f0
\r
674 portFPUSetAndInc a0, $f1
\r
675 portFPUSetAndInc a0, $f2
\r
676 portFPUSetAndInc a0, $f3
\r
677 portFPUSetAndInc a0, $f4
\r
678 portFPUSetAndInc a0, $f5
\r
679 portFPUSetAndInc a0, $f6
\r
680 portFPUSetAndInc a0, $f7
\r
681 portFPUSetAndInc a0, $f8
\r
682 portFPUSetAndInc a0, $f9
\r
683 portFPUSetAndInc a0, $f10
\r
684 portFPUSetAndInc a0, $f11
\r
685 portFPUSetAndInc a0, $f12
\r
686 portFPUSetAndInc a0, $f13
\r
687 portFPUSetAndInc a0, $f14
\r
688 portFPUSetAndInc a0, $f15
\r
689 portFPUSetAndInc a0, $f16
\r
690 portFPUSetAndInc a0, $f17
\r
691 portFPUSetAndInc a0, $f18
\r
692 portFPUSetAndInc a0, $f19
\r
693 portFPUSetAndInc a0, $f20
\r
694 portFPUSetAndInc a0, $f21
\r
695 portFPUSetAndInc a0, $f22
\r
696 portFPUSetAndInc a0, $f23
\r
697 portFPUSetAndInc a0, $f24
\r
698 portFPUSetAndInc a0, $f25
\r
699 portFPUSetAndInc a0, $f26
\r
700 portFPUSetAndInc a0, $f27
\r
701 portFPUSetAndInc a0, $f28
\r
702 portFPUSetAndInc a0, $f29
\r
703 portFPUSetAndInc a0, $f30
\r
704 portFPUSetAndInc a0, $f31
\r
709 .end vPortInitialiseFPSCR
\r
711 #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */
\r
713 #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
\r
715 /**********************************************************************/
\r
716 /* Test read back */
\r
717 /* a0 = address to store registers */
\r
721 .section .text, code
\r
722 .ent vPortFPUReadback
\r
723 .global vPortFPUReadback
\r
762 .end vPortFPUReadback
\r
764 #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */
\r