4、异常的返回地址
指令预取异常中断与数据访问中止异常中断返回到产生指令预取异常中断与数据访问中止异常中断的指令处,而不是返回到发生异常中断的指令的下一条指令处执行。
根据ARM 的流水线结构,一条指令在执行时,下一条指令在译码,而再下一条指令在取指,因此PC值始终为当前执行指令地址加8,虽然在异常响应时,处理器自动进行了返回地址的修正;LR=PC-4(当前指令的下一条指令),但这个值并不一定就是异常处理返回后要执行的指令地址,具体情况取决于何种异常,分析如下:
(1)复位异常
复位异常的处理程序不需要返回,整个应用系统是从复位异常中断处理程序开始执行的,因而它不需要返回。
(2)SWI和未定义指令异常
SWI和未定义指令异常中断是由当前执行的指令自身产生的。当SWI和未定义指令异常中断产生时,程序计数器PC的值还未更新,它指向当前指令后面第2条指令(对于ARM指令来说+8字节;对于Thumb指令来说+4字节的位置)。当SWI和未定义指令异常中断产生时,处理器将值(PC-4)保存到异常模式下的寄存器LR_mode中。这时(PC-4)即指向当前指令的下一条指令地址。因此返回操作可以通过下面的指令来实现:MOV PC,LR,该指令将寄存器LR中的值复制到程序计数器PC中实现程序返回,同时将SPSR_mode寄存器内容复制到当前程序状态寄存器CPSR中。
(3)IRQ和FIQ异常
通常处理器执行完当前指令后,查询IRQ中断引脚,并查看是否允许IRQ中断,如果某个中断引脚有效,并且系统允许该中断产生,处理器将产生IRQ异常中断,当IRQ异常中断产生时,程序计数器pc的值已经更新,它指向当前指令后面第3条指令(对于ARM指令,它指向当前指令地址加12字节的位置;对于Thumb指令,它指向当前指令地址加6字节的位置),当IRQ异常中断产生时,处理器将值(pc-4)保存到IRQ异常模式下的寄存器lr_irq中,它指向当前指令之后的第2条指令,因此返回操作可以通过下面指令实现:subs pc, lr, #4,该指令将寄存器LR中的值减4后,复制到程序计数器PC中实现程序返回,同时将SPSR_mode寄存器内容复制到当前程序状态寄存器CPSR中。
与IRQ异常中断一样,处理器执行完当前指令后,查询FIQ中断引脚,并查看是否允许FIQ中断,如果中断引脚有效,并且系统允许该中断产生,处理器将产生FIQ异常中断,当FIQ异常中断产生时,程序计数器pc的值已经更新,它指向当前指令后面第3条指令(对于ARM指令,它指向当前指令地址加12字节的位置;对于Thumb指令,它指向当前指令地址加6字节的位置),当FIQ异常中断产生时,处理器将值(pc-4)保存到IRQ异常模式下的寄存器lr_fiq中,它指向当前指令之后的第2条指令,因此返回操作可以通过下面指令实现:subs pc, lr, #4,该指令将寄存器LR中的值减4后,复制到程序计数器PC中实现程序返回,同时将SPSR_mode寄存器内容复制到当前程序状态寄存器CPSR中。
(4)指令预取中止异常
在指令预取时,如果目标地址是非法的,该指令将被标记成有问题的指令。这时,流水线上该指令之前的指令继续执行。当执行到该被标记成有问题的指令时,处理器产生指令预取中止异常中断。
当发生指令预取中止异常中断时,程序要返回到该有问题的指令处,重新读取并执行该指令。因此指令预取中止异常中断程序应该返回到产生该指令预取中止异常的指令处,而不是返回到发生中断的指令的下一条指令。
指令预取中止异常中断是由当前执行的指令自身产生的,当指令预取中止异常中断产生时,程序计数器PC的值还未更新,它指向当前指令后面第2条指令(对于ARM指令来说,它指向当前指令地址加8个字节的w位置;对于Thumb指令来说,它指向当前指令地址加4个字节的位置)。当指令预取中止异常中断产生时,处理器将(PC-4)值保存到异常模式下的寄存器LR_mode中。这时(PC-4)即指向当前指令的下一条指令。因此返回操作可以通过下面的指令来实现:SUBS PC,LR,#4,该指令将寄存器LR中的值减4后,复制到程序计数器PC中,实现程序返回,同时将SPSR_mode寄存器内容复制到当前程序状态寄存器CPSR中。
(5)数据访问中止异常
发生数据访问异常中断时,程序要返回到该有问题的指令处,重新访问该数据,因此数据访问异常中断应该返回到产生该数据访问中止异常中断的指令处,而不是当前指令的下一条指令。
数据访问异常中断由当前执行的指令自身产生,当数据访问异常中断发生时,程序计数器pc的值已经更新,它指向当前指令后面第3条指令(对于ARM指令,它指向当前指令地址加12字节的位置;对于Thumb指令,它指向当前指令地址加6字节的位置)。此时处理器将值(pc-4)保存到lr_abt中,它指向当前指令后面第2条指令,所以返回操作可以通过下面指令实现:subs pc, lr, #8,该指令将lr中的值减8后传给程序计数器pc中,实现程序返回,同时将SPSR_abt寄存器内容复制到当前程序状态寄存器CPSR中;
当异常中断处理程序中使用了数据栈时,可以通过下面的指令在进入异常中断处理程序时保存被中断程序的执行现在,在退出异常中断处理程序时恢复被中断程序的执行现场。异常中断处理程序中使用的数据栈由用户提供。
返回的操作指令可以用下面的指令来实现:
MOV PC,LR 或者 SUBS PC,LR,#0x04或SUBS PC,LR,#0x08(三者选其一)
STMFD SP!,{reglist,LR}
……
LDMFD SP! ,{reglist,LR}^
在上述指令中reglist是异常中断处理程序中使用的寄存器列表。标识符^指示将SPSR_MODE寄存器内容复制到程序状态寄存器CPSR中。该指令只能在特权模式(管理模式SVC)下使用。
异常类型 |
处理器模式 |
优先级 |
低端向量表地址 |
高端向量表地址 |
复 位 |
SVC |
1 |
0x00000000 |
0xffff0000 |
未定义指令 |
UND |
6 |
0x00000004 |
0xffff0004 |
软件中断SWI |
SVC |
6 |
0x00000008 |
0xffff0008 |
预取指中止 |
PABT |
5 |
0x0000000c |
0xffff000c |
数据中止 |
DABT |
2 |
0x00000010 |
0xffff0010 |
保留 |
/ |
/ |
0x00000014 |
0xffff0014 |
IRQ中断 |
IRQ |
4 |
0x00000018 |
0xffff0018 |
FIQ中断 |
FIQ |
3 |
0x0000001c |
0xffff001c |
异常 |
返回地址 |
返回指令 |
返回地址处的指令 |
复位 |
- |
— |
复位没有定义LR |
未定义指令 |
LR |
MOVS PC, R14_und |
指向未定义指令的下一条指令 |
软件中断SWI |
LR |
MOVS PC, R14_svc |
指向SWI指令的下一条指令 |
预取指令中止 |
LR-4 |
SUBS PC, R14_abt, #4 |
指向导致预取指令异常的那条指令 |
数据中止 |
LR-8 |
SUBS PC, R14_abt, #8 |
指向导致数据中止异常的指令 |
IRQ |
LR-4 |
SUBS PC, R14_irq, #4 |
指向发生异常时正在执行的指令 |
FIQ |
LR-4 |
SUBS PC, R14_fiq, #4 |
指向发生异常时正在执行的指令 |