# Pipeline ## 1. Datapath Take MIPS as example: Split Single-cycle **MIPS** Datapath into 5 Steps 1. IF (instruction fetch) 2. ID (instruction decode and register file read) 3. EX (execution or address calculation) 4. MEM (data memory access) 5. WB (write back) <img src="https://hackmd.io/_uploads/HkNwE4u2C.png" width="80%"> ## 2. Pipeline hazard 資源衝突或指令之間的相互依賴,可能會導致指令執行錯誤或性能下降的情況 ### 2.1 Structure Hazard 不同 instruction 同時想去用同一資源,但該資源無法同時被多個 instruction 使用 <img src="https://hackmd.io/_uploads/H1ex0VEunA.png" width="60%"> - 解決方法 - 盡量讓每個 instruction 需要花的cycle 數差不多 - 每個 instruction 要在相同的 stage 用特定的 resource - 例子:add 在第四個 stage 就已經算完可以準備 write back 了,但因為要避免 structure hazard,需要在第五個 stage 才能 write back <img src="https://hackmd.io/_uploads/B1IkBVunC.png" width="60%"> ### 2.2 Data Hazard 指令之間存在依賴性,而 pipeline 中後續指令需要前面指令的運算結果時,就會出現 data hazard - 種類 1. True dependence → RAW (read after write) 其中一個指令需要讀取另一個指令寫入的資料 ```python 1. ADD R1, R2, R3 # R1=R2+R3 2. SUB R4, R1, R5 # R4=R1-R5 ``` 2. Anti-dependence → WAR (write after read) ```python 1. SUB R4, R1, R5 # R4=R1-R5 2. ADD R1, R2, R3 # R1=R2+R3 ``` 在out-of-order (OOO) processor, WAR 會有hazard 問題 3. Output dependence → WAW (write after write) ```python 1. ADD R1, R2, R3 # R1=R2+R3 2. SUB R1, R4, R5 # R1=R4-R5 ``` 在out-of-order (OOO) processor, WAW 會有hazard 問題 - 解決方法 - WAR, WAW 1. 確保 In-order execution 2. Register Renaming ```python 1. ADD R1, R2, R3 # R1=R2+R3 2. SUB R1, R4, R5 # R1=R4-R5 ↓ 1. ADD R6, R2, R3 # R6=R2+R3 2. SUB R7, R4, R5 # R7=R4-R5 ``` - RAW 1. Insert the NOPs (no operation) 2. Forwarding (不等到第一個指令將結果寫回,直接在第一個指令完成 Execution 時將結果傳送給第二個指令的 Execution Input,這樣會比較快拿到前一筆的結果) ex1: <img src="https://hackmd.io/_uploads/SkRLP4u30.png" width="100%"> r1 有 RAW 問題,所以前一指令計算的 output 一出來,就直接接到下一指令計算的 input Hardware architecture <img src="https://hackmd.io/_uploads/HkR9wN_3C.png" width="100%"> ex2: **forwarding沒辦法解決所有data hazard 問題** <img src="https://hackmd.io/_uploads/HJDTwN_h0.png" width="100%"> 3. Code Re-Ordering, use software to reschedule ### 2.3 Control Hazard 當遇到 branch or jump 指令時,program 的 execution path 可能改變,導致處理器在 branch decision 確定前取錯指令 - 例子: 在 cycle 4 才知道要不要 branch,可是如果要 branch 前面已經先讀了三個錯誤的 instruction 進來了 - 目標: 1. 決定 branch taken or not sooner 2. taken 的話,要能夠更快速的計算 branch address - 方法: 1. 都先當作沒有要 branch,等真的要 branch 再把之前讀錯的 flush 掉 2. 早點決定 branch taken 或 not taken 種類 1. predict branch always taken (並早點算出branch的address) 2. predict branch always not taken 3. dynamic branch prediction: 用 branch prediction buffer 來紀錄上一次是 taken(跳) 還是 not taken(沒跳) 3. make the stall cycle useful (找別的事情做)