blob: 0561ed0efc00e6d62334737da72bd8d1442707c0 [file]
--/*
-- * 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