基于ARM920T的OSIntCtxSw()实现分析:
首先必须了解,在将ucos-II移植到ARM920T时,使用了如下结构的任务栈:
程序清单:基于ARM920T的OSIntCtxSw()实现分析: |
_IntCtxSw ; OSIntCtxSwFlag = 0 mov r1,#0 str r1,[r0]
/* 此时正处于中断模式下,因此sp、spsr等寄存器为中断模式下的相应寄存器,因此 r0-r3,r12,lr这些寄存器在进入中断处理程序后,先被保存在了中断模式下的堆栈中。*/ ;现将这些寄存器的值重新恢复。 ldmfd sp!,{r0-r3,r12,lr} ;将r0-r3重新保存回中断模式下的栈空间 stmfd sp!,{r0-r3} /* 此时中断栈的内容(为被中断任务的r0-r3的值): ----------------à r3,r2,r1,r0 ----------------à栈顶 */
;保存中断模式下的栈顶指针sp到r1:r1 = sp_irq mov r1,sp
add sp,sp,#16; sp_irq += 16; ;计算被中断任务的中断返回地址: r2 = lr – 4 sub r2,lr,#4 /* spsr在中断发生时,保存了中断前即用户模式下的cpsr的值,该过程由硬件自动完成 */ ;取中断前的状态寄存器到r3 mrs r3,spsr
orr r0,r3,#NOINT;屏蔽中断 ;返回用户模式(切换到用户堆栈),以便下面保存中断现场 msr cpsr_cxsf,r0
;ldr r0,=.+8 ;movs pc,r0;自动切换到用户堆栈 /* 此时已是用户模式,因此,sp为用户模式的栈顶指针,即被中断任务的堆栈指针。 */ ;根据任务栈结构,分别压栈,保存旧任务的现场 stmfd sp!,{r2} ; push old task's pc stmfd sp!,{r4-r12,lr} ; push old task's lr,r12-r4 /* 此时任务栈的内容: ----------------à pc,lr,r12,r11,,,,,,r4 ----------------à栈顶 */ ;r1为中断栈的栈顶指针,r4 = r1 mov r4,r1 ; Special optimised code below ;r3为中断前状态寄存器cpsr,r5 = r3 mov r5,r3 ;将保存在中断栈中的r0-r3保存到任务栈中,r4为中断栈的栈顶指针 ldmfd r4!,{r0-r3} stmfd sp!,{r0-r3} ; push old task's r3-r0 ;保存任务的cpsr到任务栈 stmfd sp!,{r5} ; push old task's psr ;保存任务的spsr到任务栈 mrs r4,spsr stmfd sp!,{r4} ; push old task's spsr /* 至此,被中断的任务的现场保存完毕! */
; OSPrioCur = OSPrioHighRdy ldr r4,=OSPrioCur ldr r5,=OSPrioHighRdy ldrb r5,[r5] strb r5,[r4]
; Get current task TCB address:r5= OSTCBCur ldr r4,=OSTCBCur ldr r5,[r4] ;OSTCBCur->OSTCBStkPtr = SP; str sp,[r5] ; store sp in preempted tasks's TCB
bl OSTaskSwHook ; call Task Switch Hook
; Get highest priority task TCB address:r6= OSTCBHighRdy ldr r6,=OSTCBHighRdy ldr r6,[r6] ;SP = OSTCBHighRdy ->OSTCBStkPtr; ldr sp,[r6] ; get new task's stack pointer
; OSTCBCur = OSTCBHighRdy str r6,[r4] ; set new current task TCB address
;根据任务栈结构,分别出栈,恢复新任务的现场 ldmfd sp!,{r4} ; pop new task's spsr msr SPSR_cxsf,r4 ldmfd sp!,{r4} ; pop new task's psr msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc |