天天看點

流水線學習筆記(二)

摘要: 對于偏軟體的程式員,時常對指令的亂序執行,寄存器重命名,超标量處理器,等名詞感到疑惑。本文将對這些知識進行初步介紹,為你解開這些疑惑。本文是我閱讀Computer Architecture- A Quantitative Approach的學習筆記,文章中在原書例子的基礎上,加上了我自己的一些了解。寫作本文的目的是學習的總結和備忘,同時與愛好者進行交流,是以錯誤之處,期待各位斧正。

由于本書主要以MIPS為目标平台進行介紹的,是以例子也是MIPS彙編代碼,但是熟悉X86彙編的朋友也不用擔心,在文章開頭,我特别對幾條彙編指令進行了解釋,相信彙編文法不會成為你閱讀本文的障礙。

單一流水線結構在遇到資源沖突和資料依賴時,比較停滞流水線,直到依賴被解除。例如:

時鐘周期
指令 1 2 3 4 5 6 7 8 9
DADD R1, R2, R3 取指 譯碼 執行 回寫
DSUB R4, R1, R5 取指 Stall Stall 譯碼 執行 回寫
AND R6, R5, R7 取指 Stall Stall 譯碼 執行 回寫
......

在這種情況下,由于第二條指令的依賴關系,緻使第三條及後續指令受到“無辜”的牽連。我們可以通過編譯器在編譯期進行依賴性檢查,把指令調整為下面這個樣子:

DADD R1, R2, R2
AND R6, R5, R7
......
DSUB R4, R1, R5
......
      

但是編譯器取得的效果有限,為了進一步挖掘指令“重疊”執行的潛力,當沒有依賴的情況下,我們希望指令按下列方式進入流水線:

時鐘周期
指令 1 2 3 4 5 6 7 8 9
DADD R1, R2, R3 取指 譯碼 執行 回寫
DSUB R4, R1, R5 取指 Stall Stall 譯碼 執行 回寫
AND R6, R5, R7 取指 譯碼 執行 回寫
......

