4.1.20 · D4Computer Architecture (Deep)

Exercises — Hazard mitigation — stalling, forwarding - bypassing, branch prediction

2,790 words13 min readBack to topic

This page assumes the parent topic and its prerequisites: Pipelining basics — 5-stage MIPS, Datapath and control signals, Amdahl's Law and CPI analysis, and Compiler instruction scheduling. We reuse the same 5 stages throughout:

Figure — Hazard mitigation — stalling, forwarding - bypassing, branch prediction

Read the figure above like a calendar: each row is one instruction, each column is one clock cycle. An instruction sits in a later stage as we move right. A forward is only legal when the arrow points rightward-or-straight-down in time — you can send a value to a cycle that is the same or later, never to a cycle already gone.


Level 1 — Recognition

Problem L1.1

Classify each situation as structural, data (RAW), or control hazard. (a) Two instructions both want the single memory port in the same cycle. (b) add $t1,$t0,$s1 follows lw $t0,0($s0) and needs $t0. (c) The pipeline fetched 2 instructions after a beq before knowing if the branch is taken.

Recall Solution L1.1

(a) Structural — two instructions demand the same hardware (one memory port) at once. (b) Data hazard (RAW)add reads $t0 that lw will write; specifically the load-use flavour. (c) Control hazard — the next PC is unknown until the branch resolves. Why: structural = hardware clash, data = value-not-ready, control = which-PC-unknown. Match the cause, not the symptom.

Problem L1.2

In the classic MIPS pipeline, in which stage is a register value read, and in which stage is an ALU result written back?

Recall Solution L1.2

Registers are read in ID. Results are written back in WB. Why it matters: the gap between "read in ID" and "written in WB" is exactly the window where a RAW hazard can bite — the reader can arrive before the writer finishes.

Problem L1.3

True/False: forwarding can eliminate the stall in a lw → immediate-use pair.

Recall Solution L1.3

False. The load's value is born at the end of MEM (cycle 4 for the load), but the consumer needs it at the start of EX (cycle 3 of the pipeline timeline) — one cycle earlier in absolute time. Forwarding moves data forward in time only, so it cannot help. At least 1 stall remains.


Level 2 — Application

Problem L2.1

Draw the pipeline timeline (stage per cycle) for:

lw  $t0, 0($s0)
add $t1, $t0, $s2

with full forwarding available. How many bubbles?

Recall Solution L2.1
cyc 1 2 3 4 5 6
lw IF ID EX MEM WB
add IF ID bubble EX MEM WB

1 bubble. lw's value exists only at the end of MEM (cycle 4). add must be in EX no earlier than cycle 4, so it holds in ID for one extra cycle. Then the MEM/WB value is forwarded into add's EX. See the figure — this is a legal forward (rightward in time), unlike the illegal one from cycle 4 → cycle 3.

Problem L2.2

Same timeline but for:

sub $t0, $s1, $s2
add $t1, $t0, $s3

with full forwarding. How many bubbles, and which latch supplies the forwarded value?

Recall Solution L2.2

0 bubbles.

cyc 1 2 3 4 5
sub IF ID EX MEM WB
add IF ID EX MEM WB

At cycle 4, add is in EX and sub is in MEM, so $t0 sits in the EX/MEM latch. Forward EX/MEM → ALU input A. An ALU producer's value is ready one cycle earlier than a load's, so no stall is needed.

Problem L2.3

A program: b = 0.20 of instructions are branches, misprediction penalty p = 3. Compute effective CPI (ideal = 1) for (a) always-flush (m = 1) and (b) a predictor with m = 0.08.

Recall Solution L2.3

Formula: . (a) . (b) . Why: each branch pays only when mispredicted (probability ); branches are a fraction of all instructions, so multiply the probabilities and add to the ideal 1.


Level 3 — Analysis

Problem L3.1

Trace a 2-bit saturating predictor (states 00,01,10,11; predict Taken if top bit = 1) starting at 00 (strong-NT) through this actual outcome sequence: T, T, T, NT, T, T. List predictions and count mispredictions.

Recall Solution L3.1

Rule: predict T if state ≥ 10. Taken → increment (cap 11); Not-taken → decrement (floor 00).

# state before predict actual correct? state after
1 00 NT T 01
2 01 NT T 10
3 10 T T 11
4 11 T NT 10
5 10 T T 11
6 11 T T 11

Mispredictions = 3 (the two warm-up misses, plus the single NT anomaly). Crucially, the lone NT at step 4 did not flip the long-run guess — the counter only dropped from 11 to 10, still "predict T". That is the hysteresis 2 bits buys you.

Problem L3.2

For the same sequence T, T, T, NT, T, T, a 1-bit predictor (predict = last outcome) starting from "predict NT". Count mispredictions and compare to L3.1.

Recall Solution L3.2

1-bit: predict whatever happened last time.

# predict actual correct?
1 NT T
2 T T
3 T T
4 T NT
5 NT T
6 T T

1-bit mispredictions = 3. Here they tie on this short trace, but note the pattern of failure: the 1-bit predictor mispredicts twice around the single NT (step 4 exit and step 5 re-entry), whereas the 2-bit predictor only paid for the exit and immediately recovered on step 5. On a longer loop the 2-bit predictor wins because it costs ~1 miss per loop-exit instead of ~2.

Problem L3.3

