blob: 4e56f449390049407b5f3130b2fee7c3bffb799d [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
; 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
stsr PSW, r18
tst r18, r19
; Jump over next 3 instructions: stsr (4 bytes)*2 + popsp (4 bytes)
bz 12
popsp r18, r19
ldsr r18, FPEPC
ldsr r19, 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, r19
mov FPU_MSK, r16
tst r16, r19
bz 12
stsr FPSR, r18
stsr FPEPC, r19
pushsp r18, r19
.endm
;------------------------------------------------------------------------------
; Restore used registers
;------------------------------------------------------------------------------
RESTORE_REGISTER .macro
mov FPU_MSK, r16
stsr PSW, r18
tst r18, r19
bz 12
popsp r18, r19
ldsr r18, FPEPC
ldsr r19, FPSR
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, 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, r15
cmp r16, r15
be 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