1. 程式人生 > >9.2 中斷向量表的結構

9.2 中斷向量表的結構

存放位置 line 用途 com cloud 偏移地址 一段 中斷 組成

計算機組成

9 中斷和異常

9.2 中斷向量表的結構

技術分享圖片

我現在已經知道了,在運算的時候 一旦遇到了異常情況,就翻到第一頁的第一行開始寫的這些操作的指示,開始往下執行。開始往下執行,這就能解決問題了。但是問題在於這段操作,解決的是我那個運算結果在空格裏填不下的問題。可是我遇到新的問題應該怎麽辦呢?我們可能還會遇到很多的其他的問題。這個時候,這個手冊的制造者實際上就需要做一些改進了。

手冊的第一頁不能只寫一種解決情況。他要畫一個表格,在這個表格裏分了一二三四五條,填上不同的情況。我們遇到了不認識的操作符號,請看第一頁的第二條;如果這個地方粘了一個蟲子,然後你這個數字看不清楚了,請見第一頁的第六條。這樣我們就能解決不同的情況了。

技術分享圖片

那我們先來回顧UNIVAC對異常處理的方式。當算術運算溢出的時候,UNIVAC就轉向地址0去取出指令。在那裏會執行兩條修復指令。這個處理方式已經是很靈活的了。只不過還有一些值得改進的地方。例如在存儲器當中,如果從地址0開始只預留了兩條指令的空間用於修復指令。那如果後來要改變修復的方式,需要再增加幾條指令,這裏預留的空間是否就有可能不夠了。另外當需要處理的異常情況變多的時候,那就需要根據異常情況的不同,去執行不同的異常處理指令。如果遇到異常都只能轉向地址0,就沒有辦法處理多種不同的異常了。因此,在這兩個方面都需要進行改進。

那麽就來看一看後來,8086是怎麽做的?

技術分享圖片

8086是一個16位的CPU。它內部有四個16位的通用寄存器,對外則有16根數據線。但是它的地址線要更多一些,一共有20根。這樣可以尋址的內存空間就是2的20次方,也就是一兆個Byte。

由於它內部的寄存器與運算器都是16位寬的,要生成20位寬的地址,就得用一定的轉換方法。8086采用的是段加偏移的方式。

然後對於這一兆的空間不都是可以任意使用的,有兩個區域保留作專門的用途。在這1M字節的內存空間中,最低的1K個字節保留作中斷向量表區,而最高的十六個字節保留為初始化程序區。

技術分享圖片

我們結合圖示來進行說明,這裏用填充了顏色的方塊用來表示這一兆字節的存儲器。8086CPU復位之後,它第一次取指令的操作發出的地址是四個F一個0(FFFF0H)。這個地址就是在這一兆內存空間的最高的16個字節的這個地方。這個區域實際上是很小的,只能放很少的幾條指令。通常放在這裏的是一條無條件的轉移指令,轉移到內存空間當中的另一個地方。在那個地方存放著後續的系統程序。

那CPU復位之後,為什麽不從全0(00000H)的地址開始取址呢?那樣看起來豈不是更自然一些。那因為從0開始的地址空間也已經被占用了。這個1K(0000H~003FFH)的字節被用作中斷向量表區,它一共存放了 256個中斷向量,每個中斷向量占四個字節。這樣正好就是1K(256*4=\(2^{10}=1K\))個字節。除了這兩塊專用的區域,其他區域就可以用來存儲一般的程序指令和數據。在這塊區域(0000H~003FFH),還有那些用於進行中斷處理的程序,這些程序就被稱為中斷服務程序。而這些程序代碼起始地址則被稱為中斷服務程序的入口地址。

這就是中斷向量的定義。

技術分享圖片

現在的CPU一般都能夠處理多種不同的中斷類型。

每個中斷類型就對應一個中斷向量,一共4個字節。在這四個字節當中,前兩個字節(06H和30H)用於存放中斷服務程序入口的偏移量,而且是低字節(06H)在前,高字節(30H)在後。因此,對於這個中斷向量,這兩個字節(06H和30H)就會被存放到指令指針寄存器(IP)當中去,而且前一個字節(06H)是寄存器當中的低字節,後一個字節(30H)是寄存器當中的高字節。那麽中斷向量當中的後兩個字節(00H和40H),則對應了中斷服務程序入口地址的段基值,用來存放到代碼段寄存器,也就是CS寄存器。那麽同樣,前面那個字節(00H)對應了寄存器當中的低字節,後面的字節(40H)對應了寄存器當中的高字節。在8086當中或者是後來X86處理器的實模式下,就需要用CS和IP這一對寄存器來指定一個內存的地址。

技術分享圖片

這個地址的產生方式就叫做段加偏移。CS寄存器就是一個段寄存器,它是16位的。而剛才的IP寄存器則對應了偏移量,也是一個16位。這兩個16位的地址就構成了邏輯地址。通常的表示方式就是用一個冒號分隔開這兩個16位數(CS:IP)。那在CPU產生地址時,會將段寄存器(CS)當中的數左移4位,然後加上偏移量,這樣加法運算的結就是20位的物理地址。這就是邏輯地址生成物理地址的方式。實際上是段基值乘以16加上偏移量,對於二進制來說左移四位就相當於乘以16了(二進制左移四位等價於十六進制左移一位)。

技術分享圖片

那基於這樣的方式,每個中斷向量都由兩個段基值和兩個向量的偏移地址組成。因為每一個中斷向量占四個字節,在整個中斷向量表中一共有256個中斷向量,分別命名為0號、1號、一直到255號中斷。這個中斷向量表要在系統裏面啟動時進行初始化。假設1號向量的初始值是這樣的,當cpu接收到中斷時,如果發現時1號中斷。因為各個中斷向量放置的地址是固定的,那cpu不需要通過執行指令,直接通過硬件電路的設置,就可以發出內存訪問來讀取這四個字節的內容。然後將其中高兩個字節送到CS寄存器當中去,低兩個字節送到IP寄存器當中去。

