|
这几天在弄UCOS ii的程序,是基于IAR软件的。其中有个地方不是很明白,在程序的开始,堆栈好各堆栈后进入的系统模式(sys),也就是说任务在系统模式下运行。但中断(irq)来了后进入IRQ模式执行中断的汇编代码(os_cpu_a.asm),可是在刚进入IRQ后就切换到了管理模式(SVC),之后调用中断的C语言部分。问题是为什么又进入了SVC模式呢?那这样的的话IRQ的任务堆栈,SVC的堆栈大小不是很小就可以了吗?
OS_CPU_ARM_ExceptIrqHndlr
SUB LR, LR, #4 ;
STMFD SP!, {R0-R3} ;压栈工作寄存器
MOV R0, #OS_CPU_ARM_EXCEPT_IRQ ; Set exception ID to OS_CPU_ARM_EXCEPT_IRQ.
MRS R1, SPSR ;
MOV R2, LR ; 保存连接寄存器
MOV R3, SP ; 保存堆栈指针
; Change to SVC mode & disable interruptions.
MSR CPSR_c, #(OS_CPU_ARM_CONTROL_INT_DIS | OS_CPU_ARM_MODE_SVC) ;切换到SVC模式
;为什么要切换到SVC模式 有的说是为了中断的嵌套?
; SAVE CONTEXT ONTO SVC STACK:
STMFD SP!, {R2} ; Push task's PC,
STMFD SP!, {LR} ; Push task's LR,
STMFD SP!, {R4-R12} ; Push task's R12-R4,
LDMFD R3!, {R5-R8} ; Move task's R3-R0 from exception stack to task's stack.
STMFD SP!, {R5-R8}
STMFD SP!, {R1} ; Push task's CPSR (i.e. exception SPSR).
LDR R3, =OSRunning ; if (OSRunning == 1)
LDRB R4, [R3] ;
CMP R4, #1
BNE OS_CPU_ARM_IRQHndlr_BreakNothing
; HANDLE NESTING COUNTER:
LDR R3, =OSIntNesting ; OSIntNesting++;
LDRB R4, [R3]
ADD R4, R4, #1
STRB R4, [R3]
CMP R4, #1 ; if (OSIntNesting == 1)
BNE OS_CPU_ARM_IRQHndlr_BreakIRQ
;********************************************************************************************************
; IRQ HANDLER: TASK INTERRUPTED
;
; Register Usage: R0 Exception Type
; R1
; R2
; R3
;********************************************************************************************************
OS_CPU_ARM_IRQHndlr_BreakTask
LDR R3, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R4, [R3]
STR SP, [R4]
LDR R3, =OS_CPU_ExceptStkBase ; Switch to exception stack.
LDR SP, [R3]
;OS_CPU_ExceptStkBase 是一个128字节的数组 用作调用C语言函数堆栈使用? ;这个SP堆栈应该是为了减少SVC模式堆栈的负荷量,单独是用高了一个堆栈区?
; EXECUTE EXCEPTION HANDLER:
LDR R1, =OS_CPU_ExceptHndlr1 ; OS_CPU_ExceptHndlr(except_type = R0)
MOV LR, PC
BX R1
; Change to IRQ mode & disable interruptions.
MSR CPSR_c, #(OS_CPU_ARM_CONTROL_INT_DIS | OS_CPU_ARM_MODE_IRQ)
; Adjust exception stack pointer. This is
ADD SP, SP, #(4 * 4)
; Change to SVC mode & disable interruptions.
MSR CPSR_c, #(OS_CPU_ARM_CONTROL_INT_DIS | OS_CPU_ARM_MODE_SVC)
LDR R0, =OSIntExit
MOV LR, PC
BX R0
LDR R3, =OSTCBCur ; SP = OSTCBCur->OSTCBStkPtr;
LDR R4, [R3]
LDR SP, [R4]
; RESTORE NEW TASK'S CONTEXT:
LDMFD SP!, {R0} ; Pop new task's CPSR,
MSR SPSR_cxsf, R0
LDMFD SP!, {R0-R12, LR, PC}^ ; Pop new task's context.
|
|