1. 首先就是知道ARM狀態(tài)下37個(gè)寄存器包括通用寄存器、程序計數器、狀態(tài)寄存器。綠顏色的就是相應模式下的私有寄存器。就是說(shuō)程序一般運行在系統和用戶(hù)模式下,使用的是系統和用戶(hù)模式下的通用寄存器,當有異常發(fā)生時(shí),比如FIQ,那么系統將切換到FIQ模式下,相應的就會(huì )采用FIQ模式下的寄存器,其中綠顏色的就是只在FIQ模式下才會(huì )用到的寄存器。
2. 在模式切換的過(guò)程中,要保護系統和用戶(hù)模式下的通用寄存器狀態(tài),以便在異常處理完成之后程序能正常返回。因為FIQ模式下R8-R14為其私有寄存器,所以切換到FIQ模式的過(guò)程中,系統和用戶(hù)模式下的通用寄存器的R8-R14就不用保護了,所以減少了對寄存器存取的需要,從而可以快速的進(jìn)行FIQ處理,故稱(chēng)為FIQ。這就是FIQ的私有寄存器比其它模式多的原因。切到FIQ模式需要保護的寄存器為R0~R7,切到SVC,IRQ,ABORT.和未定義模式需要保護的寄存器為R0~R12

3. 異常處理的動(dòng)作。當然這都是CPU內核自己干的。以FIQ為例。
當CPU切入FIQ模式時(shí),
第一,將原來(lái)執行程序的下一條指令地址保存到LR中,就是將R14保存到R14_fiq里面。
第二,拷貝CPSR到SPSR_fiq。
第三,改變CPSR模式位的值,改到FIQ模式。
第四,改變PC值,將其指向異常處理向量所指的下一條指令。
離開(kāi)異常處理的時(shí)候,
第一,將LR(R14_fiq)賦給PC。
第二,將SPSR(SPSR_fiq)拷貝到CPSR。
第三,清除中斷禁止標志(如果開(kāi)始時(shí)置位了)。
4.異常中斷向量
異常中斷的向量地址
地址 異常中斷類(lèi)型 入口時(shí)處理器的操作模式
0x00000000 復位 超級用戶(hù)
0x00000004 未定義指令 未定義
0x00000008 軟件中斷 超級用戶(hù)
0x0000000c 中止(預取指) 中止
0x00000010 中止(數據) 中止
0x00000014 保留 保留
0x00000018 IRQ IRQ
0x0000001c FIQ FIQ
異常中斷優(yōu)先級
中斷 優(yōu)先級
復位 最高
數據異常
FIQ
IRQ
預取指異常中斷
未定義指令和軟件中斷 最低
5.當發(fā)生IRQ中斷時(shí)
第一,模式進(jìn)入到IRQ里面。
第二,PC跳到0x00000018處運行。因為這是IRQ的中斷入口。
第三, 通過(guò)0x00000018:LDR PC, IRQ_ADDR。跳轉到相應的中斷服務(wù)程序。這個(gè)里面就有個(gè)確定哪個(gè)中斷源的問(wèn)題了。那就有優(yōu)先級的問(wèn)題了。每個(gè)中斷源會(huì )有自己的中斷服務(wù)程序。
第四,得到中斷源有硬件實(shí)現和軟件處理兩種方式。比如LPC21XX的就是利用硬件方式,為了利用向量中斷控制器的優(yōu)點(diǎn),IRQ中斷向量入口處代碼做了修改,變成
0x00000018:LDR PC, [PC, #-0xff0]。
這條指令從內存映射地址0xfffff030處獲得數據裝載到PC,這樣就能夠直接從硬件中獲得中斷源。這樣就減少了中斷延遲。記得,三星的S3C44B0好象采用的是用軟件確定中斷源,因此要建立中斷向量表。好久不用了,記不清了。
第五,得到中斷源,就知道要跳到哪個(gè)中斷服務(wù)程序去了。
一般都是這么定義的。Timer0_Handler HANDLER Timer0 。這種格式是調用一種宏定義,目的是保護現場(chǎng),跳到中斷服務(wù)程序。
ARM中斷實(shí)現過(guò)程的個(gè)人筆記
作者: 逛逛 發(fā)布日期:2006-3-19
歡迎大家加入我的小圈子共同學(xué)習討論:www.uuzone.com/club/embbed/
決定開(kāi)始學(xué)習嵌入式后,最先做的事情就是要熟悉ARM指令及其偽指令偽操作。ARM指令的助記符其實(shí)都是其具體功能的單次縮寫(xiě),所以學(xué)習的過(guò)程中最好利用網(wǎng)絡(luò ),從一些文獻或書(shū)籍中找到ARM指令助記符的全稱(chēng),這樣方便記憶。學(xué)完之后,我做了整理了一個(gè)有關(guān)這方面的筆記,有需要的朋友請郵件聯(lián)系:gmman@163.com
接下來(lái)的學(xué)習過(guò)程中,比較難以理解的是ARM的中斷過(guò)程和存儲系統。ARM中斷的實(shí)現有些書(shū)上看一兩遍也不見(jiàn)得能夠完全理解,當然可能只對于像我一樣跨專(zhuān)業(yè)的朋友來(lái)說(shuō)存在這個(gè)問(wèn)題。這次只談中斷。由于是初學(xué)者,難免會(huì )出錯,敬請各位指正。
當一個(gè)程序正常執行過(guò)程中,CPU可能檢測到有某個(gè)中斷源發(fā)出中斷請求,這時(shí)ARM硬件實(shí)現了程序強制跳轉,在這之前保存了相關(guān)信息,以便程序正常返回。如果是發(fā)生了Reset中斷,程序實(shí)現系統初始化設置。
開(kāi)始比較難以理解的是中斷產(chǎn)生后,程序都進(jìn)行了哪些操作。我就從跟蹤PC作為分析的主線(xiàn)。以發(fā)生FIQ中斷為例。(只以ROM起始地址為0為例,不為0的情況參照存儲地址映射)
最簡(jiǎn)單的是中斷發(fā)生后,PC=0x08,在此地址處存放一個(gè)跳轉指令,跳轉到相關(guān)處理程序。當然多數情況中斷處理程序可能比較復雜,并且要處理多種中斷的情況下,采用一步映射兩步跳轉(我自己起的名字,不一定妥當)。如下圖所示:
一步映射指,在RAM地址中建立一個(gè)中斷向量表,圖中該表起始地址為0x400000,在該表中存放的是中斷處理函數的入口地址。兩步跳轉是指,當中斷發(fā)生時(shí),由于系統硬件強制程序跳轉到了0x08處,在該地址處是一個(gè)跳轉指令,跳轉到中斷函數地址解析程序IRQ_Handler,完成一步跳轉。解析程序(IRQ_Handler)的作用無(wú)非是把中斷向量表內中斷處理函數(SystemIrqHandler)的入口地址賦值給 PC,如圖所示PC=0x003000280,完成第二步跳轉,開(kāi)始處理中斷。在中斷處理函數的最后,恢復中斷開(kāi)始時(shí)保存的相關(guān)寄存器的值,完成中斷。
下面以一個(gè)實(shí)例來(lái)具體說(shuō)明中斷建立及實(shí)現的過(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è)連續的數據段,并把中斷處理函數的入口地址值賦給各字單元
ExceptionHandlerTable
DCD UserCodeArea
DCD SystemUndefinedHandler
DCD SystemSwiHandler
DCD SystemPrefetchHandler
DCD SystemAbortHandler
DCD SystemReserv
DCD SystemIrqHandler
DCD SystemFiqHandler
下面從程序的開(kāi)始處分析:
AREA Init, CO
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跳轉范圍限于+ -32M內*/
/* 以下是地址解析程序 */
IRQ_Handler
SUB sp, sp, #4
STMFD sp!, {r0} FD滿(mǎn)遞減堆棧 執行寄存器壓棧操作.
LDR r0, =HandleIrq //對應程序開(kāi)始處以偽指令定義的向量表
LDR r0, [r0] //中斷處理函數的地址賦給R0.
STR r0, [sp, #4] //中斷處理函數的地址入棧
LDMFD sp!, {r0, pc} //實(shí)現程序跳轉,目前沒(méi)明白為什么又給r0賦值?
上面提到了還沒(méi)有給中斷向量表賦值,下面代碼把中斷處理函數的地址放到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 ;;
下面是中斷處理函數
SystemIrqHandler
IMP
STMFD sp!, {r0-r7, lr}
BL ISR_IrqHandler
LDMFD sp!, {r0-r7, lr}
SUBS pc, lr, #4
它實(shí)際上只調用了下面的C語(yǔ)言的中斷處理函數,其他什么也沒(méi)做。
void ISR_IrqHandler(void)
{
IntOffSet = (U32)INTOFFSET;
(IntOffSet>>2)
(*InterruptHandlers[IntOffSet>>2])(); // Call interrupt service routine
}
以上編程思路是,先在系統初始化時(shí)重新建立一個(gè)中斷向量表,并把相關(guān)的中斷處理函數的地址放到中斷向量表中。當系統監測到有中斷源請求服務(wù)后,硬件實(shí)現pc跳轉到地址0x08處,執行一個(gè)跳轉指令B IRQ_Handler , 然后執行地址解析程序,把中斷向量表中的中斷處理函數的入口地址賦給pc,開(kāi)始響應中斷。在中斷處理函數的最后,執行
LDMFD sp!, {r0-r7, lr}
SUBS pc, lr, #4
實(shí)現中斷的返回
硬件平臺為ARM7內核。當有軟中斷發(fā)生(即調用2.2中某一個(gè)函數時(shí))時(shí),系統首先自動(dòng)調轉到0x0008處執行。
1、第一級中斷向量
AREA Init,CO
ENTRY
b ResetHandler ;for debug
b HandlerUndef ;handlerUndef
b HandlerSWI ;SWI interrupt handler
b HandlerPabort ;handlerPAbort
b HandlerDabort ;handlerDAbort
b . ;handlerReserved
b HandlerIRQ
b HandlerFIQ
2、宏展開(kāi)
繼續找HandlerSWI。
HandlerSWI HANDLER HandleSWI
3、內存第二級中斷向量
再找HandleSWI。
^ _ISR_STARTADDRESS
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
現在我們知道軟中斷的服務(wù)程序跑到了內存中(執行速度較快)去了,我們可以編寫(xiě)相應的代碼來(lái)實(shí)現不同功能號下的不同功能。
對于學(xué)習ARM的朋友來(lái)說(shuō),中斷處理是一塊硬骨頭,尤其是中斷向量表以及中斷的跳轉。下面主要對中斷向量表的建立問(wèn)題及重映射問(wèn)題進(jìn)行探討。近來(lái)做一些東西用到中斷時(shí),總會(huì )出現一些問(wèn)題。
各種Bootloader的初始化相關(guān)代碼摘要,首先來(lái)看下面的程序:
^ DRAM_BASE //DRAM的基地址
HandleReset # 4 // 空留4個(gè)單元
HandleUndef # 4
HandleSwi # 4
HandlePrefetch # 4 //用于填充地址的
HandleAbort # 4
HandleReserv # 4
HandleIrq # 4
HandleFiq # 4
注: 這里的^是RMAP,#是FIELD,分配的意思
就是在SDARM的BANK0開(kāi)始的地方定義了一個(gè)中斷向量表,相當于0地址的FLASH??樟魡卧糜诖娣胖袛喑绦虻娜肟诘刂?。
ExceptionHandlerTable //實(shí)際的映射地址
DCD UserCodeArea
DCD SystemUndefinedHandler
DCD SystemSwiHandler
DCD SystemPrefetchHandler
DCD SystemAbortHandler
DCD SystemReserv
DCD SystemIrqHandler
DCD SystemFiqHandler
這個(gè)表中存放的是匯編程序中中斷處理函數的入口地址,每一項對應一個(gè)中斷函數。這次的跳轉后就進(jìn)入了C服務(wù)程序。
從初始化程序的開(kāi)始處來(lái)看:(各種Bootloader的初始化代碼)
AREA Init, CO
ENTRY //入口
B Reset_Handler
B Undefined_Handler //無(wú)條件的跳轉
B SWI_Handler
B Prefetch_Handler
B Abort_Handler
NOP Reserved vector
B IRQ_Handler
B FIQ_Handler
FIQ_Handler
SUB sp, sp, #4
STMFD sp!, {r0} FD滿(mǎn)遞減堆棧 執行寄存器壓棧操作.
LDR r0, =HandleFiq 匯編里的處理函數地址,然后跳到C中,在DRAM。
LDR r0, [r0] 中斷向量地址給R0.
STR r0, [sp, #4] 中斷向量地址給PC
LDMFD sp!, {r0, pc}
稍微解釋一下:
首先執行了壓棧,然后給出了中斷入口地址.這個(gè)HandleFiq就是我們前面的在DRAM中建立的中斷向量其中一個(gè)的地址。
在HandleFiq開(kāi)始的四個(gè)字節中,放著(zhù)匯編中斷處理函數的入口地址。
那么匯編中斷處理函數的地址是如何放到DRAM中斷向量表里的呢?
上面的第一個(gè)表就起作用了??聪旅孢@段程序:
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 //填充8個(gè)地址
BNE ExceptLoop //從表里取出來(lái)給了HandleReset后面的空間
這一段把ExceptionHandlerTable里的中斷處理函數的地址拷給了SDRAM里的中斷向量表。這樣兩者就聯(lián)系起來(lái)了。
在執行程序開(kāi)始的跳轉之后就自然跳到了*****Handler.真正的處理函數如下:
它實(shí)際上只調用了C語(yǔ)言的中斷處理函數,其他什么也沒(méi)做。
SystemFiqHandler
IMP
STMFD sp!, {r0-r7, lr}
BL ISR_FiqHandler //真正的中斷處理服務(wù)函數
LDMFD sp!, {r0-r7, lr}
SUBS pc, lr, #4
它實(shí)際上只調用了C語(yǔ)言的中斷處理函數,其他什么也沒(méi)做。寫(xiě)中斷處理服務(wù)程序其實(shí)就只寫(xiě)C中相應的處理部分就好了。
void ISR_FiqHandler(void)
{
IntOffSet = (U32)INTOFFSET;
(IntOffSet>>2)
(*InterruptHandlers[IntOffSet>>2])(); // Call interrupt service routine
}
其實(shí)就是將中斷向量表重映射,以提高中斷的響應速度。代碼在SDRAM的運行速度要比在FLASH中運行速度快。
聯(lián)系客服