原始流水線
先放一張原始的MIPS流水線圖,圖片來自雷思磊的《自己動手寫CPU》
目前流水線是按順序執行,沒有加入跳轉語句的數據通路,假設我們在執行階段才知道比較跳轉指令beq需要跳轉,那麼此時已經在取指、譯碼的兩條指令會無效,下一個時鐘週期需要把它們清空,於是流水線出現兩個週期的氣泡。跳轉前的狀態如下:
······
beq $t1,$t2,label #執行階段
ori $3,$3,0x8 #譯碼階段,下一刻清空
ori $3,$3,0x9 #取指階段,下一刻清空
······
label:
or $4,$9,$0 #下一刻取指
······
改進方案
爲了提高流水線的效率,避免氣泡,MIPS的架構做了兩個改進:
1、分支指令的判斷提前到譯碼階段,一部分比較邏輯在譯碼時完成,而不用等到執行階段。這樣可以少一個氣泡。
2、索性不清空取指階段指令,讓它繼續執行,反正下一個指令是跳轉指令,只要有個標記知道它是“多出”的指令,稱爲“延遲槽指令”。所以把轉移指令後面的指令位置稱爲“延遲槽”。這樣流水線就沒有氣泡了。
如果指令不跳轉,那麼正好執行下一條;如果跳轉指令不久又跳回來,那麼從原來跳轉指令下兩條開始執行,比如上面的ori $3,$3,0x9
,如果不跳回來,那麼相當於白運算了一次,總體上看,還是很划算的。修改後的跳轉前狀態:
······
beq $t1,$t2,label #譯碼階段就可判斷
ori $3,$3,0x8 #取指階段,下一刻譯碼
ori $3,$3,0x9 #如果跳回來,這裏開始取指
······
label:
or $4,$9,$0 #下一刻取指
······
增加的數據通路
具體實現增加的數據通路如下:
細節還得參看verilog代碼,先有個大概輪廓吧。