ARM的异常
终止程序的正常执行过程而不得不去完成的一些特殊工作
中断是异常的一种,包括外部硬件产生的异常和芯片内部硬件产生的内部中断。
ARM有七种处理器模式,其中用户模式和系统模式之外的5钟处理器模式叫做异常模式,用户模式之外的6钟处理器模式称为特权模式
设计这么多种模式,是为了更好地处理异常。
回顾一下ARM寄存器组:
R13用来保存堆栈指针
R14用来保存上一段程序的返回地址
R15用来保存当前模式的PC指针
CPSR = Current Process State Register
SPSR = Save Process State Register
当从一个特权模式切换到另一个特权模式时:
要将当前模式程序执行PC(R15)- 4 保存到目标模式的R14(LR)中
如果要使用目标模式下的共有寄存器(如R0 ~ R12),则必须要把这些寄存器保存到堆栈中(R13)
为了防止模式切换回来后CPSR被破坏(看图中,CPSR也是公共的),需要将CPSR提前保存到SPSR中
将CPSR切换到相应模式:
将PC值设为目标程序入口地址
(总结来说:两大步:1. 切模式 2. 送地址给PC 其他操作都是为了保存现场而做)
前面为什么要把PC - 4 送到LR寄存器?
因为ARM9三级流水线,且PC总是指向待取指的那条指令,同一时刻:
待取值的指令在PC位置
正在译码的指令在PC-4位置
正在执行的指令在PC-8位置
模式切换时运行的指令一定是执行的指令,那么这个指令下一条指令就是模式切换回来要继续执行的指令,需要保存到目标模式的LR寄存器中,也就是说PC-4送入目标模式的LR。模式切换回来时LR–> PC,就成功跳转到中断时指令的下一条指令了。
提高中断效率
在中断发生时,CPU 进入中断模式,进入中断服务函数。此时CPSR的I位和F位默认被设置为1,也就是说中断是被禁止的。此时若有另一个中断到来,CPU是无法立马响应的,这就影响了中断的效率,属于中断延迟。
要解决中断延迟,一个好的办法是实现中断嵌套,在中断处理时,允许第二中断的产生和对其的响应。但是:
在中断模式下,R14_irq保存的是被中断进程的返回地址,将它保存到堆栈中去,目的是中断模式有函数调用时,R14寄存器可以用于保存函数返回值。如果此时另一个中断恰好发生,R14_irq又要再一次地进行之前的操作:保存中断进程的返回时的地址,此时原来的返回值便弄丢了,此时可以顺利从二级中断返回一级中断将一级中断的服务函数剩余的代码都执行完,但是无法跳转到最开始被中断的进程了。
SPSR寄存器也是一样的窘境,中断模式下SPSR_irq保存了上一个模式的CPSR,如果再来一个中断,SPSR_irq又要保存新中断的CPSR,原来被中断进程的CPSR也弄丢了。
当然,难解决并不代表不能解决,只不过我们需要换个思路,不在中断模式下,而是切换到其他模式进行中断处理。当中断处理程序发生在其他模式(如SVC模式)时,函数调用的返回值会保存在寄存器R14_svc中,即使此时中断再次发生,CPU也会自动进入中断模式,将被中断的程序的返回值保存在R14_irq中,二者不再冲突。这就是实现中断嵌套的普遍方法。