| --/* |
| -- * FreeRTOS Kernel V11.2.0 |
| -- * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| -- * |
| -- * SPDX-License-Identifier: MIT |
| -- * |
| -- * Permission is hereby granted, free of charge, to any person obtaining a copy of |
| -- * this software and associated documentation files (the "Software"), to deal in |
| -- * the Software without restriction, including without limitation the rights to |
| -- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
| -- * the Software, and to permit persons to whom the Software is furnished to do so, |
| -- * subject to the following conditions: |
| -- * |
| -- * The above copyright notice and this permission notice shall be included in all |
| -- * copies or substantial portions of the Software. |
| -- * |
| -- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| -- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
| -- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
| -- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| -- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| -- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| -- * |
| -- * https://www.FreeRTOS.org |
| -- * https://github.com/FreeRTOS |
| -- * |
| -- */ |
| |
| #include "FreeRTOSConfig.h" |
| |
| ------------------------------------------------------------------------------- |
| -- Extern symbols |
| ------------------------------------------------------------------------------- |
| .extern _uxInterruptNesting |
| .extern _uxPortMaxInterruptDepth |
| .extern _xPortScheduleStatus |
| .extern _vTaskSwitchContext |
| .extern _pvPortGetCurrentTCB |
| .extern _vCommonISRHandler |
| .extern _xPortGET_CORE_ID |
| |
| .global _vIrq_Handler |
| .global _vPortStartFirstTask |
| .global _vPortYield |
| .global _vTRAP0_Handler |
| -------------------------------------------------------------------------------- |
| -- Macro definitions |
| -------------------------------------------------------------------------------- |
| .set EIPC, 0 |
| .set EIPSW, 1 |
| .set PSW, 5 |
| .set FPSR, 6 |
| .set FPEPC, 7 |
| .set FXSR, 6 |
| .set FXXP, 13 |
| .set EIIC, 13 |
| .set CTPC, 16 |
| .set CTPSW, 17 |
| .set EIIC_MSK, 0x00000FFF |
| -------------------------------------------------------------------------------- |
| -- portSAVE_CONTEXT |
| -- Context saving |
| -------------------------------------------------------------------------------- |
| .macro portSAVE_CONTEXT |
| prepare {lp}, 0 |
| |
| -- Save general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC into stack. |
| pushsp r5-r30 |
| --$nowarning |
| pushsp r1-r2 |
| --$warning |
| |
| stsr EIPSW, r15 |
| stsr EIPC, r16 |
| stsr EIIC, r17 |
| stsr CTPSW, r18 |
| stsr CTPC, r19 |
| pushsp r15-r19 |
| |
| -- Save FPU registers to stack if FPU is enabled |
| #if (1 == configENABLE_FPU) |
| stsr FPSR, r18 |
| stsr FPEPC, r19 |
| pushsp r18-r19 |
| #endif |
| |
| -- Save FXU registers to stack if FXU is enabled |
| #if (1 == configENABLE_FXU) |
| mov r0, r20 |
| mov r0, r21 |
| stsr 0, r19, 2 -- Get PEID |
| cmp r19, r0 -- Confirm PEID value is PE0 |
| bne 8 -- branch 2 instructions if is not PE0 |
| -- to avoid unprivileged access |
| stsr FXSR, r20, 10 -- If PE0, save FXU register |
| stsr FXXP, r21, 10 -- If PE0, save FXU register |
| pushsp r20-r21 |
| #endif |
| |
| -- Get current TCB, the return value is stored in r10 |
| jarl _pvPortGetCurrentTCB, lp |
| st.w sp, 0[r10] |
| |
| .endm |
| |
| -------------------------------------------------------------------------------- |
| -- portRESTORE_CONTEXT |
| -- Context restoring |
| -------------------------------------------------------------------------------- |
| .macro portRESTORE_CONTEXT |
| -- Current TCB is returned by r10 |
| jarl _pvPortGetCurrentTCB, lp |
| ld.w 0[r10], sp -- Restore the stack pointer from the TCB |
| |
| -- Restore FXU registers if FXU is enabled |
| #if (1 == configENABLE_FXU) |
| popsp r20-r21 |
| stsr 0, r19, 2 -- Get PEID |
| cmp r19, r0 -- Confirm PEID value is PE0 |
| bne 8 -- branch 2 instructions if is not PE0 |
| -- to avoid unprivileged access |
| ldsr r21, FXXP, 10 -- If PE0, restore FXU register |
| ldsr r20, FXSR, 10 -- If PE0, restore FXU register |
| #endif |
| |
| -- Restore FPU registers if FPU is enabled |
| #if (1 == configENABLE_FPU) |
| popsp r18-r19 |
| ldsr r19, FPEPC |
| ldsr r18, FPSR |
| #endif |
| |
| --Restore general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC |
| popsp r15-r19 |
| ldsr r19, CTPC |
| ldsr r18, CTPSW |
| ldsr r17, EIIC |
| ldsr r16, EIPC |
| ldsr r15, EIPSW |
| |
| --$nowarning |
| popsp r1-r2 |
| --$warning |
| popsp r5-r30 |
| |
| dispose 0, {lp} |
| .endm |
| |
| -------------------------------------------------------------------------------- |
| -- Save used registers |
| -------------------------------------------------------------------------------- |
| .macro SAVE_REGISTER |
| pushsp r5-r30 |
| --$nowarning |
| pushsp r1-r2 |
| --$warning |
| |
| stsr EIPSW, r19 |
| stsr EIPC, r18 |
| stsr EIIC, r17 |
| mov lp, r16 |
| mov ep, r15 |
| stsr CTPSW, r14 |
| stsr CTPC, r13 |
| pushsp r13-r19 |
| |
| #if (1 == configENABLE_FPU) |
| stsr FPSR, r18 |
| stsr FPEPC, r19 |
| pushsp r18-r19 |
| #endif |
| |
| -- Save FXU registers to stack if FXU is enabled |
| #if (1 == configENABLE_FXU) |
| mov r0, r20 |
| mov r0, r21 |
| stsr 0, r19, 2 -- Get PEID |
| cmp r19, r0 -- Confirm PEID value is PE0 |
| bne 8 -- Branch 2 instructions if is not PE0 |
| -- to avoid unprivileged access |
| stsr FXSR, r20, 10 -- If PE0, save FXU register |
| stsr FXXP, r21, 10 -- If PE0, save FXU register |
| pushsp r20-r21 |
| #endif |
| |
| .endm |
| -------------------------------------------------------------------------------- |
| -- Restore used registers |
| -------------------------------------------------------------------------------- |
| .macro RESTORE_REGISTER |
| -- Restore FXU registers if FXU is enabled |
| #if (1 == configENABLE_FXU) |
| popsp r20-r21 |
| stsr 0, r19, 2 -- Get PEID |
| cmp r19, r0 -- Confirm PEID value is PE0 |
| bne 8 -- Branch 2 instructions if is not PE0 |
| -- to avoid unprivileged access |
| ldsr r21, FXXP, 10 -- If PE0, restore FXU register |
| ldsr r20, FXSR, 10 -- If PE0, restore FXU register |
| #endif |
| |
| #if (1 == configENABLE_FPU) |
| popsp r18-r19 |
| ldsr r19, FPEPC |
| ldsr r18, FPSR |
| #endif |
| |
| popsp r13-r19 |
| ldsr r13, CTPC |
| ldsr r14, CTPSW |
| mov r15, ep |
| mov r16, lp |
| ldsr r17, EIIC |
| ldsr r18, EIPC |
| ldsr r19, EIPSW |
| |
| --$nowarning |
| popsp r1-r2 |
| --$warning |
| popsp r5-r30 |
| .endm |
| |
| -------------------------------------------------------------------------------- |
| -- Start the first task. |
| -------------------------------------------------------------------------------- |
| _vPortStartFirstTask: |
| portRESTORE_CONTEXT |
| eiret |
| |
| -------------------------------------------------------------------------------- |
| -- _vPortYield |
| -------------------------------------------------------------------------------- |
| _vPortYield: |
| trap 0 |
| jmp [lp] -- Return to caller function |
| |
| -------------------------------------------------------------------------------- |
| -- PortYield handler. This is installed as the TRAP exception handler. |
| -------------------------------------------------------------------------------- |
| _vTRAP0_Handler: |
| --Save the context of the current task. |
| portSAVE_CONTEXT |
| |
| -- The use case that portYield() is called from interrupt context as nested interrupt. |
| -- Context switch should be executed at the most outer of interrupt tree. |
| -- In that case, set xPortScheduleStatus to flag context switch in interrupt handler. |
| jarl _xPortGET_CORE_ID, lp -- return value is contained in r10 |
| mov r10, r11 |
| shl 2, r11 |
| mov _uxInterruptNesting, r19 |
| add r11, r19 |
| ld.w 0[r19], r18 |
| cmp r0, r18 |
| be _vTRAP0_Handler_ContextSwitch |
| |
| mov _xPortScheduleStatus, r19 |
| add r11, r19 |
| |
| -- Set xPortScheduleStatus[coreID]=PORT_SCHEDULER_TASKSWITCH |
| mov 1, r17 |
| st.w r17, 0[r19] |
| br _vTRAP0_Handler_Exit |
| |
| _vTRAP0_Handler_ContextSwitch: |
| -- Pass coreID (r10) as parameter by r6 in SMP support. |
| mov r10, r6 |
| -- Call the scheduler to select the next task. |
| -- vPortYeild may be called to current core again at the end of vTaskSwitchContext. |
| -- This may case nested interrupt, however, it is not necessary to set |
| -- uxInterruptNesting (currently 0) for nested trap0 exception. The user interrupt |
| -- (EI level interrupt) is not accepted inside of trap0 exception. |
| jarl _vTaskSwitchContext, lp |
| |
| _vTRAP0_Handler_Exit: |
| -- Restore the context of the next task to run. |
| portRESTORE_CONTEXT |
| eiret |
| |
| -------------------------------------------------------------------------------- |
| -- _Irq_Handler |
| -- Handler interrupt service routine (ISR). |
| -------------------------------------------------------------------------------- |
| _vIrq_Handler: |
| -- Save used registers. |
| SAVE_REGISTER |
| |
| -- Get core ID by HTCFG0, thread configuration register. |
| -- Then, increase nesting count for current core. |
| jarl _xPortGET_CORE_ID, lp -- return value is contained in r10 |
| mov r10, r17 |
| shl 2, r17 |
| |
| mov _uxInterruptNesting, r19 |
| add r17, r19 |
| ld.w 0[r19], r18 |
| addi 0x1, r18, r16 |
| st.w r16, 0[r19] |
| |
| pushsp r17-r19 |
| |
| --Call the interrupt handler. |
| stsr EIIC, r6 |
| andi EIIC_MSK, r6, r6 |
| |
| -- Do not enable interrupt for nesting. Stackover flow may occurs if the |
| -- depth of nesting interrupt is exceeded. |
| mov _uxPortMaxInterruptDepth, r19 |
| ld.w 0[r19], r15 |
| cmp r15, r16 |
| bge 4 -- Jump over ei instruction |
| ei |
| jarl _vCommonISRHandler, lp |
| di |
| synce |
| |
| popsp r17-r19 |
| st.w r18, 0[r19] -- Restore the old nesting count. |
| |
| -- A context switch if no nesting interrupt. |
| cmp 0x0, r18 |
| bne _vIrq_Handler_NotSwitchContext |
| |
| -- Check if context switch is requested. |
| mov _xPortScheduleStatus, r19 |
| add r17, r19 |
| ld.w 0[r19], r18 |
| cmp r0, r18 |
| bne _vIrq_Handler_SwitchContext |
| |
| _vIrq_Handler_NotSwitchContext: |
| -- No context switch. Restore used registers |
| RESTORE_REGISTER |
| eiret |
| |
| --This sequence is executed for primary core only to switch context |
| _vIrq_Handler_SwitchContext: |
| -- Clear the context switch pending flag. |
| st.w r0, 0[r19] |
| |
| add -1, r18 |
| bnz _vIrq_Handler_StartFirstTask |
| -- Restore used registers before saving the context to the task stack. |
| RESTORE_REGISTER |
| portSAVE_CONTEXT |
| |
| -- Get Core ID and pass to vTaskSwitchContext as parameter |
| -- The parameter is unused in single core, no problem with this redudant setting |
| jarl _xPortGET_CORE_ID, lp -- return value is contained in r10 |
| mov r10, r6 |
| |
| -- vPortYeild may be called to current core again at the end of vTaskSwitchContext. |
| -- This may case nested interrupt, however, it is not necessary to set |
| -- uxInterruptNesting (currently 0) for trap0 exception. The user interrupt |
| -- (EI level interrupt) is not accepted inside of trap0 exception. |
| jarl _vTaskSwitchContext, lp |
| portRESTORE_CONTEXT |
| eiret |
| |
| _vIrq_Handler_StartFirstTask: |
| RESTORE_REGISTER |
| jr _vPortStartFirstTask |
| |