ARM中斷實(shí)現(xiàn)過(guò)程的個(gè)人筆記
——
接下來(lái)的學(xué)習(xí)過(guò)程中,比較難以理解的是ARM的中斷過(guò)程和存儲(chǔ)系統(tǒng)。ARM中斷的實(shí)現(xiàn)有些書(shū)上看一兩遍也不見(jiàn)得能夠完全理解,當(dāng)然可能只對(duì)于像我一樣跨專(zhuān)業(yè)的朋友來(lái)說(shuō)存在這個(gè)問(wèn)題。這次只談中斷。由于是初學(xué)者,難免會(huì)出錯(cuò),敬請(qǐng)各位指正。
當(dāng)一個(gè)程序正常執(zhí)行過(guò)程中,CPU可能檢測(cè)到有某個(gè)中斷源發(fā)出中斷請(qǐng)求,這時(shí)ARM硬件實(shí)現(xiàn)了程序強(qiáng)制跳轉(zhuǎn),在這之前保存了相關(guān)信息,以便程序正常返回。如果是發(fā)生了Reset中斷,程序?qū)崿F(xiàn)系統(tǒng)初始化設(shè)置。
開(kāi)始比較難以理解的是中斷產(chǎn)生后,程序都進(jìn)行了哪些操作。我就從跟蹤PC作為分析的主線。以發(fā)生FIQ中斷為例。(只以ROM起始地址為0為例,不為0的情況參照存儲(chǔ)地址映射)
最簡(jiǎn)單的是中斷發(fā)生后,PC=0x08,在此地址處存放一個(gè)跳轉(zhuǎn)指令,跳轉(zhuǎn)到相關(guān)處理程序。當(dāng)然多數(shù)情況中斷處理程序可能比較復(fù)雜,并且要處理多種中斷的情況下,采用一步映射兩步跳轉(zhuǎn)(我自己起的名字,不一定妥當(dāng))。如下圖所示:
一步映射指,在RAM地址中建立一個(gè)中斷向量表,圖中該表起始地址為0x400000,在該表中存放的是中斷處理函數(shù)的入口地址。兩步跳轉(zhuǎn)是指,當(dāng)中斷發(fā)生時(shí),由于系統(tǒng)硬件強(qiáng)制程序跳轉(zhuǎn)到了0x08處,在該地址處是一個(gè)跳轉(zhuǎn)指令,跳轉(zhuǎn)到中斷函數(shù)地址解析程序IRQ_Handler,完成一步跳轉(zhuǎn)。解析程序(IRQ_Handler)的作用無(wú)非是把中斷向量表內(nèi)中斷處理函數(shù)(SystemIrqHandler)的入口地址賦值給 PC,如圖所示PC=0x003000280,完成第二步跳轉(zhuǎn),開(kāi)始處理中斷。在中斷處理函數(shù)的最后,恢復(fù)中斷開(kāi)始時(shí)保存的相關(guān)寄存器的值,完成中斷。
下面以一個(gè)實(shí)例來(lái)具體說(shuō)明中斷建立及實(shí)現(xiàn)的過(guò)程。
首先通過(guò)偽指令建立一個(gè)中斷向量表,用于存放中斷程序的入口地址(如上圖中的中斷向量表,注意,此時(shí)表中還未賦值):
;/* EXCEPTION HANDLER VECTOR TABLE */
^ DRAM_BASE
HandleReset # 4
HandleUndef # 4
HandleSwi # 4
HandlePrefetch # 4
HandleAbort # 4
HandleReserv # 4
HandleIrq # 4
HandleFiq # 4
然后定義一個(gè)連續(xù)的數(shù)據(jù)段,并把中斷處理函數(shù)的入口地址值賦給各字單元
ExceptionHandlerTable
DCD UserCodeArea
DCD SystemUndefinedHandler
DCD SystemSwiHandler
DCD SystemPrefetchHandler
DCD SystemAbortHandler
DCD SystemReserv
DCD SystemIrqHandler
DCD SystemFiqHandler
下面從程序的開(kāi)始處分析:
AREA Init, CODE, READONLY
ENTRY
/* ROM起始地址向量表 */
B Reset_Handler
B Undefined_Handler
B SWI_Handler
B Prefetch_Handler
B Abort_Handler
NOP Reserved vector
B IRQ_Handler
B FIQ_Handler
/* B跳轉(zhuǎn)范圍限于+ -32M內(nèi)*/
/* 以下是地址解析程序 */
IRQ_Handler
SUB sp, sp, #4
STMFD sp!, {r0} FD滿(mǎn)遞減堆棧 執(zhí)行寄存器壓棧操作.
LDR r0, =HandleIrq //對(duì)應(yīng)程序開(kāi)始處以偽指令定義的向量表
LDR r0, [r0] //中斷處理函數(shù)的地址賦給R0.
STR r0, [sp, #4] //中斷處理函數(shù)的地址入棧
LDMFD sp!, {r0, pc} //實(shí)現(xiàn)程序跳轉(zhuǎn),目前沒(méi)明白為什么又給r0賦值?
上面提到了還沒(méi)有給中斷向量表賦值,下面代碼把中斷處理函數(shù)的地址放到DRAM中斷向量表里
EXCEPTION_VECTOR_TABLE_SETUP
LDR r0, =HandleReset
LDR r1, =ExceptionHandlerTable
MOV r2, #8
ExceptLoop
LDR r3, [r1], #4
STR r3, [r0], #4
SUBS r2, r2, #1 Down Count
BNE ExceptLoop ;;
下面是中斷處理函數(shù)
SystemIrqHandler
IMPORT ISR_IrqHandler
STMFD sp!, {r0-r7, lr}
BL ISR_IrqHandler
LDMFD sp!, {r0-r7, lr}
SUBS pc, lr, #4
它實(shí)際上只調(diào)用了下面的C語(yǔ)言的中斷處理函數(shù),其他什么也沒(méi)做。
void ISR_IrqHandler(void)
{
IntOffSet = (U32)INTOFFSET;
(IntOffSet>>2)
(*InterruptHandlers[IntOffSet>>2])(); // Call interrupt service routine
}
以上編程思路是,先在系統(tǒng)初始化時(shí)重新建立一個(gè)中斷向量表,并把相關(guān)的中斷處理函數(shù)的地址放到中斷向量表中。當(dāng)系統(tǒng)監(jiān)測(cè)到有中斷源請(qǐng)求服務(wù)后,硬件實(shí)現(xiàn)pc跳轉(zhuǎn)到地址0x08處,執(zhí)行一個(gè)跳轉(zhuǎn)指令B IRQ_Handler , 然后執(zhí)行地址解析程序,把中斷向量表中的中斷處理函數(shù)的入口地址賦給pc,開(kāi)始響應(yīng)中斷。在中斷處理函數(shù)的最后,執(zhí)行
LDMFD sp!, {r0-r7, lr}
SUBS pc, lr, #4
實(shí)現(xiàn)中斷的返回。
評(píng)論