《大話處理器》連載——微架構(7) 流水線上的冒險——資料冒險
(2) 資料冒險
流水線使原先有先後順序的指令同時處理,當出現某些指令的組合時,可能會導致指令使用了錯誤的資料。
看下面這個例子:
暫存器訪問的資料冒險
add R1,R2,R3將暫存器R2和R3的和賦給R1,add R4,R1,R5將暫存器R1和R5的和賦給R4,很明顯,R1在第1條指令中被更新,然後在第2條指令中使用,可是R1必須在第5個cycle之後才被更新,而指令2再第4個cycle就要訪問R1,這時的R1還不是正確的值,執行結果出錯。
一種解決方法是在這2條語句之間增加2個cycle的等待:
通過增加等待來消除資料冒險
延時2個cycle,cycle 5將第1條指令的結果寫回到暫存器R1中後,第2個add指令的EX單元就可以正常執行了。
這種方法很大一個缺點就是中間增加了2個cycle的等待,影響了執行效率。實際的處理器使用直通(Forwarding)來解決這個問題。
當硬體檢測到當前指令的源運算元正好在EX/MEM流水線暫存器中時,就直接將EX/MEM暫存器的值傳遞給ALU的輸入,而不是從暫存器堆中讀資料,如圖:
使用Forwarding,解決資料冒險
不只暫存器訪問有這樣的問題,Memory訪問也有同樣的問題。看下面這個例子:
Memory訪問的資料冒險
load R1,(R2)將儲存器中的值裝載到R1中來,儲存器的地址在R2中儲存,store R1,(R3) 將R1中的值放到儲存器中去。在cycle 4,load指令的MEM階段將儲存器中的值裝載到MEM/WB暫存器中,在cycle 5,load指令的WB階段將MEM/WB暫存器的值裝載到暫存器R1中,而在cycle 5,store指令的MEM要將暫存器R1的值放到儲存器中去,R1的值還沒有被load指令更新。這個資料冒險的解決方法可以延時1個週期,也可以採用同樣的Forwarding方法,將MEM/WB暫存器直通到MEM輸入端。
使用Forwarding,解決資料冒險
也不是每種資料冒險都能解決,同時又不引起stall,例如下面這個例子:
仍然需要stall的直通示例
sub指令需要R1,但是R1最早也要在cycle 4才到MEM/WB暫存器中,即使將MEM/WB暫存器直通到EX的輸入端,也需要延時一個cycle才能使用。