/* FreeRTOS V8.2.0rc1 - Copyright (C) 2014 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html 1 tab == 4 spaces! *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * * not run, what could be wrong?". Have you defined configASSERT()? * * * * http://www.FreeRTOS.org/FAQHelp.html * * * *************************************************************************** *************************************************************************** * * * FreeRTOS provides completely free yet professionally developed, * * robust, strictly quality controlled, supported, and cross * * platform software that is more than just the market leader, it * * is the industry's de facto standard. * * * * Help yourself get started quickly while simultaneously helping * * to support the FreeRTOS project by purchasing a FreeRTOS * * tutorial book, reference manual, or both: * * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** *************************************************************************** * * * Investing in training allows your team to be as productive as * * possible as early as possible, lowering your overall development * * cost, and enabling you to bring a more robust product to market * * earlier than would otherwise be possible. Richard Barry is both * * the architect and key author of FreeRTOS, and so also the world's * * leading authority on what is the world's most popular real time * * kernel for deeply embedded MCU designs. Obtaining your training * * from Richard ensures your team will gain directly from his in-depth * * product knowledge and years of usage experience. Contact Real Time * * Engineers Ltd to enquire about the FreeRTOS Masterclass, presented * * by Richard Barry: http://www.FreeRTOS.org/contact * * *************************************************************************** *************************************************************************** * * * You are receiving this top quality software for free. Please play * * fair and reciprocate by reporting any suspected issues and * * participating in the community forum: * * http://www.FreeRTOS.org/support * * * * Thank you! * * * *************************************************************************** http://www.FreeRTOS.org - Documentation, books, training, latest versions, license and Real Time Engineers Ltd. contact details. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and mission critical applications that require provable dependability. 1 tab == 4 spaces! */ #include #include #include "FreeRTOSConfig.h" #include "ISR_Support.h" .extern pxCurrentTCB .extern vTaskSwitchContext .extern vPortIncrementTick .extern xISRStackTop .global vPortStartFirstTask .global vPortYieldISR .global vPortTickInterruptHandler /******************************************************************/ .set nomips16 .set nomicromips .set noreorder .set noat /*************************************************************** * The following is needed to locate the * vPortTickInterruptHandler function into the correct vector ***************************************************************/ #ifdef configTICK_INTERRUPT_VECTOR #if (configTICK_INTERRUPT_VECTOR == _CORE_TIMER_VECTOR) .equ __vector_dispatch_0, vPortTickInterruptHandler .global __vector_dispatch_0 .section .vector_0, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_1_VECTOR) .equ __vector_dispatch_4, vPortTickInterruptHandler .global __vector_dispatch_4 .section .vector_4, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_2_VECTOR) .equ __vector_dispatch_9, vPortTickInterruptHandler .global __vector_dispatch_9 .section .vector_9, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_3_VECTOR) .equ __vector_dispatch_14, vPortTickInterruptHandler .global __vector_dispatch_14 .section .vector_14, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_4_VECTOR) .equ __vector_dispatch_19, vPortTickInterruptHandler .global __vector_dispatch_19 .section .vector_19, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_5_VECTOR) .equ __vector_dispatch_24, vPortTickInterruptHandler .global __vector_dispatch_24 .section .vector_24, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_6_VECTOR) .equ __vector_dispatch_28, vPortTickInterruptHandler .global __vector_dispatch_28 .section .vector_28, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_7_VECTOR) .equ __vector_dispatch_32, vPortTickInterruptHandler .global __vector_dispatch_32 .section .vector_32, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_8_VECTOR) .equ __vector_dispatch_36, vPortTickInterruptHandler .global __vector_dispatch_36 .section .vector_36, code, keep #elif (configTICK_INTERRUPT_VECTOR == _TIMER_9_VECTOR) .equ __vector_dispatch_40, vPortTickInterruptHandler .global __vector_dispatch_40 .section .vector_40, code, keep #endif #else .equ __vector_dispatch_4, vPortTickInterruptHandler .global __vector_dispatch_4 .section .vector_4, code, keep #endif .ent vPortTickInterruptHandler vPortTickInterruptHandler: portSAVE_CONTEXT jal vPortIncrementTick nop portRESTORE_CONTEXT .end vPortTickInterruptHandler /******************************************************************/ .set noreorder .set noat .section .text, code .ent vPortStartFirstTask vPortStartFirstTask: /* Simply restore the context of the highest priority task that has been created so far. */ portRESTORE_CONTEXT .end vPortStartFirstTask /*******************************************************************/ .set nomips16 .set nomicromips .set noreorder .set noat /*************************************************************** * The following is needed to locate the vPortYieldISR function * into the correct vector ***************************************************************/ .equ __vector_dispatch_1, vPortYieldISR .global __vector_dispatch_1 .section .vector_1, code .ent vPortYieldISR vPortYieldISR: /* Make room for the context. First save the current status so it can be manipulated, and the cause and EPC registers so thier original values are captured. */ addiu sp, sp, -portCONTEXT_SIZE mfc0 k1, _CP0_STATUS /* Also save s6 and s5 so they can be used. Any nesting interrupts should maintain the values of these registers across the ISR. */ sw s6, 44(sp) sw s5, 40(sp) sw k1, portSTATUS_STACK_LOCATION(sp) /* Prepare to re-enabled interrupts above the kernel priority. */ ins k1, zero, 10, 7 /* Clear IPL bits 0:6. */ ins k1, zero, 18, 1 /* Clear IPL bit 7. It would be an error here if this bit were set anyway. */ ori k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) ins k1, zero, 1, 4 /* Clear EXL, ERL and UM. */ /* s5 is used as the frame pointer. */ add s5, zero, sp /* Swap to the system stack. This is not conditional on the nesting count as this interrupt is always the lowest priority and therefore the nesting is always 0. */ la sp, xISRStackTop lw sp, (sp) /* Set the nesting count. */ la k0, uxInterruptNesting addiu s6, zero, 1 sw s6, 0(k0) /* s6 holds the EPC value, this is saved with the rest of the context after interrupts are enabled. */ mfc0 s6, _CP0_EPC /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ mtc0 k1, _CP0_STATUS /* Save the context into the space just created. s6 is saved again here as it now contains the EPC value. */ sw ra, 120(s5) sw s8, 116(s5) sw t9, 112(s5) sw t8, 108(s5) sw t7, 104(s5) sw t6, 100(s5) sw t5, 96(s5) sw t4, 92(s5) sw t3, 88(s5) sw t2, 84(s5) sw t1, 80(s5) sw t0, 76(s5) sw a3, 72(s5) sw a2, 68(s5) sw a1, 64(s5) sw a0, 60(s5) sw v1, 56(s5) sw v0, 52(s5) sw s7, 48(s5) sw s6, portEPC_STACK_LOCATION(s5) /* s5 and s6 has already been saved. */ sw s4, 36(s5) sw s3, 32(s5) sw s2, 28(s5) sw s1, 24(s5) sw s0, 20(s5) sw $1, 16(s5) /* s7 is used as a scratch register as this should always be saved across nesting interrupts. */ /* Save the AC0, AC1, AC2 and AC3. */ mfhi s7, $ac1 sw s7, 128(s5) mflo s7, $ac1 sw s7, 124(s5) mfhi s7, $ac2 sw s7, 136(s5) mflo s7, $ac2 sw s7, 132(s5) mfhi s7, $ac3 sw s7, 144(s5) mflo s7, $ac3 sw s7, 140(s5) rddsp s7 sw s7, 148(s5) mfhi s7, $ac0 sw s7, 12(s5) mflo s7, $ac0 sw s7, 8(s5) /* Save the stack pointer to the task. */ la s7, pxCurrentTCB lw s7, (s7) sw s5, (s7) /* Set the interrupt mask to the max priority that can use the API. The yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever raise the IPL value and never lower it. */ di ehb mfc0 s7, _CP0_STATUS ins s7, zero, 10, 7 ins s7, zero, 18, 1 ori s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1 /* This mtc0 re-enables interrupts, but only above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ mtc0 s6, _CP0_STATUS ehb /* Clear the software interrupt in the core. */ mfc0 s6, _CP0_CAUSE ins s6, zero, 8, 1 mtc0 s6, _CP0_CAUSE ehb /* Clear the interrupt in the interrupt controller. */ la s6, IFS0CLR addiu s4, zero, 2 sw s4, (s6) jal vTaskSwitchContext nop /* Clear the interrupt mask again. The saved status value is still in s7. */ mtc0 s7, _CP0_STATUS ehb /* Restore the stack pointer from the TCB. */ la s0, pxCurrentTCB lw s0, (s0) lw s5, (s0) /* Restore the rest of the context. */ lw s0, 128(s5) mthi s0, $ac1 lw s0, 124(s5) mtlo s0, $ac1 lw s0, 136(s5) mthi s0, $ac2 lw s0, 132(s5) mtlo s0, $ac2 lw s0, 144(s5) mthi s0, $ac3 lw s0, 140(s5) mtlo s0, $ac3 lw s0, 148(s5) wrdsp s0 lw s0, 8(s5) mtlo s0, $ac0 lw s0, 12(s5) mthi s0, $ac0 lw $1, 16(s5) lw s0, 20(s5) lw s1, 24(s5) lw s2, 28(s5) lw s3, 32(s5) lw s4, 36(s5) /* s5 is loaded later. */ lw s6, 44(s5) lw s7, 48(s5) lw v0, 52(s5) lw v1, 56(s5) lw a0, 60(s5) lw a1, 64(s5) lw a2, 68(s5) lw a3, 72(s5) lw t0, 76(s5) lw t1, 80(s5) lw t2, 84(s5) lw t3, 88(s5) lw t4, 92(s5) lw t5, 96(s5) lw t6, 100(s5) lw t7, 104(s5) lw t8, 108(s5) lw t9, 112(s5) lw s8, 116(s5) lw ra, 120(s5) /* Protect access to the k registers, and others. */ di ehb /* Set nesting back to zero. As the lowest priority interrupt this interrupt cannot have nested. */ la k0, uxInterruptNesting sw zero, 0(k0) /* Switch back to use the real stack pointer. */ add sp, zero, s5 /* Restore the real s5 value. */ lw s5, 40(sp) /* Pop the status and epc values. */ lw k1, portSTATUS_STACK_LOCATION(sp) lw k0, portEPC_STACK_LOCATION(sp) /* Remove stack frame. */ addiu sp, sp, portCONTEXT_SIZE mtc0 k1, _CP0_STATUS mtc0 k0, _CP0_EPC ehb eret nop .end vPortYieldISR