在前一段时间分析了ARM异常处理机制的处理方式,分析了在异常产生以后CPU自动完成的相关处理以及程序员应该完成的基本操作。着重分析了异常代码的返回地址分析已经采用通用代码处理各种异常的可能性。
异常处理的基本过程如下:异常产生(在指令的临界中检测CPU的状态,一般实质在这条指令被执行完成,但是还没有执行下一条指令之前检测)——>保存状态寄存器,切换状态寄存器,保存LR=PC-4,强制PC跳转到对应异常向量(以上的过程都是CPU自动完成)——》调整返回地址,在栈中保存寄存器,便于恢复寄存器的值——》异常处理函数——》退出异常。
中断处理机制的两种形式:
1、
采用在中断向量中存储简单的跳转指令,跳转到异常处理函数中,但是这种方式存在的缺点就是跳转指令的范围是有局限性的。
2、
采用更新PC值的方法进行,具体的实现形式是在另一个固定地址处(handle_addr)保存对应异常处理函数的地址,然后采用LDR PC [PC, offset],其中offset = handle_addr – vect – 0x08;这种机制只要保证选择的地址恰当就能实现不同距离的跳转。
以上的分析和处理在上一次中已经分析,这次分析中断的处理过程,中断只是异常的一种特殊情况,对异常的处理得到了好的理解,那么对中断的处理也就比较方便了。
在ARM内核中只支持IRQ和IFQ两种类型的中断,但是不同的厂商提供不同类型的中断控制器实现对中断的扩展,使得实际的芯片更加适合我们的使用。但是中断控制器的差别也使得不同厂商的中断处理也有差别,但是基本的思想是一致的。
S3C2440的中断控制器一个支持60种中断源,基本的实现如上图所示。基本的寄存器包括SRCPND、INTPND(有且仅有1bit会被置位,可以通过这个寄存器判断中断源,找出那个IRQ源发生中断)、INTMOD、INTMSK、PRIORITY(用来改变中断的优先级顺序,但是其中还是存在一些固有的顺序,具体的参看手册)、INTOFFSET(用来表示IRQ中INTPND的那个bit被置位,这样每一类的中断源都存在一个固定的偏移量,这个寄存器可以用来用来计算偏移量以及通过这个偏移量找到对应的中断处理函数地址存储位置等),当然也存在一些关于多个中断源构成的子中断寄存器,SUBSRCPND、INTSUBMSK。
在S3C2440的启动代码中描述了关于中断处理过程的基本过程和原理。
首先需要搞清楚下面的一个宏定义:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub
sp,sp,#4
;decrement sp(to store jump address)
stmfd
sp!,{r0}
USH the work register to stack(lr does not push because it return to original address)
ldr
r0,=$HandleLabel;load the address of HandleXXX to r0
ldr
r0,[r0]
;load the contents(service routine start address) of HandleXXX
str
r0,[sp,#4]
;store the contents(ISR) of HandleXXX to stack
ldmfd
sp!,{r0,pc}
OP the work register and pc(jump to ISR)
MEND |