You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
10 KiB
ArmAsm
332 lines
10 KiB
ArmAsm
;/*
|
|
; * 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
|
|
|