ARM微處理器的編程模型之:異常中斷處理
3.4.4 異常響應(yīng)流程
1.判斷處理器狀態(tài)
當(dāng)異常發(fā)生時,處理器自動切換到ARM狀態(tài),所以在異常處理函數(shù)中要判斷在異常發(fā)生前處理器是ARM狀態(tài)還是Thumb狀態(tài)。這可以通過檢測SPSR的T位來判斷。
通常情況下,只有在SWI處理函數(shù)中才需要知道異常發(fā)生前處理器的狀態(tài)。所以在Thumb狀態(tài)下,調(diào)用SWI軟中斷異常必須注意以下兩點(diǎn)。
① 發(fā)生異常的指令地址為(lr-2)而不是(lr-4)。
② Thumb狀態(tài)下的指令是16位的,在判斷中斷向量號時使用半字加載指令LDRH。
下面的例子顯示了一個標(biāo)準(zhǔn)的SWI處理函數(shù),在函數(shù)中通過SPSR的T位判斷異常發(fā)生前的處理器狀態(tài)。
T_bit EQU 0x20 ; bit 5. SPSR中的ARM/Thumb狀態(tài)位,
:
:
SWIHandler
STMFD sp!, {r0-r3,r12,lr} ; 寄存器壓棧,保護(hù)程序現(xiàn)場
MRS r0, spsr ; 讀SPSR寄存器,判斷異常發(fā)生前的處理器狀態(tài)
TST r0, #T_bit ; 檢測SPSR的T位,判斷異常發(fā)生前是否為Thumb狀態(tài)
LDRNEH r0,[lr,#-2] ; 如果是Thumb狀態(tài),使用半字加載指令讀取發(fā)生異常的指令地址
BICNE r0,r0,#0xFF00 ; .提取中斷向量號.
LDREQ r0,[lr,#-4] ; 如果是ARM狀態(tài),使用字加載指令,讀取發(fā)生異常的指令地址
BICEQ r0,r0,#0xFF000000 ; 提取中斷向量號并將中斷向量號存入r0
; r0 存儲中斷向量號
CMP r0, #MaxSWI ; 判斷中斷是否超出范圍
LDRLS pc, [pc, r0, LSL#2] ; 如果未超出范圍,跳轉(zhuǎn)到軟中斷向量表Switable
B SWIOutOfRange ; 如果超出范圍,跳轉(zhuǎn)到軟中斷越界處理程序
switable
DCD do_swi_1
DCD do_swi_2
:
:
do_swi_1
; 1號軟中斷處理函數(shù)
LDMFD sp!, {r0-r3,r12,pc}^ ; Restore the registers and return.
; 恢復(fù)寄存器并返回
do_swi_2 ; 2號軟中斷處理函數(shù)
:
2.向量表
如前面介紹向量表時提到的,每一個異常發(fā)生時總是從異常向量表開始跳轉(zhuǎn)。最簡單的一種情況是向量表里面的每一條指令直接跳向?qū)?yīng)的異常處理函數(shù)。其中快速中斷處理函數(shù)FIQ_handler()可以直接從地址0x1C處開始,省下一條跳轉(zhuǎn)指令,如圖3.6所示。
圖3.6 異常處理向量表
但跳轉(zhuǎn)指令B的跳轉(zhuǎn)范圍為±32MB,但很多情況下不能保證所有的異常處理函數(shù)都定位在向量的32MB范圍內(nèi),需要更大范圍的跳轉(zhuǎn),而且由于向量表空間的限制,只能由一條指令完成。具體實(shí)現(xiàn)方法有下面兩種。
(1)MOV PC,#imme_value
這種辦法將目標(biāo)地址直接賦值給PC。但這種方法受格式限制不能處理任意立即數(shù)。這個立即數(shù)由一個8位數(shù)值循環(huán)右移偶數(shù)位得到。
(2)LDR PC,[PC+offset]
把目標(biāo)地址先存儲在某一個合適的地址空間,然后把這個存儲器單元的32位數(shù)據(jù)傳送給PC來實(shí)現(xiàn)跳轉(zhuǎn)。
這種方法對目標(biāo)地址值沒有要求。但是存儲目標(biāo)地址的存儲器單元必須在當(dāng)前指令的±4KB空間范圍內(nèi)。
注意 | 在計(jì)算指令中引用offset數(shù)值的時候,要考慮處理器流水線中指令預(yù)取對PC值的影響。 |
評論