從上面可以看出,第三條指令先于第二條指令結束,我們把它稱為亂序執行(Out-of-order execution)。亂序執行的關鍵是要求指令排程單元能夠動态檢測指令的依賴關系,又被稱為指令相關性,為了進一步介紹亂序執行的相關算法,我們先來對相關性進行總結和分類。

  • 資料相關性(Data Dependences)

    資料相關性可以細分為三類:真實資料相關性,名字相關性,控制相關性

  • 真實資料相關性(True Data Dependences)

    指令i産生一個結果,後續指令j使用該結果作為輸入操作數,被稱為指令j依賴于指令i。如果指令k依賴于指令i,同時指令j又依賴于指令k,那麼同樣可以得到指令j依賴于指令i。例如下面的例子:

    L.D F0, 0(R1)
    	; 源操作數寄存器 F0 依賴于前一條指令
    	ADD.D F4, F0, F2
    	; 源操作數寄存器 F4 依賴于前一條指令
    	S.D F4, 0(R1)
          
  • 名字相關性(Name Dependences) 名字相關性可以進一步細分為反相關性(Antidependence)和輸出相關性(Output Dependence)。
  • 反相關性(Antidependence) 反相關性是指:指令i以某個寄存器作為源操作數時,後續指令j同時以該寄存器作為目的操作數。例如:
    S.D F4, 0(R1)
    	DADDUI R1, R1, #8
          
    在這種情況下,如果在不加處理的進行亂序執行時,一旦第二條指令先回寫結果,第一條指令将得到錯誤的結果。
  • 輸出相關性(Output Dependence)

    指令i和後續指令j以同一個寄存器作為目的操作數。例如:

    S.D R4, 0(R1)
    	AND R4, R2, R3	
          

    在這種情況下,如果第二條指令先于第一條指令結束,那麼R4寄存器将得到錯誤的值。

    和真實資料相關性比較起來,在反相關性和輸出相關性中,指令與指令直接并不存在資料的傳遞,是以又被統稱為名字相關性,名字相關性并不是真正意義上的相關性。寄存器重命名(Register Renaming)是消除名字相關性的有效手段,寄存器重命名可以同編譯器來實作,也可以通過CPU硬體實作。考慮下面的代碼:

    DIV.D F0, F2, F4
    	ADD.D F6, F0, F8
    	S.D   F6, 0(R1)
    	SUB.D F8, F10, F14
    	MUL.D F6, F10, F8
          

    在這個例子中,ADD.D和SUB.D之間存在一個反相關性,ADD.D F6, F0, F8中,F8作為源操作數,而SUB.D F8, F10, F14中,F8作為目的操作數,如果SUB.D先執行完畢,則ADD.D得到錯誤的結果。

    ADD.D和MUL.D之間存在一個輸出相關性ADD.D F6, F0, F8中,F6是目的操作數,MUL.D F6, F10, F8中,F6也是目的操作數,如何MUL.D先執行完畢,之後ADD.D再執行,那麼F6寄存器中的值就是錯誤的。(注意ADD.D和S.D之間不存在輸出相關性,S.D中F6是源操作數,他們之間存在着真實資料相關性的關系,我們暫且不讨論。)

    對于反相關性,如果SUB.D回寫結果(到F8)時,ADD.D還沒有執行完畢(使用F8作為源操作數),那麼CPU會配置設定一個臨時的寄存器T1,把SUB.D的結果儲存到T1中,同樣在執行後續指令時,把F8替換為T1。于是在執行階段,上述指令變為:

    DIV.D F0, F2, F4
    	ADD.D F6, F0, F8    ; 滞後
    	S.D   F6, 0(R1)
    	SUB.D T1, F10, F14  ; 超前
    	MUL.D F6, F10, T1   ; 超前
          
    對于輸出相關性,如果MUL.D回寫結果時(到F6),ADD.D還沒有回寫結果到F6,那麼CPU會為ADD.D配置設定一個臨時的寄存器T2,于是代碼執行時,上述指令變為:
    DIV.D F0, F2, F4
    	ADD.D T2, F0, F8    ; 滞後
    	S.D   T2, 0(R1)     ; 滞後
    	SUB.D T1, F10, F14  ; 超前
    	MUL.D F6, F10, T1   ; 超前
          
    由于以上各種相關性的存在,如果不加處理的進行亂序執行,會出現以下“資料冒險”(Data Hazards),在下面的讨論中,假設指令j是指令i的後續指令。
  • RAW (Read After Write)

    指令i以某個寄存器作為目的操作數,在指令i完成寫入操作前,指令j讀該寄存器進行讀取操作。例如:

    ; 如果第二條指令先執行,F0中的值是錯誤的。
    	DIV.D F0, F2, F4
    	ADD.D F6, F0, F8
          
  • WAW(Write After Write)

    指令i和指令j同時以同一個寄存器作為目的操作數。例如:

    ; 如果第二條指令先執行,之後F0中的值是“舊”的。
    	DIV.D F0, F2, F4
    	ADD.D F0, F1, F8
          
  • WAR(Write After Read)

    指令i以某一個寄存器作為源操作數,後續指令j以同一寄存器作為目的操作數,在指令i讀操作數之前,指令j完成對目的寄存器的寫入操作。例如:

    ; 如果第二條指令先執行,第一條指令會出錯。
    	DIV.D F0, F2, F4
    	ADD.D F4, F1, F8
          
  • 控制相關性(Control Dependences)

    控制相關性主要由條件轉移引起的,例如:

    DADDU R2, R3, R4
    	BEQZ  R2, L1
    	LW    R1, 0(R2)
    L1:
    	......
          

    在這個例子中BEQZ的運作結果出來之前,LW不能執行。在亂序執行的CPU中,可以通過轉移預測解決控制相關性。

    亂序執行可以分為按序發射-無序完成(In-Order Issue, Out-Of-Order Completion),無序發射-無序完成(Out-Of-Order Issue, Out-Of-Order Completion)。無論哪一種方式,都需要CPU在執行過程中,決策各條指令的執行時機,是以又被稱為指令動态排程,或者動态動态派遣(Dynamic Scheduling)。下面我們先來看按序發射-無序完成(In-Order Issue, Out-Of-Order Completion)的具體例子。

  • 按序發射-無序完成(In-Order Issue, Out-Of-Order Completion) 首選我們來看看按序發射-無序完成帶來的好處,假設加法操作占用2個時鐘周期,乘法操作占用10個時鐘周期,除法操作占用40個時鐘周期。下列指令的流水操作情況:
    時鐘周期
    指令 1 2 3 4 6 ... 13 14 15
    MUL.D F0, F2, F4 取指 譯碼 執行 回寫
    SUB.D F8, F6, F2 取指 譯碼 執行 回寫
    SUB.D F8, F6, F2 取指 譯碼 執行
    在沒有資料相關性及資源沖突的情況下,無序完成可以使後續指令及早進入流水隊列,進而提高流水線的效率。
  • 基于Scoreboard的動态指令排程

    Scoreboard算法能夠在按序發射-無序完成的實作中,自動動檢測和消除相關性。在這一實作中,指令按照源二進制程式的順序發射到Scoreboard單元,Scoreboard有一個指令隊列,儲存譯碼後的指令,當Scoreboard檢測到某條指令可以執行時,就立刻排程該指令,而忽略它們的原始順序。在Scoreboard算法中,指令執行需要經過以下階段:

  • 發射(Issue)

    指令譯碼之後,根據指令的操作确定該條指令所需要的功能部件,如果目前功能部件是空閑的(保證了沒有資源沖突(Structural Hazards),并且目前處于執行階段的指令中(可能存在多條指令亂序執行),沒有任何一條指令的目的操作數(寫入對象)與目前待發射指令的目的操作數相同(保證了不會導緻WAW冒險(輸出相關性)。),就把譯碼後的指令送出到Scoreboard指令隊列,更新Scoreboard的相關資料結構。否則停止發射,在這種情況下,如果取指隊列還沒有滿,取指工作會繼續。

  • 讀操作數(Read Operands)

    Scoreboard監視到指令隊列中的每一個源操作數寄存器,如果沒有任何一條處于運作階段(多條指令)的指令對該寄存器進行寫入,或者寫入操作已經完成時,Scoredboard通知相關功能單元,可以為該條指令讀取源操作數。在這個過程中,Scoreboard保證了目前讀取到的源操作數是最新的,消除了RAW冒險的可能。

  • 執行(Execution)

    源操作數準備就緒之後,進入執行階段,不同的功能部件的執行時間可能不一緻,當執行完成後,會通知Scoreboard.

  • 回寫(Write Result)

    當Scoreboard接到執行單元的執行完畢的通知之後,Scoreboard檢測回寫的目标寄存器目前某條指令的源寄存器一緻,并且該條指令還沒有完成讀源操作數(消除WAR冒險)。例如:

    DIV.D F0,  F2, F4
    	ADD.D F10, F0, F8
    	SUB.D F8,  F8, F14
          

    在SUB.D回寫結果之前,如果ADD.D還沒有完成對操作數,則SUB.D必須等待,如果不存在WAR冒險,或者冒險已經消除,Scoreboard通知相關單元進行回寫操作。

    為了完成以上檢測,Scoreboard需要維護3張表格,分别是指令狀态,功能部件狀态,以及寄存器狀态。其中指令狀态表格如下所示:

    指令狀态(Instruction Status)
    指令(Instruction) 發射(Issue) 讀操作數(Read Operands) 執行完畢(Execution Complete) 回寫(Write Result)
    L.D F6, 34(R2) Y Y Y Y
    L.D F2, 45(R3) Y Y Y
    MUL.D F0, F2, F4 Y
    SUB.D F8, F6, F2 Y
    DIV.D F10, F0, F6 Y
    ADD.D F6, F8, F2
    Scoreboard在這個表中記錄已發射指令的狀态。功能部件狀态表如下所示:
    功能部件狀态(Functional Unit Status)
    Name Busy Op Fi Fj Fk Qj Qk Rj Rk
    Integer Yes Load F2 R3 No
    Mult1 Yes Mult F0 F2 F4 Integer No Yes
    Mult2 No
    Add Yes Sub F8 F6 F2 Integer Yes No
    Divide Yes Div F10 F0 F6 Mult1 No Yes
    每一條已發射的指令都在這個表中有一條對應的記錄。其中各個字段的意義如下:
  • Functional Unit Name 表示一個功能部件,例如Integer表示整數運算單元,Mult1表示第一個乘法器,Add表示加法器(注意SUB指令實際上使用加法器。),Divide表示除法器等等。
  • Busy 表示該功能部件是否空閑。
  • Fi 表示該條指令對應的目的操作寄存器。
  • Fj, Fk 表示指令對應的源操作寄存器。
  • Qj, Qk 當源操作數沒有就緒時,Qj, Qk分别記錄哪一個功能部件為該條指令計算Fj, Fk.
  • Rj, Rk 用于訓示Fj, Fk已經準備就緒,但是Fj, Fk讀源操作數還沒有完成時,對應的Rj, Rk為Yes,如果Fj, Fk沒有準備就緒,或者讀操作數已經完成,則Rj, Rk為No,是以(在有兩個源操作數的情況下)當Fj, Fk都為Yes時,可以進行讀操作數。

    由于字段比較多,我們舉兩個例子來說明這個表格是如何填寫的。例如在上面指令狀态表中的MUL.D F0, F2, F4指令已經發射,在功能部件狀态表中的第二項(和指令順序沒有關系)Name為Mult1表示目前有一條指令要使用乘法器1,同時Busy字段為Yes;Op字段為Mult,表示要進行乘法操作;Fi為F0,表示該條指令的目的操作數為F0;Fj, Fk分别為F2, F4表示兩個源操作數;Qj為Integer表示目前這條指令的源操作數Fj從一個整數運算部件的輸出擷取(F2來自L.D F2, 45(R3),整數運算部件用于計算45+R3);Qk為空,表示另外一個源操作數F4已經就緒; Rj為No,表示第一個源操作數(F2)還沒有準備就緒,Rk為Yes,表示第二個源操作數(F4)已經準備就緒,當Rj和Rk都為Yes後,可以進行讀操作數。

    Scoreboard的第三個表是Register Result Status表:

    寄存器狀态(Register Result Status)
    F0 F2 F4 F6 F8 F10 F12 ... F30
    Functional Unit Mult1 Integer Add Divide

    Register Result Status用于訓示哪一個功能部件将要把結果回寫到哪一個寄存器。例如上面的例子中,F0為Mult1,表示有一條指令以F0為目的操作寄存器,将來會寫F0.(對應MUL.D F0, F2, F4).

    在上面這個例子中,由于沒有空閑的功能單元,是以最後一條指令不能發射。由于第三條(MUL.D),第四條指令(SUB.D)的源操作寄存器(F2)是第二條指令(L.D)的目的操作寄存器(RAW),是以不能進行讀操作數,同樣第五條指令(DIV.D)的源操作寄存器(F0)是第三條指令(MUL.D)的目的操作數,是以不能讀操作數。

    為了進一步說明Scoreboard的具體操作過程,假設加法操作占用2個時鐘周期,乘法操作占用10個時鐘周期,除法操作占用40個時鐘周期。下一步假設L.D操作已經完成,是以Scoreboard的狀态變成下面這個樣子。

    第二條指令(L.D)回寫已經完成,Integer部件變成空閑狀态。第六條指令(ADD)因為沒有空閑的加法器,依然不能發射,此時如果第七條指令使用Integer部件,也不能發射,是以被稱為按序發射。

    第三(MUL.D),第四(SUB.D)條指令可以讀操作數。是以Scoreboard的狀态如下:

    指令狀态(Instruction Status)
    指令(Instruction) 發射(Issue) 讀操作數(Read Operands) 執行完畢(Execution Complete) 回寫(Write Result)
    L.D F6, 34(R2) Y Y Y Y
    L.D F2, 45(R3) Y Y Y Y
    MUL.D F0, F2, F4 Y Y
    SUB.D F8, F6, F2 Y Y
    DIV.D F10, F0, F6 Y
    ADD.D F6, F8, F2
    功能部件狀态(Functional Unit Status)
    Name Busy Op Fi Fj Fk Qj Qk Rj Rk
    Integer No
    Mult1 Yes Mult F0 F2 F4 No No
    Mult2 No
    Add Yes Sub F8 F6 F2 No No
    Divide Yes Div F10 F0 F6 Mult1 No Yes
    由于第二條指令的寫入已經完成,是以寄存器狀态表變為:
    寄存器狀态(Register Result Status)
    F0 F2 F4 F6 F8 F10 F12 ... F30
    Functional Unit Mult1 Add Divide

    讀操作數完成後,第二(MUL.D),第三(SUB.D)條指令同時開始執行,兩個時鐘周期後,第三條指令(SUB.D)執行完畢,Scoreboard開始做如下檢查:

    回寫的目标寄存器目前某條指令的源寄存器一緻,并且該條指令還沒有完成讀源操作數(消除WAR冒險)

    這個條件并不滿足,是以回寫可以順利進行,假設回寫占用1個時鐘周期,此時第二條指令(MUL.D)沒有結束。這時加法器已經空閑,是以第六條指令(ADD.D)可發射,發射後,由于沒有任何一個指令會對該指令的兩個源操作數(F8, F2)進行寫人,是以第六條指令可以立即完成讀源操作數的步驟。Scoreboard狀态如下:

    指令狀态(Instruction Status)
    指令(Instruction) 發射(Issue) 讀操作數(Read Operands) 執行完畢(Execution Complete) 回寫(Write Result)
    L.D F6, 34(R2) Y Y Y Y
    L.D F2, 45(R3) Y Y Y Y
    MUL.D F0, F2, F4 Y Y
    SUB.D F8, F6, F2 Y Y Y Y
    DIV.D F10, F0, F6 Y
    ADD.D F6, F8, F2 Y Y
    功能部件狀态(Functional Unit Status)
    Name Busy Op Fi Fj Fk Qj Qk Rj Rk
    Integer No
    Mult1 Yes Mult F0 F2 F4 No No
    Mult2 No
    Add Yes ADD F6 F8 F2 No No
    Divide Yes Div F10 F0 F6 Mult1 No Yes
    寄存器狀态(Register Result Status)
    F0 F2 F4 F6 F8 F10 F12 ... F30
    Functional Unit Mult1 F6 Divide
    從上面我們可以看出,第4條指令(SUB.D)在第三條指令之前完成,是以稱為無序完成。當第三條指令(MUL.D)完成時,此前第六條指令(ADD.D)也已經完成,但是因為其目的操作數為F6,而第五條指令(DIV.D)還沒有讀源操作數,是以第六條指令(ADD.D)不能進行回寫操作。Scoreboard的狀态如下:
    指令狀态(Instruction Status)
    指令(Instruction) 發射(Issue) 讀操作數(Read Operands) 執行完畢(Execution Complete) 回寫(Write Result)
    L.D F6, 34(R2) Y Y Y Y
    L.D F2, 45(R3) Y Y Y Y
    MUL.D F0, F2, F4 Y Y Y
    SUB.D F8, F6, F2 Y Y Y Y
    DIV.D F10, F0, F6 Y
    ADD.D F6, F8, F2 Y Y Y
    功能部件狀态(Functional Unit Status)
    Name Busy Op Fi Fj Fk Qj Qk Rj Rk
    Integer No
    Mult1 Yes Mult F0 F2 F4 No No
    Mult2 No
    Add Yes ADD F6 F8 F2 No No
    Divide Yes Div F10 F0 Add Mult1 No Yes
    寄存器狀态(Register Result Status)
    F0 F2 F4 F6 F8 F10 F12 ... F30
    Functional Unit Mult1 Add Divide
    通過以上讨論,我們可以看到, Scoreboard存在以下缺點:
  • 按序發射可能會導緻某個功能部件“長期”空閑,例如在上面的例子中,當Integer部件空閑時,由于資源沖突第六條指令(ADD.D)不能發射,如果後續指令正好是一條要使用Integer部件的指令,就可以通過提前發射該條指令來進一步提高性能。為此提出了無序發射-無序完成(Out-Of-Order Issue, Out-Of-Order Completion)的方法。無序發射-無序完成為譯碼單元設定專門的緩沖器,進而形成一個譯碼後的指令隊列,通過随時檢測該隊列,一旦某條指令所需的功能部件空閑就立即發射。假設上面的例子中,最後一條指令(ADD.D)之後是一條需要使用Integer部件的指令,則該指令可在ADD.D之前發射。
  • 對于所有的資料冒險(Data Hazards),RAW, WAR, WAW都一律通過等待的方式來避免,例如在當第六條指令ADD.D F6, F8, F2執行結束時,而第五條指令DIV.D F10, F0, F6由于等待F0的結果,是以還沒有讀源操作數,為了消除這個WAR冒險(F6),是以ADD.D回寫(F6)操作被推遲,進而導緻加法器不能及時的變成空閑狀态。為此提出了寄存器重命名的方法。通過寄存器重命名(Register Renaming)可以在避免額外等待的同時消除WAR和WAW的資料冒險。
  • Tomasulo算法

    Tomasulo算法是另外一個按序發射-無序完成的實作,它采用寄存器重命名(Register Renaming)來消除WAR和WAW類型的資料冒險。Tomasulo算法和Scoreboard非常類似,它也有3個表,分别是指令狀态(Instruction Status)表,保留棧(Reservation Stations),和寄存器狀态(Register Status),其中保留棧的作用和Scoreboard中的功能部件狀态(Functional Unit Status)類似。各個表的内容如下所示:

    指令狀态(Instruction Status)
    指令(Instruction) 發射(Issue) 執行完畢(Execut) 回寫(Write Result)
    L.D F6, 34(R2) Y Y Y
    L.D F2, 45(R3) Y Y Y
    MUL.D F0, F2, F4 Y Y
    SUB.D F8, F6, F2 Y Y Y
    DIV.D F10, F0, F6 Y
    ADD.D F6, F8, F2 Y Y Y
    和Scoreboard相比較,Tomasulo的指令狀态表省去了讀操作數的狀态。在這裡我們看到第五條指令(DIV.D)之前,第六條指令(ADD.D)已經完成了回寫操作,由于采用了寄存器重命名,消除他們之間的WAR冒險(R6),是以ADD.D可以提前進行回寫操作。
    保留棧(Reservation Stations)
    Name Busy Op Vj Vk Qj Qk A
    Load1 No
    Load2 No
    Add1 No
    Add2 No
    Add3 No
    Mult1 Yes Mult Mem[45+Regs[R3]] Regs[F4]
    Mult2 Yes DIV Mem[34+Regs[R2]] Mult1
    保留棧中,各個字段的意義如下:
  • Name 所需的功能部件。
  • 訓示保留棧和對應的功能部件是否空閑。
  • Op 指令中的具體操作。
  • Qj, Qk 保留棧中,哪一條指令将為該條指令産生源操作數。當Qj, Qk為0時,表示源操作數已經準備好,儲存在Vj, Vk中,或者不需要某個源操作數。
  • Vj, Vk 操作數的實際值,對于每一個操作數,當Qj, Qk非0時,表示操作數還沒準備好,此時Vj, Vk為0,同時Qj, Qk指向産生該操作數的指令。對于Load指令,Vj儲存基址寄存器的值,Vk儲存偏移量。
  • A 用來為Load/Store指令儲存位址資訊,初始化時,儲存立即數(偏移量),當位址計算出來後,儲存基址+偏移的計算結果。

    這個表是實作寄存器重命名的關鍵,在上面的例子中,DIV.D F10, F0, F6這條指令的源操作數,F6已經準備好,是以Vk儲存F6的實際值(這裡記做Mem[34+Regs[R2]]。),但是F0還沒有準備好,還在等待MUL.D F0, F2, F4回寫結果,是以Qj為Mult1,表示Vj這個源操作數将由乘法器Mult1産生,當Mult1回寫結果時,把這個結果在公共資料總線(Common Data Bus)上廣播,每一個部件都能看到這個結果,保留棧中每一條等待該結果的指令會更新這個結果。

    從上面的分析中可以看出,在DIV.D F10, F0, F6還沒有執行時,ADD.D F6, F8, F2就可以把計算結果回寫到F6中。

    寄存器狀态(Register Result Status)
    F0 F2 F4 F6 F8 F10 F12 ... F30
    Field Mult1 Mult2
    現在,再來看在Tomasulo算法中,指令的執行過程就簡單的多了(略去了取指令和指令譯碼的步驟。):
  • 發射(Issue) 擷取下一條指令,如果保留棧(Reservation Station)中有比對的空閑項目(消除了 Structural Hazard),就把改指令送出到保留棧中,并且更新相關資料結構。如果源操作數已經就緒,就把它讀到保留棧的Vj, Vk中,如果還沒有就緒,就在Qj, Qk中記錄将産生源操作數的部件。這個步驟被稱為寄存器重命名(Register Renaming),消除了WAR和WAW.
  • 執行(Execute) 如果源操作數沒有就緒,就監視通用資料總線(Common Data Bus),,将來如果某個部件完成運算時,會把結果廣播到通用資料總線(Common Data Bus)上,這時可以更新Vj, Vk,并開始執行。通過等待源操作數就緒後才開始執行,消除了RAW類型的資料冒險。
  • 回寫(Write Result) 計算完成時,把通用資料總線上的結果回寫到目标寄存器,以及相應的保留棧中。和Scoreboard比較起來,通過寄存器重命名來消除了WAR和WAR類型的資料冒險,是以回寫操作無需等待。

    最後我們來看看超級流水線和超标量的差別。

  • 超級流水線超級流水線是對普通流水線的進一步細分,例如把取指令分為兩個或者更多的流水步驟,Pentium4的流水級數超過20級。
  • 超标量在亂序執行的基礎上,超标量處理器擁有多條互相獨立的流水線,它們同時取指令,亂序執行。例如,我們在龍芯2F的參數中看到的4發射,這裡的4發射是指有4條流水線,一個周期能夠發射4條指令。

來源:http://www.osplay.org/modules/article/view.article.php/15/c9

繼續閱讀