ARM的異常處理過程分析
異常類型 | Mode | 異常向量 | 內(nèi)容 |
IRQ異常 | IRQ | 0x00000018 | LDR PC,[PC,#0x18]或者0xE59FF018 |
IFQ異常 | IFQ | 0x0000001C | LDR PC,[PC,#0x18] 0xE59FF018 |
0x00000038 | Address of OS_CPU_ARM_ExceptIrqHndlr() | ||
0x0000003C | Address of OS_CPU_ARM_ExceptFiqHndlr() |
有必要的討論一下,為什么在向量中存儲的是指令: LDR PC,[PC,#0x18],我們從上面的地址可以知道,IRQ異常處理函數(shù)地址被存儲到了0x00000038中,異常向量與該地址之間的差值是0x20,那么為什么在其中存儲的值只是0x18呢?這還要討論ARM的流水線結(jié)構(gòu),當前執(zhí)行的命令相比PC指向的地址差0x08。也就是當前執(zhí)行的指令的地址是PC-0x08.當PC指向異常向量以后(取值),還需要等待一個時鐘(譯碼)之后才會被執(zhí)行(真正意義上的執(zhí)行操作),而這時PC值已經(jīng)被更新了。指向了Vector+0x8的位置,因此我們可以知道,當執(zhí)行向量中的代碼時,這時PC=Vector+0x8,而這時相對于固定的0x20-0x08=0x18,這也就是為什么是LDR PC,[PC,#0x18],而不是LDR PC,[PC,#0x20].
采用上面的例子說明IRQ的向量為0x00000018,而設定好的固定地址用來存儲對應異常處理函數(shù)地址的地址是0x00000038,當CPU執(zhí)行完P(guān)C = 0x00000018以后,還需要譯碼、才能被執(zhí)行,這時候PC值已經(jīng)更新為PC = 0x00000018 + 0x08;這時候固定地址距離PC的相對位置位0x00000038 – PC = 0x18,而該地址中保存了IRQ中斷的通用處理函數(shù)OS_CPU_ARM_ExceptIrqHndlr()的地址,LDR PC,[PC,#0x18]這條指令是指將PC+0x18地址處的內(nèi)容加載到PC中,實質(zhì)上也就完成跳轉(zhuǎn)到異常處理函數(shù)的操作。
這樣處理的好處是因為LDR的加載范圍是一個固定值+-32M,我們不能保證異常處理程序的地址剛好在+-32M左右,采用這種LDR PC, ADDR(固定地址)的形式就能實現(xiàn)大范圍的跳轉(zhuǎn)操作。
我們僅僅以FIQ中斷處理的形式進行討論,其他的異常有一定的相似性,只是在返回地址上存在差別。這段代碼主要是完成寄存器的壓棧,返回地址的調(diào)整,保存等操作。具體的看下面的分析:
AREA CODE, CODE, READONLY
CODE32
OS_CPU_ARM_ExceptFiqHndlr
;修改中斷返回地址,這屬于進入真正處理函數(shù)前的返回地址調(diào)整,具體的返回地址依據(jù)前面保存的R14進行相應的修改。
SUB LR, LR, #4 ; LR offset to return from this exception: -4.
;壓棧操作
STMFD SP!, {R0-R12, LR} ; Push working registers.
;保存鏈接寄存器
MOV R2, LR ; Save link register.
;設置好ID號,這是非常必要的,只有這樣才能辨別屬于那種異常
MOV R0, #OS_CPU_ARM_EXCEPT_FIQ ; Set exception ID
/*跳轉(zhuǎn)到通用的異常處理函數(shù),傳遞的參數(shù)是異常ID號*/
BOS_CPU_ARM_ExceptHndlr ; Branch to global exception handler.
OS_CPU_ARM_ExceptHndlr(except_type)是一個通用的異常處理函數(shù),可以對除了IRQ以外的其他異常進行控制操作。在這個通用處理函數(shù)中又調(diào)用了下面的函數(shù)OS_CPU_ARM_ExceptHndlr_BreakExcept()或者OS_CPU_ARM_ExceptHndlr_BreakTask()。這兩個函數(shù)中又調(diào)用了通用處理函數(shù)OS_CPU_ExceptHndlr(),然后OS_CPU_ExceptHndlr()中調(diào)用具體的中斷處理操作。
一般的OS_CPU_ExceptHndlr()處理形式,可以認為是一個模板如下:
void OS_CPU_ExceptHndlr (INT32U except_type)
{
/* Determine behavior according to exception type (except_type) */
/* If an IRQ or FIQ,具體的可能要使用中斷向量等形式實現(xiàn)*/
while (there are interrupting devices) {
/* Clear interrupting device */
OS_CPU_SR_INT_En(); /* Enable nesting, if desired */
/* Handle interrupt */
}
}
這是其中的一段關(guān)于IRQ中斷的文字復述:
IRQ中斷的基本的流程圖如下:
以上的uC/OS-II異常處理就分析完了,這種方式的實現(xiàn)實質(zhì)上是采用了通用模板的形式,這樣實現(xiàn)出來的形式只需要控制一定的,具體的一些IRQ中斷處理函數(shù)(如定時器,GPIO等的中斷),與具體的廠商有很大的關(guān)系,有的廠商采用硬件寄存器的方式進行設計,有的采用軟件方式實現(xiàn),因此具體的中斷。
關(guān)鍵詞:
ARM異常處理過程分
評論