超标量处理器设计 姚永斌 第1章 超标量处理器概览 摘录
1.1 為什么需要超標量?
如何才能讓程序執行得更快?在計算機領域有這樣一個經典的公式來計算一個程序的執行時間:
影響程序執行時間的因素:
????????Total Instructions:程序總共需要執行指令的個數;
????????Cycles/Instructions:執行每天指令所需要的周期數;
Seconds/Cycle:每周期需要的時間;
從上面三個因素可以看出,要加快執行程序的速度,可以采取的策略有如下方式:
????????(1) 減少程序中指令的數量,這個主要取決于程序本身要完全的工作量,實現某個功能所需要的算法、編譯器強大與否、甚至指令級是否會對某些特殊的功能有擴展。比如x86指令集中的多媒體指令。
????????(2) 減少每條指令在處理器中執行所需要的周期數,也就是減少CPI,意味著增加IPC(Instructions Per Cycle),其中,CPI與IPC互為倒數、CPI表示處理器執行一條指令需要的周期數,而IPC則表示處理器在一個周期內可以執行的指令個數。對于非流水線的處理器,需要多個周期才能執行一條指令,而對于普通的流水線處理器,每周期最多執行一條指令,因此IPC最大也就是1。可以使用超標量處理器來提高IPC。
????????(3) 減少處理器的周期時間,在經過精巧的電路設計、更深的流水線來減少處理器的周期時間。
從三個因素可以看出,在程序一定的情況下,需要處理器有比較大的IPC,以及更快的運行頻率。但是實際中這兩個因素是相互制約的,更大的IPC要求每周期更多的指令,這樣設計復雜度會劇烈上升,導致處理器的周期時間很難降低下來。
雖然可以通過更深的流水線來獲得小的周期時間,但是卻導致處理器在各種預測失敗時,例如分支預測失敗(mis-prediction),有著更大的懲罰(penalty),嚴重降低處理器的IPC,并增大了功耗。造成“高頻低能”的后果。
每周期可以從I-Cache中取出的n條指令送到處理器的流水線中,處理器在每周期內也最少可以同時執行n條指令,這稱為n-way的超標量處理器是。
在處理器的發展史中,每周期執行多于一條指令的處理器并非超標量一種,超長指令字(Very Long Instruction Word, VLIW)也是一種每周期可以執行多條指令的處理器架構。
這兩種架構本質區別是:超標量處理器是靠硬件自身來決定哪些指令可以并行地執行,而VLIW處理器則是依靠編譯器和程序員自身來決定那些指令可以并行執行。
對于通用處理器來說,超標量結構是必須的,程序員可以拋開底層硬件的實現細節,專注于軟件本身的功能,而且這個程序可以運行在任何支持該指令集的處理器上。而VLIW則無法實現這個功能。
超標量處理器可以獲得比較高的IPC,也伴隨著天生的復雜性。導致處理器設計師需要根據實際情況作出各種折中(tradeoff)。例如,實現一個精準的分支預測算法需要復雜的硬件資源,導致其在一個周期無法完成,則處理器無法馬上利用預測信息進行連續的取指令,這樣處理器的性能就會下降。再比如load/store指令如果按照完全亂序的方式執行雖然會獲得最大的IPC,卻會導致load/store指令之間的相關性檢查變得非常復雜,而且一旦發現相關性違例,還需要復雜的回復機制,導致硬件復雜度和功耗的增加。以及,CheckPoint的個數和硬件的面積,發射隊列(issue?queue)和仲裁(select)電路的復雜度,每周期可以同時執行的指令個數(issue?width)和寄存器堆(register?file)的端口個數。
要想獲得更好的性能,就需要更復雜的設計和更多硬件資源,由此帶來了更高的成本和功耗。注意服務器和桌面PC領域的處理器應該將性能放在第一位。移動領域在保證性能的情況下,盡量降低設計的復雜度,才能獲得比較低的功耗。
1.2?普通處理器的流水線
1.2.1?流水線概述
流水線是現代處理器獲得高性能的重要法寶,通過流水線可以降低處理器的周期時間(cycle time),從而獲得更快的執行頻率。
當處理器沒有使用流水線時,它的周期時間是D,也就是頻率是1/D;使用n級流水線后,周期時間變為“D/n+S”,其中S表示流水線寄存器的延遲。
在加入流水線后,處理器所消耗的硬件也有了變化。
當處理器沒有使用流水線時,需要消耗的硬件面積為G;當使用了n級流水線后,消耗的硬件可以表示為G+n*L;
則假如流水線后的Cost/Performance = (G+n*L)/(1/(D/n+S)) = GD/n + SL*n + GS;從上式可以看出,當G、D、L和S都已知的情況下,可以得到最優化的流水線級數。當然,還要考慮其他因素,例如分支預測的準確度,load/store指令的處理方式。而且不同的處理器有不同的定位,有些處理器面向高性能計算,有些面向低功耗的嵌入式應用。
1.2.2?流水線的劃分
在理想情況下,流水線的劃分需要滿足下面一個條件:
????????(1)流水線中每個階段所需要的時間都近似相等,其中最長的流水段所需要的時間決定了整個處理器的周期時間。
????????(2)流水線中每個階段的操作都會被重復地執行。
????????(3)流水線中每個階段的操作都和其他流水段相互獨立、互不相干。這一條由于存在指令之間的相關性,例如寫后讀。因此這一條最難滿足,也是影響流水線執行效率的關鍵因素。
對于CISC指令級而言,指令的長度不等,并且執行時間也不等,所以直接實現流水線是比較復雜的。而對于RISC而言,由于指令的長度相等,并且每條指令所完成的任務比較規整,易于使用流水線實現。一個典型的RISC處理器的流水線如下圖所示:
?流水線每個階段完成的任務如下表所示:
| 流水段 | 完成的任務 |
| Fetch | 取指令,使用PC寄存器的值作為地址,從I-Cache中取出指令,并將指令儲存在指令寄存器中。 |
| Decode&Regfile?read | 將指令解碼,并根據解碼出來的值來讀取寄存器堆(register file),得到指令的源操作數。 |
| Execute | 根據指令的類型,完成計算任務,例如對算法類型的指令完成算術運算,對訪問存儲器類型的指令完成地址的計算等。 |
| Memory | 訪問D-Cache,只對訪問存儲器類型的指令(主要是load/store指令)起作用,其他類型的指令在這個流水段不做任何事情。 |
| Write?back | 如果指令如下目的寄存器,則將指令的最終結果寫到目的寄存器中。 |
上面的這個流水線未必是最優化的,因為每個階段所需要的時間相差很多,比如
?則不使用流水線時,處理器的周期時間近似為 T = 7 + 11 + 5 + 10 + 3 = 36ns;
使用流水線后,周期時間近似為T =max(Ti) = 11ns;
使用上圖的流水線可以使處理器的速度提高36/11倍,但是上面的流水線中,各個階段所占時間是很不平衡的,要想獲得更優化設計,需要對流水線中的各個階段進行平衡,有兩種方法可以進行這個工作。
????????方法一:合,將兩個或多個流水段合并成一個流水段。
?
?使得流水線從五級降為三級,每個流水段所占據的時間也比較均衡,此時處理器的周期時間為13ns,這種辦法適用于對性能要求不高的低功耗嵌入式處理器。
????????方法二:拆,將流水線的一個階段拆成多個更小的階段。如下圖所示:
?這種方法適合高性能處理器,可以獲得比較高的主頻,但是這種比較深得流水線會導致硬件消耗的增大,例如需要更多的流水線寄存器和控制邏輯;寄存器堆的端口數也需要增加,以支持多個流水段同時讀寫;存儲器(D-Cache)端口數量也需要隨之增加,用來支持更多的流水段同時訪問存儲器。隨著芯片面積的增大和主頻的提高,處理器的功耗也會隨之增大,制約了這種方法的方式。而且,深流水線對于分支預測的影響也是非常大的,會導致預測失敗時的懲罰(mis-prediction penalty)增大,從而影響處理器的執行效率。因此這種方法無法無限制使用下去
?1.2.3?指令間相關性
指令之間的存在的相關性是阻礙程序并行執行的關鍵因素。概括來說,指令之間存在三種類型的相關性。
? ? ? ? (1)先寫后讀(Read After Write, RAW),也稱true?dependence,一條指令的操作數如果來自之前指令的結果,那么這條指令必須等到之前的指令的到的結果,才可以繼續執行。這種類型的相關性是無法回避的,舉例如下;
指令A:R1 = R2 + R3; 指令B:R5 = R1 + R4;????????指令B的一個操作數來自于指令A的結果,所以就必須等待指令A將結果計算出來,指令B才可以繼續執行。
? ? ? ? (2)?先讀后寫(Write After Read, WAR),也稱anti-dependence,一條指令要將結果寫到某個寄存器中,但是這個寄存器還在被其他指令讀取,所以不能馬上寫入。距離如下;
指令A:R1 = R2 + R3; 指令B:R2 = R5 + R4;? ? ? ? 指令A在讀取寄存器R2之前,指令B不能將結果寫到寄存器R2中,這種類型的相關性是可以壁面的,只需要將指令B的結果寫到其他寄存器就可以了。
? ? ? ? (3)?先寫后寫(Write After Write, WAW),也稱output?dependence,如果兩條指令都要將結果寫到同一個寄存器中,那么后面的指令必須等待漆面的指令寫完之后,自己才能執行寫操作,舉例如下:
指令A:R1 = R2 + R3; 指令B:R1 = R5 + R4;? ? ? ? 指令A和指令B都將結果寫到目的寄存器R1中,指令B應該在指令A之后進行寫入,這種劉選哪個的相關性也可以壁面,只要后續的指令B將結果寫到其他寄存器就可以了。
還有一種類型的相關性稱為控制相關性(control?dependence),它是由分支指令引起的,只有當分支指令的結果被計算出來的時候,才可以知道從那里取得后續的指令來執行,由于分支指令需要一段時間才可以得到結果(跳轉或不跳轉,跳轉的目標地址)。一段典型的MIPS匯編程序:
?WAR、RAW和WAW這三種相關性不僅對寄存器之間的關系適用,對于存儲器地址之間的相關性也適用,只不過寄存器之間的相關性可以通過指令直接表現出來,而存儲器地址之間的相關性則很難看出來。
sw r1, 0(r5) // 將寄存器r1的值保存到MEM[r5]中 lw r2, 0(r6) // 將MEM[R6]的值讀取到寄存器r2中當寄存器r5和r6的值相等時,這兩條指令之間存在RAW的相關性。比較隱蔽。
對于標量處理器而言,WAW和WAR這兩種相關性并不會引起問題,而RAW相關性可以通過旁路(bypass)的方式來解決;對于超標量處理器來說,WAW、WAR和RAW這三種相關性會阻礙指令的亂序執行,都需要在流水線中進行特殊的處理。
1.3?超標量處理器的流水線
簡單地說,如果一個處理器每周期可以取出多于一條的指令送到流水線中執行,并且使用硬件來對指令進行調度,那么這個處理器就可以被稱為超標量處理器。
| Frontened | Issue | Write back | Commit | |
| In-Order Superscalar | in-order | in-order | in-order | in-order |
| Out-of-Order Superscalar | in-order | out-of-order | out-of-order | in-order |
在這個表格中,Frontened表示流水線中的取指令(Fetch)和解碼(Decode)階段,這兩個階段很難(事實上也沒有意義)實現亂序執行;
Issue表示將指令送到對應的功能單元(Function Unit, FU)中執行,這里可以實現亂序執行,因為只要將指令的源操作數準備好了,就可以將其先于其他指令而執行;
Write?back表示將指令的結果寫到目的寄存器中,可以在處理器內部使用寄存器重命名,將指令集中定義的邏輯寄存器(Architecture Register File, ARF)動態地轉化為芯片內部實際使用的無壓力寄存器(Physcial Register File, PRF),從而實現亂序方式的寫回寄存器;
Commit表示一條指令被允許更改處理器的狀態(Architecture?state,例如D-Cache等),為了保證程序按照原來的意圖得到執行,并且實現精確的異常,這個階段需要順序執行,這樣才能保證從處理器外部看來,程序是按照串行執行的。
1.3.1?順序執行
在順序執行的超標量處理器中,指令的執行必須遵循程序中指定的順序,這種類型的處理器的流水線可以概括地用下圖來表示:
?上述流水線每周期可以從I-Cache中取出兩條指令來執行,則稱為2-way的超標量處理器,在指令經過解碼之后,需要根據自身的類型,將兩條指令送到對應的FU中執行,這個過程稱為發射(Issue)。如果將發射過程放到指令的解碼?階段,會嚴重影響處理器的周期時間,因此將發射過程單獨使用一個流水段,在這個階段,指令會讀取寄存器而得到操作數,同時根據指令的類型,將指令送到對應的FU中進行執行。在執行階段使用了三個FU:第一個階段用來執行ALU類型的指令,第二個FU用來執行訪問存儲器類型的指令,第三個階段用來執行乘法操作,因為要保證流水線的寫回(Write back)階段是順序執行的,因此所有FU都需要經歷同樣周期數的流水線,其中乘法運算需要的時間最長,因此所有第三個FU使用了三級流水線,其他FU也需要更隨著使用三級流水線,即使他們在有些流水線什么事情都沒有做。ScoreBoard用來記錄流水線中每條指令的執行情況,例如一條指令在那個FU中執行,在什么時候這條指令可以將結果計算出來。
?ScoreBoard中記錄了指令集中定義的每個邏輯寄存器(R0~R31)的執行情況,在典型的情況中,需要記錄的信息如下:
? ? ? ? P:Pending,表示指令的結果還沒有寫回到邏輯寄存器中。
? ? ? ? F:一條指令在那個FU中執行,在將指令結果進行旁路時會使用這個信息。
? ? ? ? Result Position:在這個不分記錄了一條指令到達FU中流水線的那個階段,3表示指令處于FU流水線的第一個流水段,1表示指令到達FU流水段的最后一個階段,0表示指令處于流水線的寫回階段,在流水線的發射階段,會將指令的信息寫到ScoreBoard中。同時,這條指令會查詢ScoreBoard來獲知自己的源操作數是否都準備好了,再這條指令被送到FU中執行之后的每個周期,都會將這個值右移一位,這樣使用這個值就可以表達出指令在FU中執行到那個階段,對于執行ALU類型指令的第一個FU來說,當指令到達3時,就可以將它的結果旁路了;而對于執行乘法指令的第三個FU來說,只有當指令到達1時,才可以將它的結果進行旁路。指令可以從旁路網絡(bypassing network)獲得操作數,不需要等待源寄存器的值被寫回到通用寄存器中。
在所有的處理器中,RAW相關性都是不可以繞開的,如果一個程序存在過多的RAW相關性,那么這個程序就不能在處理器中被有效執行。
1.3.2?亂序執行
一旦某條指令的操作數準備好了,就可以將其送到FU中執行。
對于一個2-way超標量處理器是,每周期從I-Cache取出兩條指令并進行解碼,為了亂序執行解決WAW和WAR這兩種相關性,需要對寄存器重命名(register renaming),這個過程可以在流水線的解碼(Decode)階段完成,也可以單獨使用一個流水段來完成。處理器需要增加物理寄存器堆(Physical Register File,PRF)來配合完成指令集中定義的寄存器(Architecture Register File, ARF)進行重命名,PRF中的寄存器的個數要多于ARF。
指令在流水線的取指令、解碼和寄存器重命名都是按照程序中規定的順序(in-order)來進行的,直到指令到達流水線的發射(Issue)階段。在這個階段,指令將被存儲在一個緩存中,這個緩存被稱為發射對列(Issue Queue),一旦指令的操作數準備好了,就可以從發射隊列中離開,送到對于的FU中執行,因此發射隊列是流水線從順序執行到亂序執行的分界點。
每個FU都有自己的流水線級數,如執行ALU類型的指令的FU需要一個周期就可以計算出結果,不在需要像順序執行的處理器那樣唄拉長到和乘法FU一樣的周期數。在這種流水線中,由于每個FU的執行周期都不相同,所以指令在流水線的寫回(Write back)階段是亂序的。在這個階段,一條指令只要計算完畢,就會將結果寫到PRF,由于分支預測(mis-prediction)和異常(exception)?的存在,PRF的結果未必都會寫到ARF中,因此也將PRF成為Future File。
為了保證程序的串行結果,指令需要按照程序中規定的順序更新處理器的狀態,這需要使用一個稱為重排序緩存(ROB)的部件配合,流水線中的所有指令都按照程序中規定的順序存儲在重排序緩存中,使用重排序緩存來實現程序對處理器狀態的順序更新,這個階段稱為提交(Commit)階段,一條指令在這個階段,會將它的結果從PRF搬到ARF中,同時重排序緩存也會配合完成對異常(exception)的處理,如果不存在異常,那么這個指令就能順利離開流水線,并對處理器的狀態進行更改,此時稱這條指令退休了,一條指令一旦退休,它就再也不可能回到之前的狀態了。
指令一旦退休之后,就不可以再從流水線中清除了。這給store?指令帶來了額外的麻煩,因為store指令需要寫存儲器,如果在write?back階段就將結果寫到存儲器中,那么一旦由于分支預測失敗或者異常等原因,需要將這條store指令從流水線中抹掉時,就沒有辦法將存儲器的狀態進行恢復了,因為存儲器中原來的值已經被覆蓋了。于是,上圖使用了一個緩存,稱為Store Buffer(SB),來存儲store指令指令沒有退休之前的結果,store指令在流水線的寫回階段,會將它的結果寫到Store Buffer中,只有一條store指令真滴從流水線中退休的時候,才可以將它的值從Store Buffer寫回到存儲器中。使用了這個部件之后,Load指令此時除了從D-Cache中尋找數據,還需要從Store Buffer進行查找,這樣在一定程度上增加了設計的復雜度。
本節重點關注亂序執行的超標量處理器,下面對?某個流水線中的各個階段做一個粗略的介紹:
? ? ? ? (1)Fetch(取指令):這部分負責從I-Cache中取指令,主要由兩大部件組成,I-Cache負責存儲最近常用的指令:分支預測器用來決定下一條指令的PC值。
? ? ? ? (2)Decode(解碼):這部分用來識別出指令的類型、指令需要的操作數以及指令的一些控制信號等。這部分的設計和指令集是息息相關的,對于RISC指令集來說,由于比較簡潔,解碼部分相對比較簡單。對于CISC指令集來說,由于比較復雜,所以解碼部分需要更多的邏輯電路來對這些指令進行識別。
? ? ? ? (3)Register Renaming(寄存器重命名):在流水線解碼階段,可以得到指令的源寄存器和目的寄存器,這些寄存器都是邏輯寄存器,在指令集中定義好的。為了解決WAW,WAR這兩種“偽相關性”,需要使用寄存器重命名的方法,將指令集中定義的邏輯寄存器重命名為處理器內部使用的物理寄存器,物理寄存器的個數要多于邏輯寄存器,通過寄存器重命名,處理器可以調用更多可以并行執行的指令。在進行重命名時,通常使用一個表格來存儲當前邏輯寄存器到物理寄存器的對應關系,同時在其中還存儲中那些物理寄存器還沒有被使用的信息,提供一些電路來分析當前周期被重命名的指令之間的RAW相關性,將那些存在RAW相關性的指令加以標記,這些指令會通過后續的旁路(bypassing?network)來解決它們之間存在的“真相關性”。由于寄存器重命名階段花費時間比較長,現實當中處理器都會將其單獨使用一級流水線,而不是和解碼階段放在一起。
? ? ? ? (4)Dispatch(分發):在這個階段,被重命名之后的指令會按照程序中規定的順序,寫到發射對列(Issue Queue)、重排序緩存(ROB)和Store Buffer等部件中,如果這些部件中沒有合適的空間可以容納當前的指令,那么這些指令就需要在流水線的重命名階段進行等待,這就相當于暫停了寄存器重命名以及之前的所有流水線,直到這些部件中有空閑的空間為止。分發階段可以和寄存器重命名階段放在一起,在一些對周期時間比較緊的處理器匯總,也可以將這個不分單獨使用一個流水段。
? ? ? ? (5)Issue(發射):經過流水線分發(Dispatch)階段之后,指令被寫到發射隊列(Issue Queue)中,仲裁(select)電路會從這個部件中挑選出合適的指令送到FU中執行,這個仲裁電路可繁可簡。對于順序發射發射(in-order?issue)的情況,只需要判斷發射隊列中最舊的那條指令是否準備好就可以了。而對于亂序進行發射(out-of-order issue),則仲裁電路會變得會變得比較復雜,它需要對發射隊列中所有指令進行判斷,并從所有準備好的指令中找出最合適的那條指令,送到FU中執行、對于亂序處理器而言,這個階段是從亂序執行到亂序執行的分界點,指令在這個階段之后,都是按照亂序的方式來執行,直到流水線的提交(Commit)階段,才會重新變成順序執行的狀態。在發射隊列中還存在喚醒(wake-up)電路,他可以將發射隊列中對應的源操作數置為有效的狀態,仲裁電路和喚醒電路互相配合進行工作,是超標量處理器中的關鍵路徑。
? ? ? ? (6)Register File(讀取寄存器):被仲裁電路選中的指令需要充物理寄存器堆(PRF)中讀取操作數。一般情況下,被仲裁電路選中的指令可以從PRF得到源操作數。當然還有不一般的情況,那就是指令不能從PRF中得到操作數,事實上很大一部分指令都是通過旁路網絡獲得操作數的。這也為減少PRF的讀端口提供了可能。由于超標量處理器每周期需要執行好幾條指令,PRF所需要的端口數也是比較多的,多端口的寄存器堆的訪問速度一般都不是特別快。因此在現實世界的處理器中,這個階段都會單獨使用一個流水段。
? ? ? ? (7) Execute(執行):指令得到了它所需要的操作數之后,馬上就可以送到對應的FU中執行了,在超標量處理器中,這個階段通常有很多不同類型的FU。例如負責普通運算的FU,負責乘加運算的FU,負責分支指令運算的FU,負責load/store指令的FU等。現在處理器還會加入一些多媒體運算的FU,例如SIMD運算的FU。
? ? ? ? (8) Wirte?back(寫回):這個階段將FU計算的結果寫回物理寄存器堆中。同時這個階段還有一個很重要的功能,就是通過旁路網絡將這個計算結果送到需要的地方,一般都是送到FU的輸入端。由FU的輸入端的控制電路在決定最終需要的數據,在現代處理器中,旁落網絡是影響速度的關鍵因素,因為這部分需要大量的布線,而隨著硅工藝尺寸的減少,連線的延遲甚至超過門電路的延遲,因此旁路網絡會嚴重影響處理器的周期時間。為了解決這個問題,很多處理器都采用了Cluster結構,將FU分成不同的組,在一個組內FU,布局布線時會緊挨在一起,這樣此組內的旁路網絡由于經過的路徑比較短,一般都可以在一個周期內完成。當旁路網絡跨越不同的組時,就需啊喲兩個甚至更多的周期了。
? ? ? ? (9) Commit(提交):這個階段主要作用的部件是重排序緩存ROB,它會將亂序執行的指令拉回到程序中規定的順序,之所以能完成這樣的任務,是因為指令在流水線的分發(Dispatch)階段,按照程序中規定in-order寫到了重排序緩存中。處理器執行的結果要和程序中原始的順序是一樣的,但是在超標量處理器中,指令是按照亂序的方式在內部執行的,最后需要這樣一個階段,將這些亂序執行的指令變回到程序規定的原始順序。在重排序緩存中,如果一條指令的指令還沒有執行完,那么即使這條?指令已經執行完了,它也不能離開重排序緩存,必須等待它之前的所有指令都執行完成。在這個階段也會對指令產生的異常進行處理,指令在流水線的很多階段都可以發生異常,但是所有的異常都必須等到指令到達流水線的提交Commit階段才能進行處理,這樣保證異常的處理按照程序中規定的順序進行,并且能夠保證實現精確的異常。一條指令一旦從重排序緩存中離開而退休retrie,那么就對處理器的狀態進行了修改,再也無法返回到之前的狀態了。
? ? ? ? 在超標量處理器中,還有一個非說不可的話題就是處理器的狀態恢復,現代的處理器在很多地方使用了預測技術。因為超標量處理器的流水線一般比較深,不使用預測技術是沒有辦法獲得高性能的。一般情況下,預測能夠有效工作的前提就是有規律可循,一個很明顯的例子就是分支預測。分支指令在執行過程中表現出規律性,使分支預測成為了可能。但是,只要是預測,就會存在失敗的可能,這時候就需要一種辦法,將處理器的狀態恢復到正確的狀態,這就是恢復電路的工作。它不但要將錯誤的指令從流水線中抹去,還需要將這些錯誤指令子啊流水線中造成的“痕跡”進行消除。例如錯誤的指令可能已經修改了重命名映射表,或者將結果寫到了物理寄存器中等。恢復電路和預測技術是天生一對,只要有預測,就必然有狀態恢復。激進的預測技術會提高處理器的性能,但是代價就是更復雜的恢復電路。
總結
以上是生活随笔為你收集整理的超标量处理器设计 姚永斌 第1章 超标量处理器概览 摘录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: log4cplus指南
- 下一篇: cout 输出格式