MIPS 體系和CISC體系結構有什么不同
一、MIPS指令集的限制
(1)所有指令長(cháng)度都是32位:這意味著(zhù)沒(méi)有指令能夠僅占用兩三個(gè)字節的內存空間(因而MIPS的二進(jìn)制文件比典型的680x0或80x86大百分之二十到三十),也沒(méi)有指令可以超過(guò)四個(gè)字節。
隨之而來(lái)就是不可能把一個(gè)32位常數放進(jìn)單個(gè)指令中。MIPS設計者決定留出26位常數的空間用以編碼跳轉和調用指令的目標地址:但是僅有給兩條指令。其它指令只能有16位空間留給常數。這樣裝入任意32位數值需要一個(gè)兩條指令的序列,條件分支被限制到64K指令范圍。
(2) 指令操作必須適合流水線(xiàn):只能在相應的流水線(xiàn)階段才能執行任務(wù),并且必須在一個(gè)時(shí)鐘周期內完成。例如:寄存器寫(xiě)回階段只能有一個(gè)值存入寄存器堆,所以指令只能修改一個(gè)寄存器。
整數乘除是不可或缺的重要指令,但是不能在一個(gè)時(shí)鐘周期內完成。MIPS CPU傳統的做法是發(fā)送這些操作到一個(gè)獨立的流水線(xiàn)單元,這個(gè)我們以后再說(shuō)。
(3)三操作數的指令:算數/邏輯指令不需要指定內存地址,所以空出了充足的指令位可以定義兩個(gè)獨立的源操作數和一個(gè)目的操作數。編譯器喜歡三操作數指令,其給了優(yōu)化程序更大的空間來(lái)處理復雜的表達式的代碼。
(4)32個(gè)寄存器:寄存器數量的選擇主要是由軟件需求驅動(dòng)的,在現代體系結構中一組32個(gè)通用寄存器是最為流行的。采用16個(gè)肯定不夠現代編譯器的需要,但是32個(gè)足夠讓C編譯器把常用的數據保存在寄存器中。采用64個(gè)或者更多的寄存器需要更大的指令域去編碼寄存器而且也增加了上下文切換的負擔。
(5)寄存器零:$0寄存器永遠返回零,給這個(gè)常用的數提供一個(gè)簡(jiǎn)縮的編碼。
(6)沒(méi)有條件碼:MIPS的指令集的一個(gè)特征就是沒(méi)有條件標志,這即使在1985年的RISC中也是極為激進(jìn)的。許多體系結構有多個(gè)標志位來(lái)表示運算結果的“進(jìn)位”、“為零”等等。CISC的典型做法是根據一些指令的操作結果設置這些標志,有些RISC體系結構保留了標志位。
MIPS體系結構決定把所有信息保存到寄存器堆中。比較指令設置通用寄存器,條件分支指令檢測通用寄存器。那樣確實(shí)有利于流水線(xiàn)實(shí)現,因為能夠減少對算術(shù)/邏輯操作依賴(lài)的巧妙機制不論從哪一種也都同時(shí)會(huì )減少比較/分支指令對中的依賴(lài)。
我們后邊會(huì )看到有效的條件分支意味著(zhù)是否分支的決定必須在半個(gè)流水線(xiàn)周期內作出:該體系結構通過(guò)保持分支決策的測試條件簡(jiǎn)單有助于實(shí)現這一點(diǎn)。所以MIPS的條件分支只測試單個(gè)寄存器的符號/為零或者一對寄存器是否相等。
二、尋址和訪(fǎng)存
(1)訪(fǎng)問(wèn)內存只能通過(guò)簡(jiǎn)單的寄存器加載和存儲:對內存變量進(jìn)行算術(shù)運算會(huì )打亂流水線(xiàn)。,所以不這么做。每次內存訪(fǎng)問(wèn)都要一條顯式的加載或存儲指令。大的寄存器堆使得這一點(diǎn)實(shí)際遠沒(méi)有聽(tīng)上去那么麻煩。
(2)只有一種數據尋址方式:幾乎所有的加載和存儲都通過(guò)單個(gè)寄存器基址加上一個(gè)16位的常數偏移量尋址內存。
(3)字節地址指令:一旦數據存入MIPS CPU的寄存器,所有的操作都是在整個(gè)寄存器上操作。但是象C這樣的語(yǔ)句語(yǔ)義不適合不能尋址內存到字節粒度的機器。因而MIPS對8-和16-位變量提供了一套完整的裝入/存儲操作。一旦數據到達寄存器,就當作寄存器全長(cháng)來(lái)處理,所以部分字節愛(ài)在指令有兩種形式——符號擴展和零擴展。
(4)load/store必須對齊:內存操作只能從對齊到相應數據類(lèi)型邊界的地址加載荷存儲數據。字節可以在任意地址傳輸,但是半字必須在偶數地址對齊,字在四字節邊界對齊。許多CISC微處理器可以從任意字節地址加載/存儲四字節數據,但是要花費額外的時(shí)鐘周期。
但是,MIPS指令集體系結構確實(shí)包含有幾個(gè)特殊的指令以簡(jiǎn)化對沒(méi)有適當對齊的地址存取操作。
(5)跳轉指令:有限的32為指令長(cháng)度在想要支持很大程序的體系結構上對分支是個(gè)問(wèn)題。MIPS指令的最小操作碼域為6位,留出了26位來(lái)定義跳轉的目標。因為所有指令在內存中都是四字節邊界對齊的,低兩位地址無(wú)需保存,這樣可有256MB的地址范圍。這個(gè)地址不是相對PC的,而是解釋成256MB段內的絕對地址。這對大于256MB的單個(gè)程序極為不便,到目前按還沒(méi)有碰到太大的問(wèn)題。
超出段內的分支可以通過(guò)使用一個(gè)寄存器跳轉指令做到,該指令可以跳轉任意32位地址。
條件分支只有16位的偏移域——給出了262144字節的范圍,因為指令都是四字節對齊的——解釋成相對PC的帶符號的偏移量。如果知道分支目標會(huì )在緊跟分支之后的指令的128KB范圍內,編譯器就能只生成一個(gè)簡(jiǎn)單的條件分支指令。
三、MIPS沒(méi)有的特性
(1)沒(méi)有字節或半字數據的運算:所有算術(shù)和邏輯操作都是在32位的數據上進(jìn)行。字節或半字的運算需要大量額外的資源和許多額外的操作碼,而且很少有用。C語(yǔ)言的語(yǔ)法讓大多數的計算用int 類(lèi)型,對MIPS而言int就是32位的整數。
然而當程序明確做short或者char運算時(shí),MIPS編譯器必須插入額外的代碼以保證結果回繞和溢出,生成跟8-或16-位機器上一樣的結果。
(2)沒(méi)有對堆棧的特殊支持:傳統的MIPS匯編確實(shí)定義了一個(gè)寄存器作為堆棧指針,但是硬件上SP沒(méi)有任何特殊之處。有一種推薦的關(guān)于子程序調用的棧幀布局,這樣可以混合不同語(yǔ)言和編譯器的模塊;你應當遵守這些約定,但是這些與硬件無(wú)關(guān)。
堆棧彈出不能適應流水線(xiàn),因為有兩個(gè)寄存器要寫(xiě)。
(3)最少的子程序支持:有一點(diǎn)比較特別:跳轉指令有一個(gè)跳轉并鏈接的選項,把返回地址存入一個(gè)寄存器,默認是#31.所以方便起見(jiàn)習慣上用#31作為返回地址寄存器。
這樣做比起把返回地址保存到堆棧上要簡(jiǎn)單,但卻帶來(lái)明顯的好處。隨便舉兩個(gè)好處瞧瞧:第一,保持了分支和訪(fǎng)存指令的完全分離;第二,當調用許多根本不需要在堆棧保存返回地址的小程序時(shí),這樣做又助于提高效率。
(4)最少的中斷處理:很難看到硬件能做得比這更少的了。它把重新開(kāi)始的地址存放到一個(gè)特殊的寄存器,接著(zhù)僅修改剛剛夠找出怎么回事的少量機器狀態(tài)并禁止進(jìn)一步中斷,然后跳轉到低端內存事先定義好的一個(gè)單一入口地址,伺候一切由軟件負責。
(5)最少的異常處理:中斷只是異常的一種類(lèi)型。一個(gè)異??梢詠?lái)自一個(gè)中斷,來(lái)自對物理上不存在的虛擬內存的試圖訪(fǎng)問(wèn)、或者其它很多情況。一條有意引入的、類(lèi)似系統調用的、用來(lái)進(jìn)入受保護的OS內核的自陷指令發(fā)生時(shí),也會(huì )進(jìn)入一個(gè)異常。所有異常都導致控制傳遞到同樣的固定入口地址。任何異常發(fā)生時(shí),MIPS CPU都不會(huì )存進(jìn)堆棧、寫(xiě)入內存或者備份寄存器。
按照約定,保留了兩個(gè)通用寄存器給用于異常,這樣異常處理程序可以自舉。對于運行在允許中斷和自陷的任何系統上的程序來(lái)說(shuō),這兩個(gè)寄存器的值隨時(shí)可能變化,所以最好不要用。
四、程序員可見(jiàn)的流水線(xiàn)效果
到目前為止,以上就是你需要從一個(gè)簡(jiǎn)化的CPU了解的全部?jì)热?。然而使得指令集適應流水線(xiàn)也會(huì )導致一些奇怪的效果。為了便于理解,我們畫(huà)圖說(shuō)明。
圖1.3:流水線(xiàn)和分支延遲
評論