關於中斷

ARM7TDMI有兩種類型的中斷模式:FIQ和IRQ,它們的區別是:對於FIQ必須儘快處理事情並離開這個模式,IRQ可以被FIQ中斷,而IRQ不能中斷FIQ。常見的例子是各種中斷使用IRQ模式,把FIQ模式保留備用。

      對於各種中斷源的響應,S3C44B0有兩種中斷模式:向量中斷模式和非向量中斷模式,這就導致在軟件處理上,可以很靈活的處理中斷請求。一般來說做如下處理:
      如果系統採用的ROM定位在地址0X00,則中斷向量標應該包含一系列分支語句,跳轉到相應的中斷處理程序(這也是S3C44B0所支持的模式)
      如果ROM定位到別的地址處,向量必須由初始化代碼進行動態定位。
一般把這部分功能放在Bootloader中處理,對於這一點來說初學者很容易搞混,下面就詳細解釋中斷處理的幾種實現方式。


1、向量中斷模式(也叫矢量中斷模式)
      爲了縮短中斷模式在進入所需的服務前所需要的中斷響應時間,S3C44B0提供了一種新的中斷模式——矢量中斷模式。當多重中斷源請求中斷時,硬件優先級邏輯會判斷哪一個中斷將會被執行,同時,硬件邏輯自動執行由0x18地址到各個中斷源向量地址的跳轉指令,然後再由中斷源向量進入相應的中斷處理程序。簡單的說,每個中斷源對應一個內存地址,只要在對應的地址上設置一條到中斷服務程序的跳轉指令,CPU自動跳轉到響應的中斷處理函數。和原來的軟件實現方式相比,這種方式可顯著縮短中斷響應時間。
 
2、非向量中斷模式
      在非向量中斷模式下,有兩種方式可以使PC指向相應的中斷處理程序。

      第一種方法,可以通過對I_ISPR/F_ISPR寄存器的分析判斷出中斷的類型,然後再把PC指向相應的中斷處理程序。其中HandlerXXX實際上是一段跳轉程序,運行這段程序將把HandleXXX指向的內容值賦給PC。由於HandleXXX所對應的地址中,存放的是每個相應的ISR的起始地址,這樣就完成了向特定ISR的調轉。這些ISR地址存放在HandleXXX指向的表項中,該表一般定位在RAM高端,基地址爲ISR_STARTADDRESS。
      第二種方法,對於IRQ處理程序可以通過對I_CMST寄存器的分析來判斷中斷源的類型,然後再把PC指向相應當中斷處理程序。

      之所以被稱爲向量中斷模式,是因爲它不需要用程序判斷中斷源,通過硬件實現直接跳轉到相應ISR。而非向量中斷必須在中斷服務程序中判斷中斷來源,進而跳轉到不同的處理程序。但兩者中斷源的優先級都是通過硬件判斷的,因爲中斷服務登記寄存器每次只能設置一個服務位,並有硬件置位中斷響應後清除,若被打斷登記寄存器相應位置位。

      在非向量中斷模式下,中斷響應流程如下:
      1、通常情況下,CPU內核收到來自中斷控制器的IRQ中斷請求,會在0x00000018處執行一條指令,在從0x00000018處取指令時,中斷控制器會在數據總線上加載分支指令。這些分支指令使程序計數器能夠對應到每一箇中斷源的向量地址。所以,一般會在從0x00處到0xA0處放置跳轉指令,跳轉到HandlerXXX處。
 
      2、HandlerXXX處一般放置彙編下面的一段中斷處理宏(一般定義爲HANDLER),入口是跳轉地址,
      主要流程:
              棧空間遞減保存跳轉地址
              保存工作寄存器R0到棧
              載入中斷入口地址所在位置到R0
              載入中斷入口地址到R0
              保存中斷入口地址到棧
              恢復工作寄存器並跳轉到中斷函數
      通過如下一系列宏跳轉到HandleXXX:HandlerXXX        HANDLER        HandleXXX(HandlerXXX是彙編標號)
      HandleXXX一般是定義在存儲器高端的中斷入口向量定義表,存放中斷處理函數的指針。
      內存中的HandleIRQ地址處存放總中斷入口處理函數指針。這個函數的實現其中一個方法如下:

            static ISR_HANDLER_IRQ IsrHandler[NINT_NUMBERS];        //定義中斷跳轉表

            void IrqIsr(void)
            {
                int nInt;
                INT32U temp,i;
                ISR_HANDLER_IRQ pIsr;
        
                if((temp = rI_ISPR) == 0)              //讀出中斷掛起寄存器
                        return;
                for(i=0; i<26; i++)                    //轉換成中斷編號
                {
                        if(temp & 0x1 == 1)
                              break;
                        else
                              temp = temp >> 1;
                }
        
                nInt = i;
                if(nInt == 26)
                        return;
        
                pIsr = IsrHandler[nInt];
                if(pIsr)
                        (*pIsr)();                      //執行中斷服務程序
                else
                        CLEAR_PENDING_BIT(nInt);        //清空中斷標誌位
            }

            //中斷裝載函數:
            int OSInstallIsr(int nInt,ISR_HANDLER_IRQ pIsr)
            {
                if(nInt > NINT_NUMBERS || nInt < 0 || !pIsr)
                        return 0;
        
                IsrHandler[nInt] = pIsr;
                        return 1;
            }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章