ARM微處理器的編程模型之:異常中斷處理
2.ARM編譯器對中斷處理函數(shù)編寫的擴展
考慮到中斷處理函數(shù)在現(xiàn)場保護和返回地址的處理上與普通函數(shù)的不同之處,不能直接把普通函數(shù)體連接到異常向量表上,需要在上面加上一層封裝,下面是一個例子。
IRQ_Handler ;中斷相應(yīng)函數(shù)
STMFD SP!,{r0-r12,lr} ;保護現(xiàn)場,一般只需要保護{r0-r3,LR}
BL IrqHandler ;進入普通處理函數(shù),C或匯編均可
……
LDMFD sp!,{r0-r12,LR} ;恢復(fù)現(xiàn)場
SUBS pc,lr,#4 ;中斷返回,注意返回地址
為了方便使用高級語言直接編寫異常處理函數(shù),ARM編譯器對此做了特定的擴展,可以使用函數(shù)聲明關(guān)鍵字_irq,這樣編譯出來的函數(shù)就可以滿足異常響應(yīng)對現(xiàn)場保護和恢復(fù)的需要,并且自動加入LR減4的處理,符合IQR和FIQ中斷處理的要求。
下面的例子顯示了使用_irq對中斷處理函數(shù)產(chǎn)生的影響。
C語言源程序如下。
__irq void IRQHandler (void)
{
volatile unsigned int *base = (unsigned int *) 0x80000000;
if (*base == 1)
{
/*調(diào)用C語言中斷處理函數(shù)*/
C_int_handler();
}
/*清楚中斷標(biāo)志*/
*(base+1) = 0;
}
使用armcc編譯出的匯編代碼如下。
IRQHandler PROC
STMFD sp!,{r0-r4,r12,lr}
MOV r4,#0x80000000
LDR r0,[r4,#0]
SUB sp,sp,#4
CMP r0,#1
BLEQ C_int_handler
MOV r0,#0
STR r0,[r4,#4]
ADD sp,sp,#4
LDMFD sp!,{r0-r4,r12,lr}
SUBS pc,lr,#4
ENDP
如果不使用_irq子程序聲明關(guān)鍵字,編譯出的匯編代碼如下。
IRQHandler PROC
STMFD sp!,{r4,lr}
MOV r4,#0x80000000
LDR r0,[r4,#0]
CMP r0,#1
BLEQ C_int_handler
MOV r0,#0
STR r0,[r4,#4]
LDMFD sp!,{r4,pc}
ENDP
3.可重入中斷設(shè)計
在缺省情況下,ARM中斷是不可重入的。因為一旦進入異常響應(yīng)狀態(tài),ARM自動關(guān)閉中斷使能。如果在異常處理過程中,簡單地打開中斷使能而發(fā)生中斷嵌套時,顯然新的異常處理將破壞原來的中斷現(xiàn)場而導(dǎo)致出錯。但有時需要中斷必須是可重入的,因此要通過程序設(shè)計來解決這個問題。其中有兩個關(guān)鍵問題。
① 新中斷使能之前,必須要保護好前一個中斷的現(xiàn)場信息。比如LR_irq和SPSR_irq等,這一點比較容易做的。
② 中斷處理過程中對BL進行保護。
在中斷處理函數(shù)中發(fā)生函數(shù)調(diào)用BL是很常見的,假設(shè)有下面一種情況。
IRQ_Handler:
……
BL Foo
ADD
其中,
Foo:
STMFD SP!,{r0-r3,LR}
……
LDMFD SP!{r0-r3,PC}
上述程序,在IRQ處理函數(shù)IRQ_Handler()中調(diào)用了函數(shù)Foo()。若是在IRQ_Handler()里面中斷可重入的話,可能發(fā)生問題,考察下面的情況:當(dāng)新的中斷請求恰好在“BL Foo”指令執(zhí)行完成后發(fā)生。這時候LR_irq寄存器(因在IRQ模式下,所以是LR_irq)的值將調(diào)整為BL指令的下一條指令(ADD)地址,使其能從Foo()正確返回;但是因為這時候發(fā)生了中斷請求,接下來要進行新中斷的響應(yīng),處理器在新中斷響應(yīng)過程中也要進行LR_irq保存。這次對LR_irq的操作發(fā)生了沖突,當(dāng)新中斷返回后,往下執(zhí)行STMFD指令,這時候壓棧的LR已不是原來的ADD指令地址,從而使子程序Foo()無法正確返回。
這個問題無法通過增加額外的現(xiàn)場保護指令來解決。一個辦法就是在重新使能中斷之前改變處理器模式,也就是使上面程序的“BL Foo”指令不要運行在IRQ模式下。這樣當(dāng)新的中斷發(fā)生時,就不會造成LR寄存器的沖突??紤]ARM的所有運行模式,采用SYSTEM模式是比較合適的,因為它是特權(quán)模式,不是IRQ模式,與中斷響應(yīng)無關(guān)。
下面的例子顯示了標(biāo)準(zhǔn)的IRQ/FIQ異常中斷處理程序。
PRESERVE8
AREA INTERRUPT, CODE, READONLY
IMPORT C_irq_handler
IRQ
SUB lr, lr, #4 ;跳轉(zhuǎn)返回地址
STMFD sp!, {lr} ;保存返回地址
MRS r14, SPSR ;讀取SPSR
STMFD sp!, {r12, r14} ;保存寄存器
; 清除中斷源
MSR CPSR_c, #0x1F ;切換到SYSTEM模式,
STMFD sp!, {r0-r3, lr} ;保存lr_USR 和其他使用到的寄存器
BL C_irq_handler ;跳轉(zhuǎn)到C中斷處理函數(shù)
LDMFD sp!, {r0-r3, lr} ;恢復(fù)用戶模式寄存器
MSR CPSR_c, #0x92 ;切換回irq模式
LDMFD sp!, {r12, r14}
MSR SPSR_cf, r14
LDMFD sp!, {pc}^
END
評論