📄 os_cpu_a.s
字号:
;*
;* File: os_cpu_a.s
;*
;* (c) Copyright ARM Limited 1999. All rights reserved.
;*
;* ARM Specific code
;*
;*
;
; Functions defined in this module:
;
; void ARMDisableInt(void) /* disable interrupts when in SVC */
; void ARMEnableInt(void) /* enable interrupts when in SVC */
; void OS_TASK_SWAP(void) /* context switch */
; void OSStartHighRdy(void) /* start highest priority task */
SwiV EQU 0x08
IrqV EQU 0x18
FiqV EQU 0x1C
NoInt EQU 0x80
SVC32Mode EQU 0x13
IRQ32Mode EQU 0x12
FIQ32Mode EQU 0x11
OSEnterSWI EQU 0x00
BIT_TIMER0 EQU (0x1<<13)
I_ISPC EQU 0x1e00024
INTMSK EQU 0x1e0000c
PRESERVE8
AREA |subr|, CODE, READONLY
; External symbols we need the addresses of
IMPORT OSTCBCur
addr_OSTCBCur DCD OSTCBCur
IMPORT OSTCBHighRdy
addr_OSTCBHighRdy DCD OSTCBHighRdy
IMPORT OSPrioCur
addr_OSPrioCur DCD OSPrioCur
IMPORT OSPrioHighRdy
addr_OSPrioHighRdy DCD OSPrioHighRdy
IMPORT need_to_swap_context
IMPORT OSRunning
IMPORT IrqStart
IMPORT OSTimeTick
IMPORT IrqFinish
IMPORT OSIntNesting
; IMPORT OutDebug
IMPORT BreakPoint
EXPORT IRQContextSwap
EXPORT TickHandler
IMPORT OSIntEnter
IMPORT OSIntExit
IMPORT DoInt4567Isr
; 此段代码不会执行
IRQContextSwap
LDMIA sp!,{a1-v1, lr}
SUBS pc, lr, #4
; 时钟中断服务程序
TickHandler
STMDB sp!,{r0-r11,lr}
;interrupt disable(not nessary)
mrs r0, CPSR
orr r0, r0, #0x80 ; and set IRQ disable flag
msr CPSR_cxsf, r0
; End of interrupt
; (Clear pending bit of INTPEND that don't accessed it.)
; rI_ISPC= BIT_TIMER0;
LDR r0, =I_ISPC
LDR r1, =BIT_TIMER0
STR r1, [r0]
BL IrqStart
BL OSTimeTick
BL IrqFinish
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 判断是否需要进行context switch ;
; 若需要切换则跳转到_CON_SWAP ;
; 若不需切换则跳转到_NOT_CN_SWAP ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LDR r0, =need_to_swap_context
LDR r2, [r0]
CMP r2, #1
LDREQ pc, =_CON_SWAP
_NOT_CON_SWAP
LDMIA sp!,{r0-r11, lr}
SUBS pc, lr, #4
_CON_SWAP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; context switch前的准备工作 ;
; 首先将need_to_swap_context清零 ;
; 由于进入中断的时候保存了被中断任务的r0-r11,所以在开始context switch前要先将堆栈复原 ;
; 计算出被中断任务的返回指针,并暂存到SAVED_LR ;
; 由irq模式切换到svc模式 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MOV r1, #0
STR r1, [r0]
LDMIA sp!,{r0-r11,lr}
SUB lr, lr, #4
STR lr, SAVED_LR
MRS lr, SPSR
AND lr, lr, #0xFFFFFFE0
ORR lr, lr, #0x13
MSR CPSR_cxsf, lr
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 模式转换完成后,开始context switch ;
; 堆栈内容的变化 ;
; 1 2 3 4 5 6 ;
;H sp |---| sp |---| |---| |---| |---| |---| |---| ;
; | | | | sp |_LR| |_LR| sp |_LR| |_LR| |_LR| ;
; | | |r12| |r12| sp |r12| | |>r12 sp|lr | |lr | ;
;L | | | | | | | | | | | | |r12| ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STR r12, [sp, #-8] ; 暂存r12 ;1
LDR r12, SAVED_LR ; 载入任务返回指针
STMFD sp!, {r12} ; 将返回指针存储到栈顶 ;2
SUB sp, sp, #4 ; 调整堆栈指针指向r12的位置 ;3
LDMIA sp!, {r12} ; 恢复r12 ;4
STMFD sp!, {lr} ; 开始依次保存各寄存器 ;5
STMFD sp!, {r0-r12} ; ;6
MRS r4, CPSR ;
STMFD sp!, {r4} ;
MRS r4, SPSR ;
STMFD sp!, {r4} ;
; OSPrioCur = OSPrioHighRdy
LDR r4, addr_OSPrioCur
LDR r5, addr_OSPrioHighRdy
LDRB r6, [r5]
STRB r6, [r4]
; Get current task TCB address
LDR r4, addr_OSTCBCur
LDR r5, [r4]
STR sp, [r5] ; store sp in preempted tasks's TCB
; Get highest priority task TCB address
LDR r6, addr_OSTCBHighRdy
LDR r6, [r6]
LDR sp, [r6] ; get new task's stack pointer
; OSTCBCur = OSTCBHighRdy
STR r6, [r4] ; set new current task TCB address
LDMFD sp!, {r4} ; YYY+
MSR SPSR_cxsf, r4 ; YYY+
LDMFD sp!, {r4} ; YYY+
MSR CPSR_cxsf, r4 ; YYY+
LDMFD sp!, {r0-r12, lr, pc} ; YYY+
SAVED_LR DCD 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ARMDisableInt 禁止中断 ;
; ARMEnableINt 允许中断 ;
; AEMIsDisableInt 查询中断状态 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EXPORT ARMDisableInt
ARMDisableInt
STMDB sp!, {r0}
MRS r0, CPSR
ORR r0, r0, #NoInt
MSR CPSR_cxsf, r0
LDMIA sp!, {r0}
MOV pc, lr
EXPORT ARMEnableInt
ARMEnableInt
STMDB sp!, {r0}
MRS r0, CPSR
BIC r0, r0, #NoInt
MSR CPSR_cxsf, r0
LDMIA sp!, {r0}
MOV pc, lr
EXPORT ARMIsDisableInt
ARMIsDisableInt ;return value [disable: 1 enable: 0]
MRS a1, CPSR
AND a1, a1, #NoInt
MOV pc, lr
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; void OS_TASK_SW(void) ;
; Perform a context switch. ;
; On entry, OSTCBCur and OSPrioCur hold the current TCB and priority ;
; and OSTCBHighRdy and OSPrioHighRdy contain the same for the task to be switched to. ;
; The following code assumes that the virtual memory is directly mapped into physical memory. ;
; If this is not true, the cache must be flushed at context switch to avoid address aliasing. ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EXPORT OS_TASK_SW
OS_TASK_SW
STMFD sp!, {lr} ; save pc
STMFD sp!, {lr} ; save lr
STMFD sp!, {r0-r12} ; save register file and ret address
MRS r4, CPSR
STMFD sp!, {r4} ; save current PSR
MRS r4, SPSR ; YYY+
STMFD sp!, {r4} ; YYY+ save SPSR
; OSPrioCur = OSPrioHighRdy
LDR r4, addr_OSPrioCur
LDR r5, addr_OSPrioHighRdy
LDRB r6, [r5]
STRB r6, [r4]
; Get current task TCB address
LDR r4, addr_OSTCBCur
LDR r5, [r4]
STR sp, [r5] ; store sp in preempted tasks's TCB
; Get highest priority task TCB address
LDR r6, addr_OSTCBHighRdy
LDR r6, [r6]
LDR sp, [r6] ; get new task's stack pointer
; OSTCBCur = OSTCBHighRdy
STR r6, [r4] ; set new current task TCB address
LDMFD sp!, {r4} ; YYY+
MSR SPSR_cxsf, r4 ; YYY+
LDMFD sp!, {r4} ; YYY+
MSR CPSR_cxsf, r4 ; YYY+
LDMFD sp!, {r0-r12, lr, pc} ; YYY+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; void OSStartHighRdy(void) ;
; Start the task with the highest priority ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EXPORT OSStartHighRdy
OSStartHighRdy
LDR r0, =OSRunning ; OSRunning = 1
MOV r1, #1
STRB r1, [r0]
LDR r4, addr_OSTCBCur ; Get current task TCB address
LDR r5, addr_OSTCBHighRdy ; Get highest priority task TCB address
LDR r5, [r5] ; get stack pointer
LDR sp, [r5] ; switch to the new stack
STR r5, [r4] ; set new current task TCB address
LDMFD sp!, {r4} ; YYY
MSR SPSR_cxsf, r4
LDMFD sp!, {r4} ; get new state from top of the stack
MSR CPSR_cxsf, r4 ; CPSR should be SVC32Mode
LDMFD sp!, {r0-r12, lr, pc } ; start the new task
K_LINK_SAVE DCD 0
K_PSR_SAVE DCD 0
EXPORT OSEINT4567ISR
OSEINT4567ISR
STMFD sp!, {r4}
LDR r4, =K_LINK_SAVE
STR lr, [r4] ; LINK_SAVE = lr_irq
MRS lr, spsr
STR lr, [r4, #4] ; PSR_SAVE = spsr_irq
LDMFD sp!, {r4}
ORR lr, lr, #0x80 ; Mask irq for context switching before
MSR cpsr_cxsf, lr ; returning back from irq mode.
SUB sp, sp, #4 ; Space for PC
STMFD sp!, {r0-r12, lr}
LDR r4, =K_LINK_SAVE
LDR lr, [r4, #0]
SUB lr, lr, #4 ; lr = LINK_SAVE - 4,
STR lr, [sp, #(14*4)] ; the return address for pc.
LDR r4, [r4, #4] ; r4 = PSR_SAVE,
STMFD sp!, {r4} ; CPSR of the task
BL OSIntEnter
LDR r4, =OSIntNesting
LDRB r4, [r4]
CMP r4, #1
LDRNE pc, =_LDRSP
LDR r4, addr_OSTCBCur
LDR r4, [r4]
STR sp, [r4] ; OSTCBCur -> stkptr = sp
_LDRSP
BL DoInt4567Isr
BL OSIntExit
LDMFD sp!, {r4} ; pop new task cpsr
MSR cpsr_cxsf, r4
LDMFD sp!, {r0-r12,lr,pc} ; pop new task r0-r12,lr & pc
END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;end of Os_cpu_a.s;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -