Visual walkthrough — Data hazards and forwarding - bypassing
Step 1 — Two instructions, one shared register
WHAT. We line up two instructions where the second reads what the first writes.
ADD R1, R2, R3 # I1: put (R2 + R3) into R1
SUB R4, R1, R5 # I2: needs R1, then R4 = R1 - R5
WHY. Before we can fix anything, we must see the collision. The word data hazard just means: the reader arrives before the writer has finished. To make it concrete we need one producer (I1) and one consumer (I2) sharing register R1.
PICTURE. Each instruction is a train of five boxes — the five pipeline stages. Because the pipeline overlaps, I2 starts one clock after I1. Read the two rows as two trains one platform apart.

Step 2 — Mark the exact clock cycles of "produce" and "consume"
WHAT. We stamp a clock number onto the two moments that matter: when R1 is born and when R1 is needed.
WHY. A hazard is a timing problem, so we must measure it in cycles, not in vibes. Two questions:
- When is
R1's value produced? The ALU finishes it at the end of I1's EX stage. - When is
R1's value written to the register file? At the end of I1's WB stage — two cycles later. - When does I2 read
R1? During I2's ID stage.
PICTURE. The red dot is when the ALU produces R1 (end of EX, cycle 3). The blue dot is when I2 tries to read R1 from the register file (its ID, cycle 3). The purple dot is when R1 is actually stored in the register file (end of WB, cycle 5).

Look at the dots: I2 reads in cycle 3, but the value is not filed away until cycle 5. That is the gap.
Value read in cycle 3 vs. value stored in cycle 5 — so I2 grabs the OLD R1
Step 3 — Why "produced early" is the whole opportunity
WHAT. We notice something hopeful: R1 exists (end of EX, cycle 3) long before it is filed (end of WB, cycle 5).
WHY. The naive fix — stalling — makes I2 wait for the register file. But the register file is a slow middle-man. The result is already sitting on a wire at the ALU output the instant EX finishes. The tool we reach for is not "wait"; it is "re-route". Instead of produce → register file → read, we do produce → straight to the next ALU.
PICTURE. The long detour (grey, through the register file) versus the shortcut (mint, straight across). The shortcut is what "forwarding" literally is.

Step 4 — Where does the result physically wait? Pipeline registers
WHAT. We name the little latches between stages that hold a result for exactly one cycle: ID/EX, EX/MEM, MEM/WB.
WHY. To forward a value we must know which wire it lives on at the moment we need it. Between every pair of stages sits a pipeline register — a row of flip-flops that carries a stage's output into the next cycle. After I1 leaves EX, its ALU result does not vanish; it is parked in the EX/MEM register. One cycle later it slides into the MEM/WB register.
PICTURE. The datapath skeleton: four pipeline registers as vertical bars, the ALU in EX, and the register file in ID. The ALU output feeds the EX/MEM bar (labelled ALUOutput).

Step 5 — Case A: the 1-cycle-away neighbour (EX→EX forward)
WHAT. I2 directly follows I1. We forward from EX/MEM into I2's EX stage.
WHY. At the cycle when I2 is in EX and needs R1, where is I1's result? I1 is exactly one stage ahead — in MEM — so its ALU result sits in the EX/MEM register. That is the freshest copy. Grab it there.
PICTURE. Follow the mint arrow: it leaves the EX/MEM bar and lands on the top input of I2's ALU. The register file (blue) is bypassed entirely.

Step 6 — Case B: the 2-cycles-away producer (MEM→EX forward)
WHAT. An unrelated instruction sits between producer and consumer. We forward from MEM/WB instead.
ADD R1, R2, R3 # I1: produces R1
AND R6, R7, R8 # I2: does NOT use R1
SUB R4, R1, R5 # I3: needs R1, two behind I1
WHY. When I3 reaches EX, I1 has moved two stages further — it is now in WB, so its result lives in the MEM/WB register, not EX/MEM. Same idea, different pipeline register. Any producer three-or-more instructions back has already written the register file in time, so no forwarding is needed.
PICTURE. The coral arrow starts from the MEM/WB bar (one bar to the right of Step 5's source) and lands on I3's ALU input.

Step 7 — The tie-breaker: which copy when two match?
WHAT. When both EX/MEM and MEM/WB hold the same register number, we pick the newer one (EX/MEM).
WHY. Consider two writes to R1 before a read:
ADD R1, R2, R3 # I1: old R1
ADD R1, R6, R7 # I2: newer R1 ← this is the one I3 must see
SUB R4, R1, R5 # I3: reads R1
When I3 is in EX: I2's result is in EX/MEM (fresh), I1's result is in MEM/WB (stale). Program order says I3 must use the latest writer, I2. So EX/MEM wins.
PICTURE. Two arrows aim at I3's ALU. The mint one (EX/MEM, newer) is solid and chosen; the coral one (MEM/WB, older) is dashed and blocked by a small "×".

Two producers of R1 in flight — which does the consumer get?
Step 8 — The one case forwarding cannot save: the load-use hazard
WHAT. When the producer is a load (LW), its value isn't ready at end of EX — it arrives at end of MEM. One unavoidable stall remains.
LW R1, 0(R2) # value of R1 lands only at end of MEM
SUB R4, R1, R5 # needs R1 in its EX — one cycle too soon
WHY. For an ALU op the result exists after EX, so an EX→EX forward reaches the next instruction in time. A load has nothing to forward after EX — the data is still coming from memory. By the time it exists (end of MEM), the consumer's EX has already passed. Forwarding can shift the value sideways in time by zero cycles, not backwards. So we insert exactly one bubble, then forward from MEM/WB.
PICTURE. The load's value appears one box too late; a single grey bubble delays SUB by one cycle, after which the coral MEM/WB arrow can reach it.

Why can't forwarding fully cure a load-use hazard?
The one-picture summary
Everything above, compressed: the ALU result is born at the EX/MEM latch, ages into the MEM/WB latch, and a multiplexer at each ALU input picks the freshest available copy — EX/MEM first, then MEM/WB, else the register file — while a load forces a single bubble.

Recall Feynman retelling — say it like a story
Two instructions run nose-to-tail. The first one makes a number the instant its ALU fires, but the pipeline's rules say "don't file it into the register cabinet until three steps later." The second instruction, meanwhile, sprints up to the cabinet too early and would grab yesterday's number.
The trick is simple: don't send the number the long way through the cabinet at all. The number is already sitting on a wire — in the little holding latch right after the ALU (EX/MEM), or one latch further along (MEM/WB). So we run a shortcut wire from that latch straight to the second instruction's ALU. A small switch (the multiplexer) chooses: use the freshest latch if it has the number, else the older latch, else fall back to the cabinet.
If two earlier instructions both wrote the same register, we always take the newer one (EX/MEM), because that's whatever the cabinet would eventually hold. And there's one stubborn case — a load — where the number comes from memory and simply isn't ready until one step later than the ALU crowd; there we swallow exactly one wasted cycle, then forward as usual.
See also: control hazards handle a different kind of stall (branches), and superscalar / out-of-order machines generalise forwarding into full dependency networks.