blob: ff8e7ee31f522abd1790177e9e718545baebb32d [file] [log] [blame]
;/*
; * FreeRTOS Kernel <DEVELOPMENT BRANCH>
; * 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
; *
; */
;------------------------------------------------------------------------------
; Extern symbols
;------------------------------------------------------------------------------
.extern _uxInterruptNesting
.extern _uxPortMaxInterruptDepth
.extern _xPortScheduleStatus
.extern _vTaskSwitchContext
.extern _pvPortGetCurrentTCB
.extern _vCommonISRHandler
.extern _xPortGET_CORE_ID
.public _vIrq_Handler
.public _vPortStartFirstTask
.public _vPortYield
.public _vTRAP0_Handler
;------------------------------------------------------------------------------
; Macro definitions
;------------------------------------------------------------------------------
EIPC .set 0
EIPSW .set 1
PSW .set 5
FPSR .set 6
FPEPC .set 7
EIIC .set 13
CTPC .set 16
CTPSW .set 17
EIIC_MSK .set 0x00000FFF
FPU_MSK .set 0x00010000
;------------------------------------------------------------------------------
; portSAVE_CONTEXT
; Context saving
;------------------------------------------------------------------------------
portSAVE_CONTEXT .macro
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
mov FPU_MSK, r19
tst r15, r19
; Jump over next 3 instructions: stsr (4 bytes)*2 + pushsp (4 bytes)
bz 12
stsr FPSR, r18
stsr FPEPC, r19
pushsp r18, r19
; Save EIPSW register to stack
; Due to the syntax of the pushsp instruction, using r14 as dummy value
pushsp r14, r15
; Get current TCB, the return value is stored in r10 (CCRH compiler)
jarl _pvPortGetCurrentTCB, lp
st.w sp, 0[r10]
.endm
;------------------------------------------------------------------------------
; portRESTORE_CONTEXT
; Context restoring
;------------------------------------------------------------------------------
portRESTORE_CONTEXT .macro
; Current TCB is returned by r10 (CCRH compiler)
jarl _pvPortGetCurrentTCB, lp
ld.w 0[r10], sp ; Restore the stack pointer from the TCB
; Restore FPU registers if FPU is enabled
mov FPU_MSK, r19
; Restore EIPSW register to check FPU
; Due to the syntax of the popsp instruction, using r14 as dummy value
popsp r14, r15
tst r15, r19
; Jump over next 3 instructions: stsr (4 bytes)*2 + popsp (4 bytes)
bz 12
popsp r18, r19
ldsr r19, FPEPC
ldsr r18, FPSR
;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
;------------------------------------------------------------------------------
SAVE_REGISTER .macro
; Save general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC into stack.
; Callee-Save registers (r20 to r30) are not used in interrupt handler and
; guaranteed no change after function call. So, don't need to save register
; to optimize the used stack memory.
pushsp r5, r19
$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, r18
mov FPU_MSK, r16
tst r16, r19
bz 8
stsr FPSR, r17
stsr FPEPC, r18
pushsp r17, r19
.endm
;------------------------------------------------------------------------------
; Restore used registers
;------------------------------------------------------------------------------
RESTORE_REGISTER .macro
mov FPU_MSK, r15
popsp r17, r19
tst r19, r15
bz 8
ldsr r18, FPEPC
ldsr r17, FPSR
popsp r13, r18
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, r19
.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 (CCRH compiler)
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 (CCRH compiler) 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 (CCRH compiler)
shl 2, r10
mov r10, 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 (CCRH compiler)
; The parameter is unused in single core, no problem with this redudant setting
jarl _xPortGET_CORE_ID, lp ; return value is contained in r10 (CCRH compiler)
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