ARM微处理器的编程模型之:异常中断处理
3.4.4 异常响应流程
1.判断处理器状态
当异常发生时,处理器自动切换到ARM状态,所以在异常处理函数中要判断在异常发生前处理器是ARM状态还是Thumb状态。这可以通过检测SPSR的T位来判断。
通常情况下,只有在SWI处理函数中才需要知道异常发生前处理器的状态。所以在Thumb状态下,调用SWI软中断异常必须注意以下两点。
① 发生异常的指令地址为(lr-2)而不是(lr-4)。
② Thumb状态下的指令是16位的,在判断中断向量号时使用半字加载指令LDRH。
下面的例子显示了一个标准的SWI处理函数,在函数中通过SPSR的T位判断异常发生前的处理器状态。
T_bit EQU 0x20 ; bit 5. SPSR中的ARM/Thumb状态位,
:
:
SWIHandler
STMFD sp!, {r0-r3,r12,lr} ; 寄存器压栈,保护程序现场
MRS r0, spsr ; 读SPSR寄存器,判断异常发生前的处理器状态
TST r0, #T_bit ; 检测SPSR的T位,判断异常发生前是否为Thumb状态
LDRNEH r0,[lr,#-2] ; 如果是Thumb状态,使用半字加载指令读取发生异常的指令地址
BICNE r0,r0,#0xFF00 ; .提取中断向量号.
LDREQ r0,[lr,#-4] ; 如果是ARM状态,使用字加载指令,读取发生异常的指令地址
BICEQ r0,r0,#0xFF000000 ; 提取中断向量号并将中断向量号存入r0
; r0 存储中断向量号
CMP r0, #MaxSWI ; 判断中断是否超出范围
LDRLS pc, [pc, r0, LSL#2] ; 如果未超出范围,跳转到软中断向量表Switable
B SWIOutOfRange ; 如果超出范围,跳转到软中断越界处理程序
switable
DCD do_swi_1
DCD do_swi_2
:
:
do_swi_1
; 1号软中断处理函数
LDMFD sp!, {r0-r3,r12,pc}^ ; Restore the registers and return.
; 恢复寄存器并返回
do_swi_2 ; 2号软中断处理函数
:
2.向量表
如前面介绍向量表时提到的,每一个异常发生时总是从异常向量表开始跳转。最简单的一种情况是向量表里面的每一条指令直接跳向对应的异常处理函数。其中快速中断处理函数FIQ_handler()可以直接从地址0x1C处开始,省下一条跳转指令,如图3.6所示。
图3.6 异常处理向量表
但跳转指令B的跳转范围为±32MB,但很多情况下不能保证所有的异常处理函数都定位在向量的32MB范围内,需要更大范围的跳转,而且由于向量表空间的限制,只能由一条指令完成。具体实现方法有下面两种。
(1)MOV PC,#imme_value
这种办法将目标地址直接赋值给PC。但这种方法受格式限制不能处理任意立即数。这个立即数由一个8位数值循环右移偶数位得到。
(2)LDR PC,[PC+offset]
把目标地址先存储在某一个合适的地址空间,然后把这个存储器单元的32位数据传送给PC来实现跳转。
这种方法对目标地址值没有要求。但是存储目标地址的存储器单元必须在当前指令的±4KB空间范围内。
注意 | 在计算指令中引用offset数值的时候,要考虑处理器流水线中指令预取对PC值的影响。 |
评论