A loop branch is Taken 99 times then Not-Taken once (exit), repeated for many iterations. What is the steady-state misprediction rate for a 2-bit predictor vs a 1-bit predictor? Assume the counter is warmed up.

Recall Solution L3.3

Per 100-outcome loop:

  • 2-bit: the counter sits at 11 (strong-T). The single NT on exit is a miss and drops it to 10; the very next T is still predicted correctly (top bit still 1) and pushes back to 11. So 1 miss per 100.
  • 1-bit: the exit NT is a miss (predicted T), and it flips the predictor to "NT"; the next iteration's first T is then also a miss (predicted NT), flipping it back. So 2 misses per 100. Why the 2-bit halves it: the hysteresis absorbs the single anomaly without changing the long-run prediction — exactly the point of a second bit.

Level 4 — Synthesis

Problem L4.1

A workload: 20% loads, of which 40% are immediately followed by a dependent use (load-use, 1 bubble each). Branches are 15% of instructions with predictor m = 0.05, penalty p = 2. Forwarding handles all ALU RAW hazards for free. Compute effective CPI.

Recall Solution L4.1

Build CPI as ideal + each independent penalty source (they don't overlap here):

  • Load-use stalls: fraction of instructions that stall = , each costs 1 cycle → .
  • Branch mispredicts: . Why add them: each hazard type independently injects bubbles; total stall-cycles-per-instruction is the sum of the per-source expected stalls. See Amdahl's Law and CPI analysis for the general additive-overhead model.

Problem L4.2

A compiler can reorder an independent instruction into each load-use slot, hiding all load-use stalls. Using L4.1's numbers, what is the new CPI, and what speedup does scheduling give over the un-scheduled version?

Recall Solution L4.2

With load-use hidden, only branch penalty remains: Speedup (≈ 7.9% faster). Why: removing stall-cycles/instr shrinks the divisor. Same clock, same instruction count, fewer wasted cycles → higher throughput.


Level 5 — Mastery

Problem L5.1

Design/defend. A colleague proposes: "Widen the register-file write to happen in the first half of a clock cycle and register reads in the second half (write-before-read within WB/ID). Does this remove the need for the MEM-hazard forward (2-instructions-ahead)?" Justify with a timeline.

Recall Solution L5.1

Yes — that specific forward becomes unnecessary. The MEM-hazard case is a producer that reaches WB in the same cycle the consumer is in ID:

cyc 3 4 5
producer EX MEM WB (writes 1st half)
consumer IF ID (reads 2nd half)

If WB writes in the first half of cycle 5 and ID reads in the second half of cycle 5, the register file already holds the new value when the consumer reads — no wire needed. This is the classic "write in first half, read in second half" trick. But the closer EX-hazard (1-ahead) still needs forwarding: there the producer is only in MEM (not WB) when the consumer is in EX, so the value isn't in the register file yet. Conclusion: split-cycle register access removes the 2-ahead forward but not the 1-ahead forward, and not the load-use stall.

Problem L5.2

Prove a bound. Show that with full ALU forwarding and split-cycle registers, the only remaining single-instruction-gap RAW stall in the classic 5-stage pipeline is the load-use case. (Argue by where each producer's value is born vs where a consumer needs it.)

Recall Solution L5.2

A consumer needs its operand at the start of EX. List producers by when their result is born:

  • ALU op (add,sub,…): result born end of EX. The immediately-following instruction is in EX exactly one cycle later, so the value (in EX/MEM) can be forwarded → no stall. ✓
  • 2-ahead producer: reaches WB while consumer is in ID; split-cycle register access delivers it → no stall, no forward. ✓
  • Load (lw): result born end of MEM — one cycle later than an ALU result. The immediately-following consumer would need it in EX before it exists. No forward can reach into the past → ≥1 stall is forced. ✗ Every producer either delivers in time (ALU, 2-ahead) or is a load. Therefore the load-use hazard is the unique unavoidable single-gap stall. ∎ Why this is the deep point: stalls aren't arbitrary — they are exactly the cases where "value born" is later in absolute time than "value needed." Everything else is a wiring problem, solvable by a mux.

Problem L5.3

Synthesis with out-of-order thinking. Explain in one paragraph why forwarding (a static, in-order technique) and Tomasulo's tag-broadcast are the same idea at different scales.

Recall Solution L5.3

Both replace "wait for the value to travel through the register file" with "deliver the value the moment it is computed, tagged so only the waiters that need it grab it." In-order forwarding is a fixed set of wires (EX/MEM and MEM/WB latches → ALU inputs) governed by the RegWrite/rd comparisons. Tomasulo generalizes this to a common data bus: any functional unit broadcasts its result with a tag, and every reservation station watching that tag latches the value simultaneously — forwarding to an arbitrary number of consumers, out of program order. Forwarding is Tomasulo with a hard-wired, 1-or-2-deep forwarding network; Tomasulo is forwarding scaled to a dynamic, associative broadcast. See also Caches and memory hierarchy for how memory-side latency reshapes when values are "born."


Recall One-line self-check

Load-use minimum bubbles with full forwarding? ::: 1 CPI overhead formula for branches? ::: Which forward does split-cycle register access eliminate? ::: the 2-instructions-ahead (MEM/WB → ID) one Steady-state loop-exit misprediction: 1-bit vs 2-bit? ::: 2 misses vs 1 miss per loop