📄 tct.s
字号:
;*
;* OUTPUTS
;*
;* r0 - Available bytes on stack
;*
;* REGISTERS MODIFIED
;*
;* r0, r1, r2, r3
;*
;* HISTORY
;*
;* NAME DATE REMARKS
;*
;* Driscoll, D 01/24/2003 Released Version 1.14.1
;************************************************************************
;INT TCT_Check_Stack(VOID);
EXPORT TCT_Check_Stack
TCT_Check_Stack
; Pickup the current thread pointer.
LDR r0,TCT_Current_Thread1
LDR r0,[r0]
; Determine if there is a current thread.
CMP r0,#0 ; Determine if a thread is active
MOV r3,#0 ; Default remaining value
BEQ TCT_Skip_Stack_Check ; If NU_NULL, skip stack checking
; Determine if the stack pointer has overflowed
LDR r2,[r0,#TC_STACK_START] ; Pickup start of stack area
CMP sp,r2 ; Compare with current stack ptr
BLT TCT_Stack_Range_Error ; If less, stack is out of range
; Determine if the stack pointer has underflowed
LDR r1,[r0,#TC_STACK_END] ; Pickup end of stack area
CMP sp,r1 ; Compare with current stack ptr
BLE TCT_Stack_Range_Okay ; If less, stack range is okay
TCT_Stack_Range_Error
MOV r0,#3 ; Build NU_STACK_OVERFLOW code
BL ERC_System_Error ; Call system error handler
TCT_Stack_Range_Okay
; Calculate the amount of available space on the stack.
SUB r3,sp,r2
; Determine if there is enough memory on the stack to save
; all of the registers.
CMP r3,#INT_STACK_SIZE
; If there is enough memory, there is no stack overflow yet
BGE TCT_No_Stack_Error
; Stack overflow condition is about to happen.
MOV r0,#3 ; Build NU_STACK_OVERFLOW code
BL ERC_System_Error ; Call system error handler
TCT_No_Stack_Error
; Determine if this is a new minimum amount of stack space.
; If so, save the new stack minimum.
LDR r2,[r0,#TC_STACK_MINIMUM]
CMP r3,r2
STRCC r3,[r0,#TC_STACK_MINIMUM]
TCT_Skip_Stack_Check
; Return the remaining number of bytes on the stack.
MOV r0,r3
; Return to caller
BX lr
;************************************************************************
;*
;* FUNCTION
;*
;* TCT_Schedule
;*
;* DESCRIPTION
;*
;* This function waits for a thread to become ready. Once a thread
;* is ready, this function initiates a transfer of control to that
;* thread.
;*
;* CALLED BY
;*
;* INC_Initialize Main initialization routine
;* TCT_Control_To_System Transfers control to system
;* TCT_Signal_Exit Exit routine for signals
;* TCT_Unprotect_Specific Unprotects specific protect
;* TCT_Interrupt_Context_Restore Restore context after interrupt
;* TCT_HISR_Shell Entry point for HISRs
;*
;* CALLS
;*
;* TCT_Control_To_Thread Transfer control to a thread
;*
;* INPUTS
;*
;* None
;*
;* OUTPUTS
;*
;* r0 - Pointer to scheduled thread
;*
;* REGISTERS MODIFIED
;*
;* r0, r1, r2
;*
;* HISTORY
;*
;* NAME DATE REMARKS
;*
;* Driscoll, D 01/24/2003 Released Version 1.14.1
;************************************************************************
;VOID TCT_Schedule(VOID)
EXPORT TCT_Schedule
TCT_Schedule
IF NU_TEST2_SUPPORT
; Set suspension time for Nucleus Timing Test
BL Set_Suspend_Time
ENDIF
; Restore interrupts according to the value contained in TCD_Interrupt_Level.
LDR r1,TCT_Int_Level ; Get address of interrupt level
LDR r1,[r1] ; Pickup current interrupt lockout
MRS r0,CPSR ; Pickup current CPSR
BIC r0,r0,#LOCK_MSK ; Clear the interrupt lockout bits
ORR r0,r0,r1 ; Build new interrupt lockout CPSR
MSR CPSR_cxsf,r0 ; Setup new CPSR
; Get the addresses of the HISR and Task to execute
LDR r2,TCT_Execute_HISR
LDR r3,TCT_Execute_Task
IF INCLUDE_PROVIEW
; Check to see if there is a task to execute upon entering TCT_Schedule.
; If not, we start IDLE.
LDR r0,[r2] ; Pickup highest priority HISR ptr
CMP r0,#0 ; Is there a HISR active?
BNE TCT_Schedule_Thread ; Found an HISR
LDR r0,[r3] ; Pickup highest priority Task ptr
CMP r0,#0 ; Is there a task active?
BNE TCT_Schedule_Thread ; If not, start IDLE.
STMDB sp!,{r2-r3} ; Save r2-r3
BL _NU_Idle_Hook
LDMIA sp!,{r2-r3} ; Restore r2-r3
ENDIF
TCT_Schedule_Loop
; Wait until a thread (task or HISR) is available to execute.
; When a thread is available, branch to TCT_Schedule_Thread.
LDR r0,[r2] ; Pickup highest priority HISR ptr
CMP r0,#0 ; Is there a HISR active?
BNE TCT_Schedule_Thread ; Found a HISR
LDR r0,[r3] ; Pickup highest priority Task ptr
CMP r0,#0 ; Is there a task active?
BEQ TCT_Schedule_Loop ; If not, continue the search
TCT_Schedule_Thread
; Either a task or HISR is ready to execute. Lockout interrupts while
; the thread is transferred (by falling through to the following routine).
MRS r1,CPSR ; Pickup CPSR again
ORR r1,r1,#LOCKOUT ; Build interrupt lockout value
MSR CPSR_cxsf,r1 ; Lockout interrupts
;************************************************************************
;*
;* FUNCTION
;*
;* TCT_Control_To_Thread
;*
;* DESCRIPTION
;*
;* This function transfers control to the specified thread. Each
;* time control is transferred to a thread, its scheduled counter
;* is incremented. Additionally, time-slicing for task threads is
;* enabled in this routine. The TCD_Current_Thread pointer is
;* setup by this function.
;*
;* CALLED BY
;*
;* TCT_Schedule Indirectly called
;* TCT_Protect Protection task switch
;*
;* CALLS
;*
;* None
;*
;* INPUTS
;*
;* r0 - Thread pointer to schedule
;*
;* OUTPUTS
;*
;* None
;*
;* REGISTERS MODIFIED
;*
;* r0, r1, r2, r3, sp, pc, SPSR
;*
;* HISTORY
;*
;* NAME DATE REMARKS
;*
;* Driscoll, D 01/24/2003 Released Version 1.14.1
;************************************************************************
;VOID TCT_Control_To_Thread(VOID *thread)
EXPORT TCT_Control_To_Thread
TCT_Control_To_Thread
; Put thread pointer into TCD_Current_Thread
LDR r1,TCT_Current_Thread1 ; Pickup current thread ptr address
STR r0,[r1] ; Setup current thread pointer
; Increment the thread scheduled counter
LDR r2,[r0, #TC_SCHEDULED] ; Pickup scheduled count
ADD r2,r2,#1 ; Increment the scheduled count
STR r2,[r0, #TC_SCHEDULED] ; Store new scheduled count
; Check for time slice option
LDR r3,[r0, #TC_CUR_TIME_SLICE] ; Pickup time slice value
CMP r3,#0 ; Is there a time slice?
BEQ TCT_No_Start_TS_1 ; If 0, there is no time slice
; Set-up the time slice value
LDR r2,TCT_Time_Slice ; Pickup address of TMD_Time_Slice
STR r3,[r2] ; Setup the time slice
; Enable the time-slice timer
LDR r1,TCT_Slice_State ; Pickup address of TMD_Time_Slice_State
MOV r2,#0 ; Build active state flag
STR r2,[r1] ; Set the active flag
TCT_No_Start_TS_1
; Nucleus MMU
; Get module pointer, switch Translation Table, flush TLBs, and
; flush cache for the new thread
IF NU_MODULE_SUPPORT
LDR r1,Current_Module ; load current module pointer
LDR r2,[r1, #0] ; setup module pointer
LDR r3,[r0, #TC_ID] ; Pickup id for current thread
LDR r4,=TC_TASK_ID
CMP r3,r4 ; determine if thread is task or HISR
BNE TCT_HISR_Module ; if not equal this is a HISR
LDR r3,[r0, #TC_MODULE] ; Pickup module pointer of task thread
B TCT_Check_Same_Module ; skip the HISR code
TCT_HISR_Module
LDR r3,[r0, #TC_HISR_MODULE] ; Pickup module pointer of HISR thread
TCT_Check_Same_Module
CMP r2,r3 ; is new thread part of current module?
BEQ TCT_Same_Module ; if so, do nothing
STR r3,[r1, #0] ; update the current module pointer
IF NU_MMU_MODE
STMDB sp!,{r0} ; Save r0 so we can pass TTBR to
; MMT_Set_Translation_Table
LDR r0,[r3, #MS_TARGET] ; Get Level 1 base from module and set it up
BL MMT_Set_Translation_Table
LDMIA sp!,{r0} ; restore r0 from stack
ENDIF
TCT_Same_Module
IF NU_MMU_MODE
LDR r2,Kernel_Module ; Get the kernel module
CMP r3,r2 ; compare to the current module
MOV r2,#0 ; initialize the register
BNE TCT_Skip_Kernel_Check ; leave zero for possible MMU Enable
MOV r2,#1 ; change to 1 so we don't enable MMU
TCT_Skip_Kernel_Check
ENDIF ; End NU_MMU_MODE
ENDIF ; End NU_MMU_API
; If Nucleus Proview is defined.
IF INCLUDE_PROVIEW
STMDB sp!,{r0} ; Push r0
BL _NU_Schedule_Task_Hook ; Branch to RTView
LDMIA sp!,{r0} ; Pop r0
ENDIF
; Pickup the thread's stack pointer and resume the thread.
LDR sp,[r0, #TC_STACK_POINTER]
; Find out if we need to turn on MMU
IF NU_MMU_MODE
LDR r3,[r0, #TC_SU_MODE]
ORR r3,r3,r2
ENDIF
; Pop off the stack top to determine stack type
LDR r1,[sp], #4
; Remove CPSR from stack and put in SPSR
LDR r0,[sp], #4 ; Pop off the CPSR
IF NU_MMU_MODE
CMP r3,#0
BNE TCT_Skip_MMU_Enable
MMU_ENABLE
TCT_Skip_MMU_Enable
ENDIF
; Check if interrupt stack or solicited stack
CMP r1,#1 ; Compare stack type with 1
BEQ TCT_Interrupt_Resume ; If equal to 1, interrupt stack frame
IF NU_SUPERV_USER_MODE
MOV r2,sp ; save current stack pointer
ADD sp,sp,#40 ; calculate new stack pointer for system mode
MRS r1,CPSR ; Pickup current CPSR
BIC r1,r1,#MODE_MASK ; Clear mode
ORR r1,r1,#SUP_MODE ; Set to supervisor
MSR CPSR_cxsf,r1 ; change to supervisor
MSR SPSR_cxsf,r0 ; Place thread CPSR into the SPSR.
; With mode switching this must be done
; after the switch to supervisor mode
; so that we have a SPSR register available
LDMIA r2,{r4-r12,pc}^ ; A solicited return is required.
; This type of return only
; recovers r4-r12 & pc
ELSE
MSR SPSR_cxsf,r0 ; Place thread CPSR into the SPSR.
; With mode switching this must be done
; after the switch to supervisor mode
; so that we have a SPSR register available
; Recover all solicited stack frame registers and return
LDMIA sp!,{r4-r12,pc}^ ; A solicited return is required.
; This type of return only
; recovers r4-r12 & pc
ENDIF
TCT_Interrupt_Resume
IF NU_SUPERV_USER_MODE
ADD r3,sp,#56 ; calculate lr start
LDMIA r3,{lr} ; restore lr in system mode
MOV r3,sp ; save current stack pointer
ADD sp,sp,#64 ; calculate new stack pointer
MRS r2,CPSR ; Pickup current CPSR
BIC r2,r2,#MODE_MASK ; Clear mode
ORR r2,r2,#SUP_MODE ; Set to supervisor
MSR CPSR_cxsf,r2 ; change to supervisor
MOV sp,r3 ; restore stack pointer
MSR SPSR_cxsf,r0 ; Place thread CPSR into the SPSR.
; With mode switching this must be done
; after the switch to supervisor mode
; so that we have a SPSR register available
LDMIA sp,{r0-pc}^
ELSE
MSR SPSR_cxsf,r0 ; Place thread CPSR into the SPSR.
; With mode switching this must be done
; after the switch to supervisor mode
; so that we have a SPSR register available
; Recover all registers and resume at point of interrupt
LDMIA sp,{r0-pc}^
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -