Visual walkthrough — Hazard detection units
5.2.10 · D2· Hardware › Processor Datapath & Pipelining › Hazard detection units
Step 1 — Pipeline ko ek row mein paanch rooms ki tarah draw karo
KYA HAI. Ek pipelined processor ek bada machine nahi hai jo sab kuch ek saath kare. Yeh ek hallway hai jisme paanch rooms hain, aur har instruction left se right chalti hai, har clock tick pe ek room.
Paanch rooms, order mein:
- IF — Instruction Fetch: memory se agla instruction leke aao.
- ID — Instruction Decode: instruction padho, uske zaroorat ke register numbers dhundho.
- EX — Execute: ALU mein arithmetic karo (calculator).
- MEM — Memory: data memory se baat karo (sirf loads/stores ko yeh room chahiye).
- WB — Write Back: final result register file mein likho (CPU ka scratchpad jisme
$1,$2jaise named boxes hain).
YEH PAANCH HI KYUN, CHAAR YA CHHE KYUN NAHI? Har room ek kism ka kaam karta hai, toh clock fast tick kar sakta hai: jab room EX instruction A crunch kar raha hai, room ID already instruction B decode kar sakta hai. Paanch instructions ek saath "in flight" ho sakti hain — yahi pipeline ka poora point hai.
PICTURE. Paanch labelled rooms, aur ek single instruction jo paanch clock ticks mein unke through chalti dikhti hai (diagonal).
Step 2 — Hallway mein ek saath do instructions daalo
KYA HAI. Ab do instructions daalo, ek doosre ke bilkul peeche:
lw $2, 20($1) ; I1: load - memory se ek number box $2 mein fetch karo
add $4, $2, $5 ; I2: $2 ko input ke roop mein chahiyeKyunki yeh ek tick ke antar se enter hote hain, kisi bhi moment pe yeh adjacent rooms mein baithe hote hain. Jab I2 (add) ID mein decode ho raha hota hai, I1 (lw) ek room aage EX mein hota hai.
YEH PAIRING KYUN MATTER KARTI HAI. I2 box $2 mein value chahiye. Lekin box $2 exactly wohi hai jo I1 bana raha hai (load $2 mein likhta hai, uska Rd*). Yeh ek read-after-write (RAW) dependency hai: I2 wohi read karta hai jo I1 write karta hai. Agar I2 box $2 read kare I1 ke likhne se pehle, toh I2 ek stale (purana, galat) number read karta hai.
PICTURE. Dono instructions room-timeline pe overlap kiye gaye; ek red bracket us cycle ko highlight karta hai jahan add ID mein hai jabki lw EX mein hai.
Recall
Dangerous cycle mein lw aur add kaun se do rooms mein hain? ::: lw EX mein hai, add ID mein hai.
Step 3 — Har number actually ready kab hota hai?
KYA HAI. Sab kuch ki key ek timeline hai — kab answer physically exist karta hai. Register file mein write hone ka time nahi — jab bits pehli baar wire pe aate hain.
Pehle, notation ka ek chota tukda taaki formula saaf padhay:
- Ek arithmetic instruction jaise
addke liye: ALU EX ke end mein finish hota hai. Tohready(ALU op)= end of EX. - Ek load (
lw) ke liye: number memory se aata hai, aur memory MEM room hai. Yeh MEM ke end tak exist nahi karta — poore ek room baad. Tohready(load)= end of MEM.
YEH EK FACT KYUN POORA PAGE DECIDE KARTA HAI. Sab kuch downstream ek race hai "data kab appear karta hai?" aur "consumer ko yeh kab chahiye?" ke beech. Load ka data ALU result se ek room baad appear karta hai. Yeh yaad rakho.
PICTURE. Do horizontal "data-ready" timelines: ek add ke liye (ready at end of EX), ek lw ke liye (ready at end of MEM, ek column daayein marked).
Step 4 — Forwarding: shortcut wire jo usually hume bachata hai
KYA HAI. Normally hum WB ka wait nahi karte. Hum ek forwarding wire (bypass bhi kehte hain) lagate hain jo result ko jis moment woh exist karta hai utha leta hai aur seedha waiting instruction ke ALU inputs ko de deta hai. Yeh kaam forwarding unit ka hai — aur yahan sab kuch hai jo aapko ek sentence mein jaanna chahiye: yeh ek chota logic block hai jo, har cycle mein, check karta hai ki koi result jo already EX/MEM ya MEM/WB latch mein baitha hai woh register match karta hai kya jo ek executing instruction chahti hai, aur agar haan toh ek mux flip karta hai taaki woh result seedha ALU mein jaaye stale register-file value ki jagah.
Do shortcut wires exist karte hain, har ek Step 1 ke latches mein se ek tap karta hai:
- EX/MEM → EX: ek result lao jo abhi-abhi ALU finish hua hai (ab EX/MEM latch mein baitha hai) aur agali instruction ke ALU ko do.
- MEM/WB → EX: ek result lao jo MEM/WB latch mein baitha hai (write back hone wala hai) aur ALU ko do.
add-phir-add ke liye yeh kyun kaam karta hai. Agar I1 ek add hai, uska answer EX ke end mein exist karta hai aur EX/MEM latch mein land karta hai. Bilkul agale cycle mein I2 ko iske EX ke start mein chahiye. EX/MEM → EX wire ise just in time deliver karta hai. Koi stall nahi.
PICTURE. Ek add (I1) EX mein, uska result orange EX/MEM forwarding wire ke along curve karke add (I2) ke ALU inputs mein wapas jaata hai jo EX mein enter kar raha hai. Timing line up hoti hai.
Step 5 — Dekho shortcut LOAD ke liye FAIL karta hai
KYA HAI. Ab I1 ke add ko apne lw se replace karo. Same EX/MEM → EX shortcut use karne ki koshish karo. Timing line up karo:
- I2 (
add) ko apne EX ke start mein$2chahiye — jo same cycle hai jablwMEM mein hai. - Lekin
lwka data MEM ke end tak exist nahi karta.
Toh jis instant add ko number chahiye, load ne abhi usse fetch nahi kiya. Shortcut wire garbage carry karega — ek empty value, kyunki memory ne abhi jawab nahi diya.
YEH FASTER WIRE SE KYUN PATCH NAHI HO SAKTA. Aap data backwards in time forward nahi kar sakte. Consumer ko ek cycle ke start mein chahiye; producer usi cycle ke end mein finish karta hai. Koi wire nahi hai jo future deliver kare. Yeh ek timing impossibility hai, koi wiring oversight nahi.
PICTURE. Same forwarding attempt jaise Step 4, lekin ab source lw MEM mein hai; ek red X wire pe mark karta hai kyunki data end-of-MEM pe appear hota hai jabki add ko start-of-EX pe chahiye — ek arrow jo left (backwards in time) point karta hai crossed out.
Step 6 — Ilaaj: exactly EK bubble insert karo
KYA HAI. Agar hum add ko ek cycle peeche push karein, dekho kya hota hai: ab jab add finally EX tak pahunchta hai, lw MEM/WB tak move kar chuka hai. Uska data ab exist karta hai (end of MEM already ho chuka) aur MEM/WB → EX wire use perfectly deliver karta hai.
One-cycle delay ek bubble insert karke create hota hai — ek fake do-nothing instruction (ek NOP) jo EX mein ek tick occupy karta hai taaki real add ID mein wait kare.
Cycle-by-cycle:
| Cycle | IF | ID | EX | MEM | WB |
|---|---|---|---|---|---|
| 1 | lw |
– | – | – | – |
| 2 | add |
lw |
– | – | – |
| 3 | add |
NOP | lw |
– | – |
| 4 | … | add |
NOP | lw |
– |
| 5 | … | … | add |
NOP | lw |
Notice karo ki add IF column mein cycle 2 aur cycle 3 dono mein appear karta hai. Yeh typo nahi hai: kyunki stall PCWrite = 0 drive karta hai (Step 7), program counter frozen ho jaata hai, toh cycle 3 mein IF room simply usi add ko re-fetch karta hai jo usne cycle 2 mein fetch kiya tha — freeze lift hone tak jaane ki jagah nahi hai. add effectively IF aur ID ke across hold in place rehti hai.
Cycle 5 mein add EX mein hai aur lw MEM/WB mein hai — forwarding ab kaam karta hai, forwarding unit ki wajah se.
EXACTLY EK BUBBLE KYUN, DO KYUN NAHI? Ready-times ke beech gap exactly ek room tha (Step 3). Ek bubble exactly ek room ka gap close karta hai. Zyada cycle waste karega; kam enough nahi hoga.
PICTURE. Corrected timeline: add ek extra cycle ke liye ID mein frozen, ek gray NOP bubble EX se slide karta, aur cycle 5 mein green MEM/WB → EX forwarding arrow succeed karta.
Step 7 — Kaun se knobs bubble create karte hain?
KYA HAI. Pipeline ko ek cycle ke liye freeze karne ke liye hazard unit teen control signals ko 0 pe flip karta hai. Yeh pipeline control signals hain:
PCWrite = 0— program counter freeze karo, taaki IF ek nayi instruction pe advance na kare (woh usi ko re-fetch karta hai, jaise hum Step 6 mein dekh chuke hain).IF/ID_Write = 0— IF/ID register freeze karo, taakiaddID mein ruke aur agale cycle mein retry kare.Control_Mux = 0— mux (Step 4 ka selector switch) use karo taaki ID/EX mein jaane wale saare control signals zero ho jayein, outgoing instruction ko NOP mein badal do.
TEENO SAATH KYUN?
PCWrite=0ke bina, IF ek nayi instruction pe advance ho jaata jise rakhne ki jagah nahi hoti.IF/ID_Write=0ke bina,addaage slip ho jaati aur stale$2read kar leti.Control_Mux=0ke bina, woh instruction jo EX mein enter hone wali thi fir bhi act karti — state corrupt karti instead of innocent bubble banne ke.
PICTURE. Datapath jisme teen freeze-lines highlight ki hain (PCWrite on the PC, IF/ID_Write on the IF/ID latch, Control_Mux ID/EX mein zeros force karta), har ek apne effect ke saath labelled.
Recall
Control_Mux = 0 kya accomplish karta hai? ::: Yeh mux use karta hai ID/EX mein saare control signals zero karne ke liye, toh ID se nikalne wali instruction ek harmless NOP (bubble) ban jaati hai instead of execute karne ke.
Step 8 — Detection condition term by term likhna
KYA HAI. Hazard unit ID mein baithta hai aur stall tab fire karta hai sirf jab load-use pattern present ho. Formula se pehle, do symbols earn karne hote hain:
Ab exact test, Step 1 ke pipeline-register fields aur Rd* convention use karke:
Term by term:
- (a)
ID/EX.MemRead— woh instruction jo currently EX mein hai ek load hai (uska MemRead flag, ID/EX latch mein carried, 1 hai). Yeh sirf woh case hai jahan data forward karne ke liye bahut late appear karta hai (Step 5). ID/EX.Rd*— destination register jise load fill kar raha hai (e.g.$2). Step 1 se yaad rakho ki load ke liye yeh physically uske Rt field se aata hai, lekin hum ise uniformlyRd*kehte hain.IF/ID.Rs/IF/ID.Rt— woh instruction ke do source register numbers jo currently ID mein hai (potential victim), IF/ID latch mein carried.- (b) (c) — agar load ka target kisi bhi input se match kare, yeh instruction load pe depend karti hai. Ek match enough hai.
- (AND) — dono sides hold karni chahiye: load hona chahiye aur register match karna chahiye. Ek ordinary
addproducer (MemRead = 0) (a) mein fail hota hai aur isliye kabhi stall nahi karta.
ID MEIN TEST KYUN KARO? ID sabse pehla room hai jahan hum jaante hain kaunse register numbers read ho rahe hain. Yahan pakadna humein pehle stall karne deta hai galat data ever use hone se.
PICTURE. Detection logic gates ke roop mein drawn: MemRead ek AND mein, do equality comparators ek OR mein, AND ko feed karte, output = Stall — example values $2 flow karte hue Stall = 1 banane ke liye.
Step 9 — Edge cases jo aap kabhi skip nahi kar sakte
Har condition mein corner cases chhupe hote hain. Yeh rahe, har ek apni reasoning ke saath:
- Register
$0. MIPS mein$0zero pe hardwired hai aur kabhi write nahi kiya ja sakta. Agar ek load$0ko "target" kare (anokha lekin legal), koi stall needed nahi — kuch real change nahi hota. Real hardware AND mein extra guardID/EX.Rd* ≠ 0add karta hai, toh$0destination kabhi stall trigger nahi kar sakta. Is guard ke bina aap bekar stall karte. - Sirf ek register match karta hai, ya koi nahi. Step 8 ka (OR) "Rs pe match, Rt pe, ya dono pe" handle karta hai. Agar koi bhi match nahi karta, AND false hai → koi stall nahi, bhale hi ek load EX mein ho. Independence respect ki jaati hai.
- Producer ek
addhai, load nahi (MemRead = 0). Term (a) false hai → koi stall nahi. Forwarding unit silently handle karta hai. Hazard unit raste se hat jaata hai. - Load ke baad ek
store(lwphirsw). Ek store jaisesw $2, 0($6)$2read karta hai (apne Rt ke zariye) use memory ko bhejne ke liye. Lekin ek store apna data MEM room mein consume karta hai, EX mein nahi — ek room baad ekaddse zyada. Jab tak store MEM tak pahunche, load ki value already MEM/WB mein hai, toh ek MEM/WB → MEM store-data forward cover karta hai: koi stall nahi. Address register ($6, uska Rs), jo EX mein read hota hai, fir bhi stall karega agar woh load pe depend karta hai — toh Step 8 ka Rs check stores pe bhi apply hota hai. - Do-instruction gap (
lw, phir kuch, phir user). Agar load aur uske consumer ke beech ek alag instruction hai, jab tak consumer ID tak pahunche tab tak load already MEM/WB mein hai — forwarding cover karta hai, koi stall nahi. Step 8 ki condition naturally sirf immediately following instruction check karti hai (ID vs ID/EX), toh yeh yahan correctly silent rehti hai. - Load ke baad branch target (
lwphirbeq). Ek branch jo early resolve hota hai apne do source registers ko ID mein rehte hue compare karta hai — same room jahan load-use test rehta hai. Toh ekbeqjo woh register read kare jise pichlelwne fill kiya, exactly yeh stall trigger karta hai (uske Rs/Rt kisi bhi doosre consumer ki tarah check kiye jaate hain), aur kyunki branches ko apne inputsaddse bhi pehle chahiye, kuch designs yahan do cycles stall karte hain. Load-use test ko sirf arithmetic pe apply samjhne ki galti mat karo; yeh kisi bhi cheez pe apply hota hai jo ID mein Rs ya Rt read kare. Alag "branch kaun si direction mein jaayega?" problem control-flow ki hai, branch prediction aur control unit pe defer ki gayi hai. - Ek control (branch) hazard alag cheez hai. Jab "agla instruction kaun sa?" unknown ho, hum flush karte hain stall ki jagah. Woh kahani branch prediction mein hai.
PICTURE. Ek chota decision fan: left pe input pattern, right pe kai branches, har ek STALL ya NO-STALL mein khatam hota ek-line reason ke saath.
Ek-picture summary
Sab kuch ek race mein collapse hota hai: load ka data bilkul agali instruction ke liye ek room bahut late ready hota hai, toh hum us instruction ko ek bubble se delay karte hain, jiske baad forwarding kaam karta hai.
Recall Feynman retelling — ise ek story ki tarah batao
Instructions paanch rooms mein march karti hain: fetch, decode, execute, memory, write-back. Har do rooms ke beech ek chota latch hota hai — ek pipeline register (IF/ID, ID/EX, EX/MEM, MEM/WB) — jo instruction ke register numbers aur control flags aage carry karta hai. Ek add apna answer execute room chhodne par complete karta hai aur use EX/MEM latch mein drop karta hai, toh ek shortcut wire (mux se chosen) woh answer bilkul time pe agali instruction ke ALU input ko de sakta hai. Lekin ek load apna answer memory room se laata hai — ek room baad. Toh jab bilkul agali instruction execute tak pahunchti hai, load ne number abhi fetch nahi kiya; shortcut garbage carry karta, aur aap data backwards in time nahi bhej sakte. Ilaaj ek single stall hai: program counter freeze karo (taaki fetch same instruction wapas pakad le) aur fetch/decode latch, aur ek empty "do-nothing" instruction execute mein slip karo. Yeh one-cycle delay exactly kaafi hai load ke write-back latch tak pahunchne ke liye, jahan forwarding wire ab pahunch sakta hai. Decode room mein logic ka ek chota piece tell-tale pattern watch karta hai — "execute mein instruction ek load hai (MemRead = 1), aur woh register jise woh fill karta hai (uska Rd*) wohi hai jo main read karne wala hoon (Rs ya Rt)" — aur sirf tab stall lever kheenchta hai, provided woh register hardwired $0 na ho. Yeh kisi bhi cheez ke liye fire karta hai jo ID mein Rs ya Rt read kare, branches bhi; store ki data-only dependence aur koi bhi do-instruction gap akela chhod deta hai, kyunki forwarding ne woh pehle se cover kar rakhe hain.