新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM1176JZF-S/S3C6410處理器的異常處理過程

        ARM1176JZF-S/S3C6410處理器的異常處理過程

        作者: 時間:2016-11-09 來源:網絡 收藏
        本來準備總結一下ARM1176JZF-S/S3C6410處理器異常處理過程,但是發現《嵌入式系統Linux內核開發實戰指南》一書中的這一部分講解得非常簡明和清楚。所以就不再重復發明輪子,不過我會在以下的引用中做一些補充。

        進入異常中斷處理

        本文引用地址:http://www.104case.com/article/201611/317944.htm

        ARM處理器發生異常中斷,則ARM處理器進入如下異常中斷自動處理過程(假設發生的異常中斷對應的模式為mode):

        1. 將當前程序狀態寄存器CPSR的值保存到SPSR_mode中;
        2. 將CPSR中的模式位設置成mode模式,將CPSR中的bit7(I)設置為1,禁止IRQ中斷,如果是FIQ中斷,則再將CPSR中的bit6(F)設置為1,禁止FIQ中斷;
        3. 將返回地址傳給lr_mode;
        4. 將該異常中斷的向量地址傳給程序計數器pc,從而進入異常中斷處理程序。

        退出異常中斷處理

        當要從異常中斷處理程序中返回時,要做以下兩步操作(假設發生的異常中斷對應的模式為mode):

        1. 將保存在SPSR_mode中的值恢復到當前程序狀態寄存器CPSR中;
        2. 返回到發生異常中斷的指令的下一條指令處執行,也就是將lr_mode寄存器的值適當地返回到程序計數器pc中。

        但程序員只需做好上述第二步即可,第一步在完成第二步的同時由處理器自動完成,所以我們下面講解從各種異常中斷處理返回的編程接口。

        退出復位異常中斷處理(Reset)

        復位異常中斷處理程序不需要返回,所以不需要這個接口。

        退出未定義指令異常中斷處理(Undefined Instruction)

        未定義指令異常中斷由當前執行的指令自身產生,當未定義指令異常中斷產生時,程序計數器pc的值還未更新,它指向當前指令后面第2條指令(對于ARM指令,它指向當前指令地址加8字節的位置;對于Thumb指令,它指向當前指令地址加4字節的位置),當未定義指令異常中斷發生時,處理器將值(pc-4)保存到lr_und中,此時(pc-4)指向當前指令的下一條指令,所以從未定義指令異常中斷返回可以通過如下指令來實現:

        mov pc, lr

        該指令將寄存器lr_mode中的值到程序計數器pc中,實現程序返回,同時將SPSR_mode寄存器中的值到當前程序狀態寄存器CPSR中。

        如果要在異常中斷處理中使用數據棧,那么可以在進入異常中斷處理程序時保存被中斷程序的執行現場,在退出異常中斷處理程序時恢復被中斷程序的執行現場,編程如下:

        stmfd sp!, {register_list, lr} ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^ ;恢復被中斷程序的執行現場

        上面的register_list,是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_mode寄存器中的值到當前程序狀態寄存器CPSR中。

        退出軟中斷指令(SWI)異常中斷處理(Undefined Instruction)

        SWI異常中斷和未定義異常中斷指令一樣,也是由當前執行的指令自身產生,當SWI指令執行時,pc的值還未更新,它指向當前指令后面第2條指令(對于ARM指令,它指向當前指令地址加8字節的位置;對于Thumb指令,它指向當前指令地址加4字節的位置),當未定義指令異常中斷發生時,處理器將值(pc-4)保存到lr_svc中,此時(pc-4)指向當前指令的下一條指令,所以從SWI異常中斷處理返回的實現方法與從未定義指令異常中斷處理返回一樣:

        mov pc, lr

        使用數據棧的方法與未定義指令異常中斷處理中的方法也一樣:

        stmfd sp!, {register_list, lr} ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^ ;恢復被中斷程序的執行現場

        退出指令預取中止異常中斷處理(Prefetch Abort)

        在指令預取時,如果目標地址是非法的,該指令被標記成有問題的指令,這時,流水線上該指令之前的指令繼續執行,當執行到該被標記成有問題的指令時,處理器產生指令預取中止異常中斷。發生指令預取異常中斷時,程序要返回到該有問題的指令處,重新讀取并執行該指令,因此指令預取中止異常中斷應該返回到產生該指令預取中止異常中斷的指令處,而不是當前指令的下一條指令。

        指令預取中止異常中斷由當前執行的指令自身產生,當指令預取中止異常中斷發生時,程序計數器pc的值還未更新,它指向當前指令后面第2條指令(對于ARM指令,它指向當前指令地址加8字節的位置;對于Thumb指令,它指向當前指令地址加4字節的位置)。此時處理器將值(pc-4)保存到lr_abt中,它指向當前指令的下一條指令,所以返回操作可以通過下面指令實現:

        subs pc, lr, #4

        該指令將lr中的值減4后傳給程序計數器pc中,實現程序返回,同時將SPSR_abt寄存器的內容到當前程序狀態寄存器CPSR中。

        如果要在指令預取中止異常中斷處理中使用數據棧,可以用以下方法保護、恢復被中斷程序的執行現場:

        subs lr, lr, #4
        stmfd sp!, {register_list, lr} ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^ ;恢復被中斷程序的執行現場

        上面的register_list是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_abt寄存器中的值到當前程序狀態寄存器CPSR中。

        退出數據訪問中止異常中斷處理(Data Abort)

        發生數據訪問異常中斷時,程序要返回到該有問題的指令處,重新訪問該數據,因此數據訪問異常中斷應該返回到產生該數據訪問中止異常中斷的指令處,而不是當前指令的下一條指令。

        數據訪問異常中斷由當前執行的指令自身產生,當數據訪問異常中斷發生時,程序計數器pc的值已經更新,它指向當前指令后面第3條指令(對于ARM指令,它指向當前指令地址加12字節的位置;對于Thumb指令,它指向當前指令地址加6字節的位置)。此時處理器將值(pc-4)保存到lr_abt中,它指向當前指令后面第2條指令,所以返回操作可以通過下面指令實現:

        subs pc, lr, #8

        該指令將lr中的值減8后傳給程序計數器pc中,實現程序返回,同時將SPSR_abt寄存器內容到當前程序狀態寄存器CPSR中;

        如果要在數據訪問異常中斷處理中使用數據棧,可以用以下方法保護、恢復被中斷程序的執行現場:

        subs lr, lr, #8
        stmfd sp!, {register_list, lr} ;保存被中斷程序的執行現場;
        ; . . .
        ldmfd sp!, {register_list, pc}^ ;恢復被中斷程序的執行現場;

        上面的register_list是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_abt寄存器中的值到當前程序狀態寄存器CPSR中。

        退出IRQ異常中斷處理程序(IRQ)

        通常處理器執行完當前指令后,查詢IRQ中斷引腳,并查看是否允許IRQ中斷,如果某個中斷引腳有效,并且系統允許該中斷產生,處理器將產生IRQ異常中斷,當IRQ異常中斷產生時,程序計數器pc的值已經更新,它指向當前指令后面第3條指令(對于ARM指令,它指向當前指令地址加12字節的位置;對于Thumb指令,它指向當前指令地址加6字節的位置),當IRQ異常中斷產生時,處理器將值(pc-4)保存到IRQ異常模式下的寄存器lr_irq中,它指向當前指令之后的第2條指令,因此返回操作可以通過下面指令實現:

        subs pc, lr, #4

        該指令將lr中的值減4后傳給程序計數器pc中,實現程序返回,同時將SPSR_irq寄存器的內容到當前程序狀態寄存器CPSR中。

        如果要在IRQ異常中斷處理中使用數據棧,可以用以下方法保護、恢復被中斷程序的執行現場:

        subs lr, lr, #4
        stmfd sp!, {register_list, lr} ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^ ;恢復被中斷程序的執行現場

        上面的register_list是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_irq寄存器中的值到當前程序狀態寄存器CPSR中。

        退出FIQ異常中斷處理程序(FIQ)

        與IRQ異常中斷一樣,處理器執行完當前指令后,查詢FIQ中斷引腳,并查看是否允許FIQ中斷,如果中斷引腳有效,并且系統允許該中斷產生,處理器將產生FIQ異常中斷,當FIQ異常中斷產生時,程序計數器pc的值已經更新,它指向當前指令后面第3條指令(對于ARM指令,它指向當前指令地址加12字節的位置;對于Thumb指令,它指向當前指令地址加6字節的位置),當FIQ異常中斷產生時,處理器將值(pc-4)保存到IRQ異常模式下的寄存器lr_fiq中,它指向當前指令之后的第2條指令,因此返回操作可以通過下面指令實現:

        subs pc, lr, #4

        該指令將lr中的值減4后傳給程序計數器pc中,實現程序返回,同時將SPSR_fiq寄存器的內容到當前程序狀態寄存器CPSR中。

        如果要在FIQ異常中斷處理中使用數據棧,可以用以下方法保護、恢復被中斷程序的執行現場:

        subs lr, lr, #4
        stmfd sp!, {register_list, lr} ;保存被中斷程序的執行現場
        ; . . .
        ldmfd sp!, {register_list, pc}^ ;恢復被中斷程序的執行現場

        上面的register_list是異常中斷處理程序中使用的寄存器列表,標識符^表示要將SPSR_fiq寄存器中的值到當前程序狀態寄存器CPSR中。

        補充:關于程序返回地址(PC)的取值

        上文中提到,在進入異常處理之后,CPU會自動根據pc的值來設置lr的值(一般是減4),而對于不同各類的異常來說,這個值還不能直接用做異常的返回地址,可能還需要再減4或減8等等,這樣做的原因是什么呢?

        答案在于ARM處理器在處理指令時所使用的三級流水線機制。

        CPU執行一條指令的過程可以分為三個步驟:取指令、翻譯和執行。執行每一個步驟都需要一個指令周期的時間,所以完整地執行完一條指令實際上就需要3個周期。為了加快程序的運行,現代CPU都會采用多級流程線的技術。以三級流水線為例,一條專門負責取指,一條專門翻譯,還有一條負責執行,三條流水線并行工作,每一條流水線在每一個周期內都不會空閑,所以平均來看,執行每條指令都只要一個周期的時間。

        從二進制指令的角度來看,當前指令在執行的時候,下一條指令已經在被翻譯,再下一條指令已經正在被讀取。注意pc寄存器總是指向正在被讀取的那條指令,而不是正在被執行的指令。如下圖所示:

        箭頭方向是指令運行的方向,左側是低地址,右側是高地址,當A指令是正在運行的指令,pc寄存器現在正指向C指令的位置。

        下面,分別以軟中斷異常和數據異常為例來解釋一下上文中所講的內容:

        在軟中斷發生時,指令流水線的結構與上圖完全一樣。軟中斷是由正在執行的指令A觸發的,它的任務已經完成,所以在中斷處理結束之后,A指令不需要再被執行一次,應該直接執行B指令。而在進入中斷處理程序之前,CPU已經自動將(pc-4)的值存入lr,這正是B指定的位置。所以在中斷返回時,直接把lr的值賦給pc就行了。

        在數據訪問異常發生時,指令流水線的結構與上圖不太一樣,正在執行的指令仍然是A,pc已經更新,即指向了D指令。在中斷處理結束時,數據的問題已經解決(可以訪問),A指令還需要再重新執行一次,所以pc需要指向A指令處。而在進入中斷處理程序之前,CPU已經自動將(pc-4)的值存入lr,這是C指令的位置,所以我們需要手動調整pc的位置,把它再減8,這才是A指令的位置。



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 菏泽市| 舞钢市| 晋宁县| 孝义市| 河津市| 安阳市| 镇康县| 东乡族自治县| 荆州市| 密山市| 兰西县| 忻城县| 龙门县| 奇台县| 本溪市| 青冈县| 临汾市| 沿河| 普安县| 景泰县| 富川| 平塘县| 瑞安市| 涿州市| 巴中市| 安化县| 大同市| 双江| 清新县| 崇文区| 云南省| 连云港市| 淳化县| 潞城市| 晋江市| 乐山市| 冷水江市| 武隆县| 安化县| 桂阳县| 阳朔县|