关于中断和时钟节拍,UCOS-II对于ARM7通用的中断服务程序的汇编与c函数接口如下:
MACRO和MEND伪指令用于宏定义。MACRO……MEND伪指令可以将一段代码定义为一个整体,称为宏定义。其中,$标号在宏指令被展开时,标号会被代换为用户定义的符号。MACRO标识宏定义的开始,MEND标识宏定义的结束。定义之后在程序中就可以通过宏指令多次调用该段代码。MACRO宏定义如下
MACRO
$标号 宏名 $参数1,$参数2,……
指令序列
MEND
IRQ异常处理代码的汇编部分
MACRO
$IRQ_Label HANDLER $IRQ_Exception_Function
;$IRQ_lable标号,用于构造宏定义体内的其他标号。HANDLER是宏的名称,$IRQ_Exception_function是宏的参数
EXPORT $IRQ_Label ; 输出的标号。用于在程序中声明一个全局的标号,
该标号可在其他文件中引用
IMPORT $IRQ_Exception_Function ; 引用的外部标号。用于通知编译器要使用的标号在其他原文件中定义,但要在当前文件中引用
$IRQ_Label
SUB LR, LR, #4 ; 计算返回地址
STMFD SP!, {R0-R3, R12, LR} ; 保存任务环境
MRS R3, SPSR ; 保存状态
STMFD SP, {R3, SP, LR}^ ;保存用户状态的R3,SP,LR,注意不能回写
;后缀”!”表示最后的地址写回到SP中。
;后缀”^”不允许在用户模式或系统模式下使用,若在LDM指令且寄存器列表中包含有PC时使用,那么除了正常的多寄存器传送外,将SPSR也拷贝到CPSR中,这可用于异常处理返回。使用“^”后缀进行数据传送且寄存器列表不包含PC时,加载/存储的是用户模式的寄存器,而不是当前模式的寄存。
注意:这里用的是中断模式的堆栈,一开始就计算真正的返回地址,即将保存在R14_irq的返回地址减4,然后采用IRQ模式的R13_irq来保存中段的上下文,这里保存了R0-R3,R12。LR这6个寄存器。同时,又将用户模式下的CPSR(因为切换到中断模式,所以这里变成了SPSR)和R13(用户模式),R14(用户模式)保存到IRQ模式的堆栈中。注意,这里最后一条没有采用SP!的形式,所以SP是不回写的,保持不变。STMFD SP, {R3, SP, LR}^指的是。如果寄存器列表里面没有PC,那么采用^就表示将用户模式的寄存器的值去出来,所以(R3,SP,LR)指的是用户模式寄存器。
; OSIntNesting++
LDR R2, =OSIntNesting ;将OSIntNesting的地址保存到R2
LDRB R1, [R2] ;将R2指定地址的数据加载到R1
ADD R1, R1, #1
STRB R1, [R2]
SUB SP, SP, #4*3
这段代码将中断嵌套层数加1,并且将刚才没有调整的SP指针向下指3个,这时候SP又指向栈顶。
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
CMP R1, #1
LDREQ SP, =StackUsr
BL $IRQ_Exception_Function ; 调用c语言的中断处理程序
这段代码将运行模式切换到SYS32模式。比较一下R1,看上面的OSIntNesting是否为1。如果为1,则表示第一次进入系统模式,那么将系统指针设定好。
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
LDR R2, =OsEnterSum ; OsEnterSum,使OSIntExit退出时中断关闭
MOV R1, #1
STR R1, [R2]
BL OSIntExit
这段为中断回复代码。这里又切回系统模式。用OsEnterSum变量保证退出OSIntExit不会把中断打开。
LDR R2, =OsEnterSum; 因为中断服务程序要退出,所以OsEnterSum=0
MOV R1, #0
STR R1, [R2]
MSR CPSR_c, #(NoInt | IRQ32Mode) ; 切换回irq模式
LDMFD SP, {R3, SP, LR}^; 恢复用户状态的R3,SP,LR,注意不能回写
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1
ADD SP, SP, #4*3 ;
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不进行任务切换
LDR PC, =OSIntCtxSw ; 进行任务切换
因为上面没有回写弹出的堆栈指针,所以将堆栈指针加3个寄存器内存。根据CMP指令的结果。当优先级没有改变,就直接把终端模式生下来的R0-R3,R12,PC和SPAR弹出,中断结束,用户态程序继续执行。如果优先级发生改变,则进行任务切换。注意,如果寄存器列表里面有PC寄存器,那么在带”^”的情况下,自动将SPSR拷贝到CPSR。
MEND
END