對於8086來說,這兩個寄存器(CS和IP)的功能就相當於我們在之前介紹處理器內部結構時提到的PC寄存器。所以,這兩個寄存器的值一旦發生改變,下一個周期cpu就會從這個新的地址(CS:IP)開始取下一條指令,根據段加偏移的計算方法,cpu發出的地址就是43006。因此,也就是說在遇到1號中斷時,cpu就會轉到43006這個地址開始執行程序。當然,需要事先把1號中斷的服務程序存放在這裏(存儲器內)。

與此類似,我們還會把0號中斷的服務程序放在存儲器的另一個地方,然後將0號中斷程序的起始地址分解成段基值和偏移地址,存放在0號中斷向量所在的位置。當cpu遇到中斷時,如果發現是0號中斷,則會將0號中斷向量對應的內容取出,分別填到CS和IP寄存器當中去。這樣cpu就會從0號中斷服務程序的起始地址開始取出指令進行執行。

我們註意到,這些中斷服務程序在內存當中的存放順序並沒有要求。並不需要按照中斷類型的順序,先放0號中斷服務程序,再放1號中斷服務程序,而是可以隨意放置。只需要把它的起始地址存放在中斷向量表的對應位置就可以了。這樣做就比UNIVAC的方式要靈活的多,一來中斷服務程序就可以可長可短,不用擔心在從0開始的地址到底要預留多少的空間才夠;二來中斷服務程序的存放位置如果發生改變,也沒有關系,不需要修改cpu的硬件設計,而只需要修改中斷向量表中對應的中斷向量就可以了。這樣只用初始化好中斷向量表,並在存儲器當中準備好對應的中斷服務程序,cpu在遇到中斷時就可以自動的跳到對應的中斷服務程序進行處理。

關於中斷向量的相關的計算,我們來看幾個簡單的練習。

技術分享圖片

第一,如果中斷類型碼,也就叫做中斷類型號為20H。那中斷向量起始的邏輯地址應該是什麽呢?首先,我們知道中斷向量表是從地址0開始的,一共256個中斷向量順序存放,而每個中斷向量占四個字節。所以,中斷向量存放的位置就是它的中斷類型號乘以4,那這個中斷地址就是0000:0080。如果這個中斷向量中四個字節的內容分別是10H、20H、30H和40H,那中斷服務程序的入口地址應該是什麽呢?

按我們剛才介紹的情況。這四個字節單元低兩個字節對應了IP寄存器,高兩個字節對應了CS寄存器。而且地址較低的這個字節是放在寄存器當中較低的位置。所以,這中斷服務程序的入口地址應該是4030:2010。這兩個練習就是說明了cpu在遇到了中斷之後,硬件完成的工作。如果cpu現在遇到的中斷類型號是20H,則會通過硬件進行乘4的操作,從而得到這個邏輯地址(0000:0080)。然後將這個邏輯地址發到存儲器中,讀回了這四個字節(10H、20H、30H 和 40H)的內容。然後,按照我們剛才規定的原則拼接出了這樣兩個16位數(4030:2010),並且把這兩個16位數分別存放到CS和IP寄存器當中去。這樣在下一個時鐘周期就會將新的地址發送到存儲器去取下一條指令了。

然後我們再來看另一個練習。

技術分享圖片

如果我們現在要為17H號中斷新寫了一段中斷服務程序,而且把這段中斷服務程序放到了存儲器的某一個地方,地址是2340H:7890H。

那現在我們就需要去更新中斷向量表。現在問題就是,我們要更新中斷向量表中的哪四個字節?而且更新成什麽樣的內容?那我們可以一起來算一下。因為中斷類型號是17H,那對應中斷向量的地址就應該是它乘以4(17*4 = 5C (mod 16))。由這個地址(0000:005C)開始,向高地址增長,一共4個字節。所以,這四個字節的邏輯地址是這樣的(第一個空)。

這四個字節單元當中分別應該填寫什麽樣的內容呢?那麽還是要記住這個原則,如果把這個邏輯地址(2340:7890H)從右往左看。最右邊的這個字節(90H)放在最低的地址,而最左邊的這個字節(23H)放在最高的地址。這四個字節依次排放。所以,地址由低到高四個字節內容分別應該是90、78、40和23。

那這兩個練習就分別展示了cpu硬件查找中斷向量表的過程,和準備好中斷服務程序去初始化或者修改中斷向量表的過程。

技術分享圖片

對於8086的中斷向量表cpu已經固定使用了前五個類型的中斷,具體的功能我們後面會再介紹。之後的27個中斷(5~31)也是保留給後續的cpu使用的。而除了前20個中斷,之後的224個的中斷則是交給使用cpu的用戶自行定義。

技術分享圖片

我們現在知道了,原來我們的第一頁制造者給我們列了一張表格。一共有256條。那我們在遇到異常情況的時候,就可以根據事先的約定對應不同的情況,去找對應的那一條表項。那條表項實際上是指一個頁碼。比如說第四條說翻到第十二頁,這第十二頁翻過來以後,寫了具體的操作,我們應該做什麽事情,操作還挺復雜,寫了好幾頁,我們都放在一頁紙是放不下的。所以,這就是我們現在要怎麽處理異常情況的方法。

隨著我們要做的運算任務的增加,這個表的內容可能還需要進一步的擴展。接下來我們就來看一看它是怎麽擴展的。

9.2 中斷向量表的結構