Pipeline Hazards & Their Fixes

A hazard is any situation that stops the next instruction from entering the pipeline on the next clock cycle. There are exactly three kinds — the exam loves “explain and exemplify a hazard, then give its solution.”

The three hazards at a glance
HazardCausePrimary fix
Structuraltwo instructions want the same hardware in the same cycleduplicate the resource
Dataan instruction needs a result not yet produced by an earlier oneforwarding, else stall
Controlthe next address depends on a branch still in the pipestall / predict / delayed branch

1. Structural hazard

Occurs when two instructions at different stages need the same hardware resource at the same time. The classic case: a machine with a single memory for both instructions and data. In one cycle instruction 4 wants to be fetched (IF) while instruction 1 wants to access data (MEM) — both hit the one memory.

CC1CC2CC3CC4CC5CC6CC7CC8lw $t0IFIDEXMEMWBinst 2IFIDEXMEMWBinst 3IFIDEXMEMWBinst 4IFIDEXMEMWB
Cycle 4 (ringed): lw needs MEM and instruction 4 needs IF — a single unified memory can't serve both.
Solution: provide separate resources — a split cache: an instruction memory (used by IF) and a data memory (used by MEM). Real MIPS does exactly this, so it has no structural hazard on memory. In general: duplicate the contended unit.

2. Data hazard

Occurs when an instruction needs a value that an earlier, still-executing instruction hasn't written back yet. Example — sub reads $s0, which add is still computing:

add $s0, $t0, $t1   # produces $s0 (ready only after its WB)
sub $t2, $s0, $t3   # needs $s0 in its EX stage

When sub reaches EX, add is only in MEM — it hasn't written $s0 to the register file yet. Reading the register now gives the old value.

Fix A — Forwarding (bypassing) · the preferred fix

The result actually exists the moment add finishes EX — it's sitting in the EX/MEM pipeline register. So route it directly from there into sub's ALU input, without waiting for WB. No stall needed.

CC1CC2CC3CC4CC5CC6add $s0,..IFIDEXMEMWBsub $t2,$s0IFIDEXMEMWB
Forwarding: add's EX result (CC3) is fed straight into sub's EX (CC4) via the EX/MEM register — zero stalls.

Fix B — Stall (bubble) · when forwarding can't help

A lw produces its value only after MEM, one stage later than an ALU op. If the very next instruction needs it, even forwarding is one cycle too late — so the pipeline must stall for one cycle (insert a “bubble”), then forward.

lw  $s0, 0($t1)    # value ready only after MEM
sub $t2, $s0, $t3  # needs $s0 in EX — one cycle too early
CC1CC2CC3CC4CC5CC6CC7lw $s0,..IFIDEXMEMWBsub $t2,$s0bubbleIFIDEXMEMWB
A load-use hazard: one bubble delays sub by a cycle so lw's MEM result can be forwarded in time.
A bubble is a wasted cycle — the pipeline did no useful work. Good compilers reorder instructions to fill the slot, and forwarding removes most other data hazards.

3. Control (branch) hazard

Occurs when the pipeline must fetch the next instruction before it knows whether a branch is taken. beq resolves its condition only in a later stage, but IF wants a new instruction on the very next cycle — which address should it fetch?

beq $t0, $t1, LABEL   # taken? not known yet
???                   # what do we fetch next cycle?
Solutions:
  • Stall — freeze IF until the branch resolves (simple, wastes cycles).
  • Branch prediction — guess (e.g. “not taken”), keep fetching; if wrong, flush the wrongly-fetched instructions and restart. Cheap when the guess is usually right.
  • Delayed branch — always execute the instruction right after the branch (the “branch delay slot”); the compiler puts something useful there.
Section checklist
  • Define each hazard in one line and give a concrete example.
  • Structural → duplicate the resource (split instruction/data memory).
  • Data → forward from a pipeline register; stall only for load-use.
  • Control → stall, predict, or delayed branch.