cpu流水線上,若後一條指令獲取數據必須是前一條實時生成值,此時cpu流水線是否失效?解決辦法?


用bypass解決。國內的教科書上可能把這個叫做數據轉發或者數據前遞。

不過在實際長流水線裡面,經常做不到無縫銜接,要stall幾個周期才能拿到bypass回來的數據,當然這比stall整個流水線或者直接replay要好多了。


在這裡我們考慮最簡單的五級流水線:取指(M),解碼(ID),執行(IE),訪存(M),寫回(WB)。

這個問題需要分兩種情況來考慮:

1. 非訪存指令i更改寄存器x的值,指令i+1,i+2或者i+3 (i+n表示指令i後的第n條指令) 讀寄存器x。 在這種情況下,如果指令i沒有更新寄存器x,對於流水線後面需要讀x的指令,我們需要設計專門的電路 (forwarding circuit 或者叫 bypassing circuit) 來實現提前讀取x的值。

2. 如果指令i需要從內存中讀取內容,並存入寄存器x中,而指令i+1或者i+2需要讀取寄存器。在這種情況下,指令i沒有完成訪存周期之前,我們無法知道寄存器x中會被存入什麼值,所以不能提前讀取x的值。因此,我們只有暫停 (stall) 流水線中指令i+1或者i+2的執行,直到指令i完成訪存 操作。然後通過forwarding circuit 來獲取x的值。


當然不一定。以最簡單的MIPS五級流水來說,上一條指令通過ALU計算的結果可以直接送給下一條指令的ALU,不必等到結果寫回階段,可以做到無縫銜接。


I486 擁有五級流水線。分別是:取指,解碼,轉址,執行,寫回。

如果執行下面的代碼.

XOR a, b
XOR b, a
XOR a, b

第一步是第一條指令進入取指階段;然後在第二步第一條指令進入解碼階段,同時第二條指令進入取指階段;第三步第一條指令進入轉址階段,第二條指令進入解碼階段,第三條指令進入取指階段。但是在第四步會出現問題,第一條指令會進入執行階段,而其他指令卻不能繼續向前移動。第二條 xor 指令需要第一條 xor 指令計算的結果a,但是直到第一條指令執行完成才會寫回。所以流水線的其他指令就會在當前流水級等待直到第一條指令的執行和寫回階段完成。第二條指令會等待第一條指令完成才能進入流水線下一級,同樣第三條指令也要等待第二條指令完成。

這個現象被稱為流水線阻塞或者流水線氣泡。

於是後來就出現了亂序執行流水線.這個解釋起來有點長.百度很詳.


不是的,結果可以直通。不過有些情況下還是得暫停一兩個周期的流水。具體細節忘記了,回家去看書再答。


以一個典型的MIPS五級流水線為例,共有ID(取指令)REG(指令解碼/訪問寄存器堆)EX(執行)MEM(訪問內存)WB(寫回)

在《計算機組成與技術:軟體/硬體介面》上有一段實例代碼:

sub $2, $1, $3
and $12, $2, $5
or $13, $6, $2
add $14, $2, $2
sw $15, 100($2)

在例子中,後面四條指令都依賴於第一條指令計算出的$2的結果,因此就存在數據冒險。
由於$2的更新是在EX之後,因此主要的數據冒險存在於EX,MEMWB過程。


最簡單的過程在於WB,即如果WB階段寫回的寄存器和Reg階段訪問的是同一個寄存器,那麼一個簡單的辦法就是,在時鐘周期的前半段執行寄存器的寫操作,在寄存器的後半段執行寄存器的讀操作,這樣就可以保證讀出來的數據是最新的數據。

對於EXMEM階段,就需要數據轉發(forwarding)

例子中的轉發如下圖:

由於EX階段是第三個時鐘周期結束時產生結果,因此在這個結果產生之後,將它轉發給需要它的指令就可以了。
對於轉發,主要的問題是要檢測相關性。

在MIPS中,I型指令和R型指令是不同的

對於R型指令,格式為

ALUFunc(6),rs(5),rt(5),rd(5),shamt(5),Func(6)

對於I型指令,格式為

ALUFunc(6), rt(5),rs(5),imm(16)

因此對於這兩種指令,R型指令的結果對應的是rd,I型的指令的結果對應的是rt。因此要檢測相關性,兩者檢測的寄存器是不同的。

並且對於R型指令,相關性包含了兩類相關性,即

  • 1類

EX/MEM.RegisterRd == ID/EX.RegisterRt
EX/MEM.RegisterRd == ID/EX.RegisterRs

  • 2類

MEM/WB.RegisterRd == ID/EX.RegisterRt
MEM/WB.RegisterRd == ID/EX.RegisterRs

對於I型指令,對應的相關性為

EX/MEM.RegisterRt == ID/EX.RegisterRt
MEM/WB.RegisterRt == ID/EX.RegisterRs

在此基礎上,就是數據轉發的策略。數據轉發是用單獨的寄存器,而並非使用流水線寄存器,同時要產生對應的控制信號。然後通過在ALU的數據通路中加入多路寄存器來選擇數據,控制信號是多路選擇器的輸入。

類似的結構為:

此外,對於lw指令,當lw指令的寫入寄存器和它的下一條指令的讀取寄存器是同一個寄存器時,轉發就不能正常的工作,因為lw只有在MEM之後才能有正確的結果。

這個時候就需要通過一個模塊,來監控這種過程,一旦發生這種過程,就需要在lw之後阻塞流水線,保證lw指令得到了正確結果後,在將它進行轉發。

通常對於lw指令的阻塞,插入nop指令可以解決,因此對應的流水線的過程變成下圖:

一個完整的包含轉發和冒險檢測的設計如下圖:

這些都是最簡單的5級流水線,並且沒有考慮Cache的命中等各方面的問題,現實中的流水線往往冒險檢測模塊也更加複雜,相關性檢測也更多。

參考資料和插圖來自於 《計算機組成與技術:軟體/硬體介面》


可以用stalling和forwarding解決。

-------------------------------------------------------------

更一下:

stalling會造成吞吐量下降。所以一般更傾向於使用forwarding,但有時候forward過來的數據會銜接不上,這時stalling和forwarding就需要結合起來使用。

只學過入門級別的體系結構課程,不知道有沒有其它的方法。


數據轉發啊。什麼?還有stall?不是有OOO嗎?還不行?那再加個SMT吧。還有問題?做編譯器的同學拉兄弟一把吧。。。


推薦閱讀:

如何看待有些人認為計算機專業是「拿命換錢」?
電腦開機密碼怎麼解密?
直接拔除通過 USB 連接的移動硬碟究竟會對硬碟造成什麼損害?
Windows 系統筆記本到手之後需要做哪些工作?

TAG:中央處理器CPU | 計算機 | 流水線 |