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