Stanford's MIPS was announced in a 1982 paper as "a fast pipelined engine without pipeline interlocks", with "software solutions to several traditional hardware problems, such as providing pipeline interlocks": the compiler inserted the empty instructions you just counted. The commercial R2000 of 1985 was a five-stage pipeline much like this lesson's. Interlocks and forwarding came back everywhere: a compiler cannot know how deep tomorrow's pipeline will be.
When the line jams: hazards and forwarding
After this lesson you will take any short straight-line fragment, name its hazards, count the stall cycles with and without forwarding, and fill the cycle-by-cycle table the way an exercise expects — including the one stall that no wire can remove.
In 1982 a Stanford team called their processor MIPS: "Microprocessor without Interlocked Pipe Stages". The name was a design decision: the hardware had no stall logic at all. If an instruction needed a result the previous one had not finished, nothing stopped it from reading garbage — unless the compiler had put enough empty instructions in between.
The notes play compiler on page 25: sub x2, x1, x3, one nop, then and x12, x2, x5, "Now x2 is ready". It is not. Two questions for the next forty-five minutes: how many empty slots does that pair really need — and why does one extra wire bring the answer down to zero, for everything except a load?
Three ways a pipeline can jam
Lesson 1 ran the five-stage pipeline under two silent assumptions, spelled out by the notes on page 20: every instruction is independent of the others, and there are no branches or jumps. Drop either and the overlap stops being free. The word for what goes wrong is hazard.
Hazard — a situation in which overlapped execution would give a different result from executing the instructions one at a time, so the pipeline must either produce a wrong value or delay an instruction. The delay is a stall, also called a bubble: a cycle in which a stage does no useful work.
Each stall is a cycle in which no instruction completes — the reason the real CPI of a pipeline sits above 1 (lesson 3). Think of the assembly line as a laundry: washer, dryer, folding table, ironing board, closet, one load in each. Three things can jam it (notes, pages 20–21):
- Structural hazard — two instructions want the same hardware in the same cycle: one dryer, two loads. The notes' example: one memory for instructions and data, so the IF of one instruction collides with the MEM of another.
- Data hazard — an instruction needs a result an earlier one has not produced yet: the folding table waits for a shirt still in the dryer.
- Control hazard — the next instruction to fetch is unknown because a branch is undecided: which basket comes next depends on a decision nobody has made. This class waits for lesson 4.
Data hazards are this lesson. Here is the notes' example (page 21), written as the 2026 exam paper writes code — capital mnemonics, registers R1, R2 … and offset(Rbase) addressing (the 2024 and 2025 papers put a dollar sign in front of every register, $R1, $F2: same thing); the notes spell it lw x2, 0(x1) / add x3, x2, x4, and x2 is R2, register number 2.
I0 LD R2, 0(R1) # R2 = memory[R1 + 0]
I1 ADD R3, R2, R4 # needs R2
R2 exists only at the end of the load's ME stage and reaches the register file in WB; the add reads it in ID. The orange arrow is the RAW dependence pointing backwards in time. (ME = MEM, shortened to fit the cells.)Three orders of access, one of them real
Two instructions that touch the same register can collide in three orders, named after the order the accesses must keep; the "dependency analysis" table of Exercise 1 has a second name for each:
- RAW, read after write: the later instruction reads what the earlier one writes — a true data dependence, "RAW with I0 for R2" in the papers. This is Fig. 1.
- WAR, write after read: the later instruction writes a register the earlier one still has to read — an anti-dependence.
- WAW, write after write: both write the same register and the later value must win — an output dependence.
A fact the notes leave out and examiners like to ask: in the five-stage in-order pipeline only RAW can happen. Every instruction reads in ID and writes in WB, three stages later, and none overtakes another (Fig. 2).
WAR: ADD R4, R5, R6 reads R5 in C2, SUB R5, R7, R8 writes it in C6
WAW: SUB R2, R1, R3 and ADD R2, R7, R8 both write R2, in C5 and C6
Structural hazards are absent for a different reason: they were designed away. The datapath of lesson 1 has separate instruction and data memories, a register file with two read ports and one write port, and its own adder for PC + 4, so no two stages compete for a resource. The notes turn this into a slogan that is too strong (red pen below). The papers never make the slogan; what they state, as a machine assumption of every VLIW exercise of 2024–2026, is one of those design decisions: "in the Register File, it is possible to read and write at the same address at the same clock cycle" — the split-cycle register file of the next section.
One more thing an examiner likes to ask: which classes can hardware remove for good? Structural hazards, yes — duplicate the resource and they are gone. Data hazards it can only reduce: forwarding takes most of the stalls, and this lesson ends with the one it cannot take. Control hazards it can only guess around: prediction, lessons 4–6.
In the five-stage in-order pipeline only two things can go wrong: a RAW dependence and a branch. Everything else was designed away.
The distance rule: what a RAW costs without forwarding
Start with the plain machine: no forwarding, but one cheap trick in the register file that every exam paper assumes. The notes describe it on page 22: the register file is written in the first half of the clock cycle and read in the second half, so an instruction in WB and one in ID exchange a value within the same cycle. This is the split-cycle register file — the "read and write at the same address at the same clock cycle" of the exam texts.
Example 2 of the notes, cycle by cycle
Now put the consumer right behind the producer — Example 2 of the notes (page 23), the pair of every exercise of this kind:
I0 SUB R2, R1, R3 # R2 = R1 - R3
I1 AND R12, R2, R5 # needs R2 at once
Walk it. Cycle 3: SUB is in EX computing R2; AND is in ID and wants R2, but the register file still holds the old value. Cycle 4: SUB is in MEM, R2 sits in the EX/MEM pipeline register; AND is held in ID. Cycle 5: SUB writes R2 in the first half of the cycle, AND reads it in the second half and moves to EX in cycle 6. Two cycles lost. The table is the form of every such exercise: a row per instruction, a column per clock cycle.
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
I0 SUB R2, R1, R3 | IF | ID | EX | MEM | WB | |||
I1 AND R12, R2, R5 | IF | ID | stall | stall | EX | MEM | WB |
The example generalises into a rule the notes never state but all their tables obey. Call \(d\) the distance from producer to consumer: \(d = 1\) for the very next instruction, \(d = 2\) with one instruction between them, and so on.
-
Clock the producer. Fetched in cycle \(t\), it goes through IF, ID, EX, MEM, WB in cycles \(t, t+1, t+2, t+3, t+4\); its result enters the register file in WB:
\[ \text{write} = t + 4 . \] -
The consumer is \(d\) instructions later: fetched in cycle \(t + d\), it reads its registers in ID in cycle \(t + d + 1\) if nothing holds it.
-
Hold it \(s\) cycles in ID; the read happens in cycle \(t + d + 1 + s\). With the split-cycle register file a read in the same cycle as the write sees the new value, so
\[ t + d + 1 + s \ge t + 4 . \] -
Solve for \(s\); a stall count cannot be negative:
\[ s = \max(0,\ 3 - d) . \]\(d = 1\): two stalls (Example 2). \(d = 2\): one. \(d = 3\): none — the I1 to I4 pair of Fig. 3.
-
Without the split-cycle file the read must come strictly after the write, \(t + d + 1 + s \ge t + 5\), so \(s = \max(0,\ 4 - d)\): one more stall at distances 1 to 3. That is what the papers' assumption line saves you.
- \(d\)
- distance in instructions from the producer to the consumer (1 = the next instruction)
- \(3\)
- the stages between the read in ID and the write in WB
A load obeys the same rule without forwarding: its value also reaches the register file in WB. Loads and ALU instructions part ways only once forwarding exists.
A stall freezes everything behind it
The two-row table hides one thing: when an instruction is held in ID, the instruction behind it cannot enter ID and is held in IF, and everything further back waits too. The notes' Figure 9 (page 26) has five instructions that all read R2 after SUB writes it. Recomputed:
I0 SUB R2, R1, R3
I1 AND R12, R2, R5 # d = 1: 2 stalls
I2 OR R13, R6, R2 # d = 2, held in IF behind I1: 0
I3 ADD R14, R2, R2 # d = 3: 0
I4 SD R15, 100(R2) # d = 4: 0
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
I0 SUB R2, R1, R3 | IF | ID | EX | MEM | WB | ||||||
I1 AND R12, R2, R5 | IF | ID | stall | stall | EX | MEM | WB | ||||
I2 OR R13, R6, R2 | IF | IF | IF | ID | EX | MEM | WB | ||||
I3 ADD R14, R2, R2 | IF | ID | EX | MEM | WB | ||||||
I4 SD R15, 100(R2) | IF | ID | EX | MEM | WB |
Only I1 pays: by the time I2 reaches ID in cycle 6 the write is done, and I3 and I4 are later still. By hand, work row by row with one rule — an instruction enters a stage only in the cycle after the one ahead of it has left that stage — and I1's stalls push I2 along by themselves. The total is the cycle of the last WB: 11 = 5 instructions + 4 cycles of fill + 2 stalls, the formula sheet's \(\text{cycles} = IC + 4 + \text{stalls}\); lesson 3 turns it into CPI and seconds.
Forwarding: one wire and one comparison
Look at Example 2 again. R2 is computed at the end of cycle 3 and sits, finished, in the EX/MEM pipeline register during cycle 4 — exactly the cycle in which AND would like to execute. The two stalls carry an existing value through MEM, WB and back out of the register file. Forwarding (the notes also say bypassing) adds a wire from the pipeline register straight to the ALU input, and a multiplexer that chooses between the register-file value and the wire.
SUB enters the ALU of AND one cycle later, and the stalls are gone.The three paths, in the names the course uses
The notes name each path by the stage the value comes from and the stage it goes to (pages 23–24). All three take the value from a pipeline register, never from the register file:
- EX/EX path — from the EX/MEM register (the previous ALU result) to the ALU input. Serves an ALU producer at distance 1: Example 2, 0 stalls.
- MEM/EX path — from the MEM/WB register to the ALU input. Serves an ALU producer at distance 2, when the value has moved one register further, and — the case the notes' Figure 6 draws while their text names only the first — a load, whose value is born in MEM and only ever exists in MEM/WB. Name the wire by its ends, not by one use.
- MEM/MEM path — from the MEM/WB register to the write-data input of the data memory. Serves a load followed by a store of the loaded value: the store needs the data only in its MEM stage, exactly when the load's data sits in MEM/WB (the notes' Figure 7).
Store data from an ALU producer, and the base register of a load or store, go through the same ALU-input multiplexers, so EX/EX and MEM/EX cover them too. With forwarding, Example 2 shrinks to the notes' second table:
AND takes R2 from EX/MEM (EX/EX path).| 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|
I0 SUB R2, R1, R3 | IF | ID | EX | MEM | WB | |
I1 AND R12, R2, R5 | IF | ID | EX | MEM | WB |
| 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|
I0 LD R2, 0(R1) | IF | ID | EX | MEM | WB | |
I1 SD R2, 8(R1) | IF | ID | EX | MEM | WB |
What the forwarding unit actually does
Figure 8 of the notes (page 24) is Patterson and Hennessy's forwarding datapath, and it gives away the secret: forwarding is a comparison of register numbers. When an instruction was decoded in ID, its source numbers rs1 and rs2 were copied into ID/EX; the two instructions ahead of it carry their destination number rd in EX/MEM and MEM/WB. The forwarding unit compares them while the instruction is in EX and sets the multiplexers. In the textbook's words (background from the book, not in the notes), for the first ALU input:
EX hazard:
if EX/MEM.RegWrite and EX/MEM.rd != R0
and EX/MEM.rd == ID/EX.rs1
then ForwardA = EX/MEM # EX/EX path
MEM hazard:
if MEM/WB.RegWrite and MEM/WB.rd != R0
and MEM/WB.rd == ID/EX.rs1
and not (EX hazard on rs1)
then ForwardA = MEM/WB # MEM/EX path
Two details matter. The clause "not EX hazard" gives priority to the newest result: in ADD R1, R1, R2 / ADD R1, R1, R3 / ADD R1, R1, R4 both older instructions match R1, and the third add must take the second one's value, in EX/MEM. And R0 is excluded because it is hard-wired to zero: an instruction that "writes" R0 forwards nothing.
The table collects what forwarding buys, read as the exam reads it: producer, consumer, distance.
| Producer → use | \(d = 1\) no fwd. | \(d = 1\) fwd. | \(d = 2\) fwd. | \(d \ge 3\) |
|---|---|---|---|---|
| ALU → operand, address, store data | 2 | 0 (EX/EX) | 0 (MEM/EX) | 0 |
| Load → operand, address | 2 | 1 (bubble, then MEM/EX) | 0 (MEM/EX) | 0 |
| Load → store data | 2 | 0 (MEM/MEM) | 0 | 0 |
The one stall no wire can remove: load-use
Fig. 5 puts the two producers side by side. An ALU result is born at the end of EX, one cycle before the next instruction's EX: the EX/EX wire delivers it just in time. A load's value is born at the end of MEM — the memory has to answer first — while the next instruction's EX runs in that same cycle: there is nothing to forward yet. The consumer waits one cycle, then MEM/EX hands it the value. This is the load-use hazard: one stall even with full forwarding, the fact of the chapter most worth remembering.
SUB R2, R1, R3 then AND R12, R2, R5: EX/EX path
LD R2, 4(R1) then ADD R3, R2, R4: one bubble, then MEM/EX
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
|---|---|---|---|---|---|---|---|
I0 LD R2, 4(R1) | IF | ID | EX | MEM | WB | ||
I1 ADD R3, R2, R4 | IF | ID | stall | EX | MEM | WB |
Who inserts the bubble
The forwarding unit works in EX; it can route a value but cannot hold an instruction back. The load-use case needs a second circuit one stage earlier, the hazard detection unit of Patterson and Hennessy (background from the book: the notes draw the bubble but never say who makes it). It sits in ID and asks: is the instruction in EX a load whose destination is one of my sources?
if ID/EX.MemRead
and (ID/EX.rd == IF/ID.rs1 or ID/EX.rd == IF/ID.rs2)
then stall one cycle
One refinement the course's third wire forces on the book's rule: when the instruction in ID is a store and the match is on its data register, there is no stall — the data is needed only in MEM, where the MEM/MEM path delivers it (the Figure 7 table above). Only the base register of a store goes through the test.
Stalling is three actions in one cycle (Fig. 6): freeze the PC, so the same instruction is fetched again; freeze the IF/ID register, so the instruction in ID stays and reads its registers again next cycle; and zero the control signals entering ID/EX, so the stage downstream executes a nop. That zeroed set of control signals is the bubble; it travels through EX, MEM and WB doing nothing.
"Forwarding reads the register file faster." No: forwarding never touches the register file. The value comes from the EX/MEM or MEM/WB pipeline register, where it waits anyway; the register file is still written in WB. The split-cycle register file is a separate trick inside the register file.
Who fixes it: the compiler or the hardware
Everything so far was hardware. The notes (page 25) sort the answers to a RAW hazard by who acts: static solutions are applied by the compiler before the program runs, dynamic solutions by the hardware while it runs. Keep the two words; they return for scheduling (VLIW against Tomasulo) and branch prediction.
| Solution | Who | What it does | What it costs |
|---|---|---|---|
| nop insertion | compiler (static) | puts empty instructions between producer and consumer | the same lost cycles as a stall, plus a larger program and a larger instruction count; written for one pipeline depth |
| instruction scheduling | compiler (static) | moves independent instructions into the gap | free when independent instructions exist nearby; impossible otherwise |
| stalling (interlock) | hardware (dynamic) | holds the consumer in ID and sends a bubble down | lost cycles; a small detection circuit; no code growth |
| forwarding | hardware (dynamic) | takes the value from a pipeline register | multiplexers and comparators; removes every data-hazard stall except load-use |
The notes' Examples 3 and 4, corrected
Now the warm-up puzzle. The notes insert one nop (Example 3, page 25) or one independent instruction (Example 4, page 26) between SUB R2 and AND R12, R2, R5 and declare R2 ready. Run the distance rule: without forwarding the pair needs two stalls, so one filler turns \(d = 1\) into \(d = 2\) and removes one stall. The hardware still inserts the other — or, without interlocks, AND reads the old R2.
# no forwarding: the consumer must be the third instruction after
I0 SUB R2, R1, R3
I1 NOP # or an independent instruction
I2 NOP # or a second one
I3 AND R12, R2, R5 # reads R2 in cycle 5 = SUB's WB: ready
# with forwarding: nothing between an ALU producer and its consumer
I0 SUB R2, R1, R3
I1 AND R12, R2, R5 # EX/EX path
# with forwarding, a load producer: exactly one slot
I0 LD R2, 0(R1)
I1 NOP # fill it with useful work
I2 ADD R3, R2, R4 # MEM/EX path, 0 stalls
Why does a hardware stall beat the compiler's nop if both lose a cycle? Because the nop is a real instruction — fetched, counted in IC, and the program grows — and the compiler had to know the pipeline depth of the machine the code would run on; an interlock costs a comparator and nothing else. And why does the compiler still matter when forwarding exists? Because of the one slot forwarding cannot fill: after every load something useful should go into the load-use slot. That is the beginning of compiler scheduling, the main tool of lesson 15 and the VLIW lessons.
So the warm-up has its answer: two empty slots without forwarding, none with it — and the one-slot case the notes were reaching for exists: the slot after a load.
Forwarding is a comparison of register numbers in the pipeline registers, and it removes every data-hazard stall but one: the slot after a load.
Exam-style questions
Explain the main concepts and benefits of each one of the following techniques used in a pipelined RISC-V processor:
- The split-cycle register file (write in the first half of the clock cycle, read in the second half).
- The forwarding paths EX/EX, MEM/EX and MEM/MEM and the forwarding unit.
- The load-use hazard and the hazard detection unit.
- Static versus dynamic solutions to RAW data hazards.
Show model answer
1. The register file is written in the first half of a clock cycle and read in the second half, so an instruction in WB and an instruction in ID exchange a value within the same cycle. Benefit: a consumer three instructions after its producer needs no stall and no extra datapath; without it a consumer at distance 1, 2 or 3 would pay one more stall. It is the "read and write at the same address in the same cycle" assumption of the exercises.
2. Forwarding (bypassing) feeds a result to a dependent instruction from the pipeline register where it already sits, instead of waiting for WB and a register-file read. EX/EX takes the ALU result from EX/MEM into the ALU input (ALU producer at distance 1); MEM/EX takes a value from MEM/WB into the ALU input (ALU producer at distance 2, or a loaded value); MEM/MEM takes a loaded value from MEM/WB into the data-memory write input (load followed by a store). The forwarding unit compares the destination register numbers in EX/MEM and MEM/WB with the source numbers in ID/EX, gives priority to the newest result and ignores R0. Benefit: all ALU-to-ALU stalls disappear; cost: multiplexers and comparators.
3. A load's value exists only at the end of its MEM stage, so an instruction that uses it immediately would need it in the same cycle: one stall is unavoidable even with forwarding, after which the MEM/EX path delivers the value. The hazard detection unit, in ID, detects the case (the instruction in EX is a load whose destination equals a source the instruction in ID needs in EX; the data register of a store is exempt, since the MEM/MEM path serves it in MEM) and inserts the bubble: it holds the PC and the IF/ID register and zeroes the control signals entering ID/EX. Benefit: correctness with the minimum delay; the compiler can fill the slot with an independent instruction.
4. Static solutions are applied by the compiler: nop insertion (simple, wastes the same cycles as a stall and inflates code and instruction count) and instruction scheduling (fills the gap with independent instructions, free when they exist). Dynamic solutions are applied by the hardware at run time: stalling through interlocks (bubbles, no code growth) and forwarding (the preferred one). Benefit of dynamic solutions: the code is independent of the pipeline depth; benefit of static ones: no detection hardware and the ability to fill slots forwarding cannot remove.
This is the shape of the 8-point question of the June 2026 paper: a few lines per sub-point, each with the concept, the mechanism and the benefit. The examiner is checking the vocabulary (pipeline registers, ID/EX, EX/MEM, MEM/WB, bypass, interlock, bubble), the cost next to the benefit, and the two facts that separate a good answer from a vague one: the forwarding unit compares register numbers, and load-use keeps one stall.
Consider the 5-stage RISC-V pipeline (IF, ID, EX, MEM, WB) with a register file that is written in the first half of the clock cycle and read in the second half. Consider the following code:
I0 LD R2, 0(R1)
I1 ADD R3, R2, R4
I2 SUB R5, R3, R6
I3 SD R5, 8(R1)
I4 OR R7, R2, R5
(a) Complete the cycle-by-cycle table without forwarding. (b) Complete it with the EX/EX, MEM/EX and MEM/MEM forwarding paths. For each case give the stall cycles, the total clock cycles (IC + 4 + stalls) and the CPI. (c) Compute the speed-up of (b) over (a).
Show model answer
(a) Without forwarding. RAW on R2 (I0 to I1), R3 (I1 to I2) and R5 (I2 to I3), all at distance 1: 2 stalls each. I4 reads R2 and R5 in cycle 12, both already written: 0 stalls.
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| I0 LD R2, 0(R1) | IF | ID | EX | MEM | WB | ||||||||||
| I1 ADD R3, R2, R4 | IF | ID | stall | stall | EX | MEM | WB | ||||||||
| I2 SUB R5, R3, R6 | IF | IF | IF | ID | stall | stall | EX | MEM | WB | ||||||
| I3 SD R5, 8(R1) | IF | IF | IF | ID | stall | stall | EX | MEM | WB | ||||||
| I4 OR R7, R2, R5 | IF | IF | IF | ID | EX | MEM | WB |
Stalls = 6; clock cycles = 5 + 4 + 6 = 15 (the cycle of the last WB); CPI = 15 / 5 = 3.0.
(b) With forwarding. I0 to I1 is a load-use pair: 1 stall, then R2 through the MEM/EX path in cycle 5. I1 to I2: EX/EX path in cycle 6, 0 stalls. I2 to I3: R5 forwarded to the store through the EX/EX path in cycle 7, 0 stalls. I4: R5 through the MEM/EX path in cycle 8, R2 from the register file, 0 stalls.
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
|---|---|---|---|---|---|---|---|---|---|---|
| I0 LD R2, 0(R1) | IF | ID | EX | MEM | WB | |||||
| I1 ADD R3, R2, R4 | IF | ID | stall | EX | MEM | WB | ||||
| I2 SUB R5, R3, R6 | IF | IF | ID | EX | MEM | WB | ||||
| I3 SD R5, 8(R1) | IF | ID | EX | MEM | WB | |||||
| I4 OR R7, R2, R5 | IF | ID | EX | MEM | WB |
Stalls = 1; clock cycles = 5 + 4 + 1 = 10; CPI = 10 / 5 = 2.0.
(c) Speed-up = 15 / 10 = 1.5 (the CPI drops from 3.0 to 2.0).
Not one of the official papers' exercises: the papers of 2024–2026 test this material through the dependence table of Exercise 1, the CPI line of every table and the quizzes. The form is that of the notes' Example 2 and Figure 9 and of the textbook. What is checked: the stalls per pair from the distance rule, the frozen IF cells of the instruction behind a stall, the one surviving load-use stall, and a total that equals the cycle of the last WB. Writing "S" (or the notes' "ID-Stallo" / "IF-Stallo") for a held cell gives the same cycle count.
The code SUB R2, R1, R3 / AND R12, R2, R5 / OR R13, R6, R2 / ADD R14, R2, R2 / SD R15, 100(R2) runs on the 5-stage pipeline without forwarding, with the split-cycle register file. How many clock cycles does it take, counting the pipeline fill?
Show model answer
Only AND stalls (distance 1 from SUB: 2 stalls); OR is held in IF behind it and reads R2 in cycle 6, after the write in cycle 5; ADD and SD are later still. Clock cycles = IC + 4 + stalls = 5 + 4 + 2 = 11.
The trap is to charge OR for its own distance-2 dependence (one stall by the rule) — but the rule assumes the consumer was not already delayed. The stall of AND has pushed OR past the write. Count on the table, not on the rule alone.
On a 5-stage pipeline with full forwarding (EX/EX, MEM/EX, MEM/MEM) and a split-cycle register file, how many stall cycles does LD R5, 0(R9) immediately followed by ADD R6, R5, R5 cause? (Single answer.)
Show model answer
Answer 2: 1 stall. The loaded value exists only at the end of the load's MEM stage; the add's EX is delayed one cycle and then takes the value through the MEM/EX path.
A single-answer quiz in the form of the papers' quiz block (none of the 2024–2026 papers asks this exact pair, but it is the one fact of the chapter a quiz can test in one line). The distractor 0 is the notes' "forwarding eliminates stalls".
Which hazards can occur in the basic in-order 5-stage RISC-V pipeline with separate instruction and data memories? (Multiple answers.)
Show model answer
Answers 1 and 4. Reads in ID precede any later write in WB and all writes are in order through one WB stage, so WAR and WAW are impossible; split memories remove the IF/MEM conflict; RAW and control hazards remain.
A multiple-answer quiz in the form of the June 2026 paper. The notes' "WAR … rare in RISC" is the distractor to resist.
A compiler targets a 5-stage pipeline with no forwarding and no interlocks, but with the split-cycle register file. How many NOP instructions must it insert between SUB R2, R1, R3 and AND R12, R2, R5 for the AND to read the new R2? Motivate your answer. (Single answer.)
Show model answer
Answer 3: 2 NOPs. Motivation: SUB writes R2 in WB in cycle 5. The consumer at distance \(d\) reads in cycle \(d + 2\); the read must be in cycle 5 or later, so \(d = 3\): two instructions in between. Stalls = max(0, 3 − d) = 0.
The "motivate your answer" line is where the second point is: write the two cycle numbers (write in 5, read in d + 2), not only the count.
Check yourself
Why can a WAR hazard never occur in the in-order 5-stage pipeline?
No forwarding, split-cycle register file. ADD R4, R1, R2 is followed by one independent instruction and then by SUB R6, R4, R5. How many stalls does the SUB pay?
Which statements about forwarding are true?
Three true, two false — the false ones are the two most common misunderstandings of the chapter.
With full forwarding, LD R2, 0(R1) is immediately followed by SD R2, 8(R3). Which path serves the store, and how many stalls?
ADD R1, R1, R2 / ADD R1, R1, R3 / ADD R1, R1, R4 with full forwarding. When the third add is in EX, both EX/MEM.rd and MEM/WB.rd equal R1. Which value must it use?
An instruction is held in ID for two stall cycles. What happens to the instruction right behind it during those cycles?
Without forwarding, a compiler places two NOPs between SUB R2 and AND R12, R2, R5 instead of letting the hardware stall twice. Compared with the stalled version, the program now …
Key take-aways
- A hazard is a situation where overlapping would change the result, so the pipeline must stall; in the in-order 5-stage pipeline only RAW data hazards and control hazards can occur — WAR and WAW are impossible, structural hazards were designed away.
- Without forwarding a consumer at distance \(d\) from its producer pays \(\max(0, 3 - d)\) stalls; the split-cycle register file (write first half, read second half) is what makes the distance-3 consumer free.
- Forwarding takes a value from a pipeline register — EX/EX from EX/MEM, MEM/EX and MEM/MEM from MEM/WB — chosen by a comparison of register numbers in which the newest result wins and R0 is excluded.
- A load's value is born at the end of MEM, so a load followed by its use costs exactly one stall even with full forwarding; the hazard detection unit inserts that bubble by freezing PC and IF/ID and zeroing the controls into ID/EX.
- A stall in ID holds every instruction behind it in IF, and the total clock cycles of a fragment is the cycle of the last WB: IC + 4 + stalls.
- RAW hazards have static solutions (nop insertion, compiler scheduling) and dynamic ones (interlocks, forwarding); the notes' one-nop examples are wrong — two slots without forwarding, zero with it, one only after a load.
What to watch and read
-
CPU Pipeline
Computerphile, Matt Godboltabout 22 min
The production-line metaphor and why a dependence jams it, told with pen and paper and no formulas — the right warm-up before the distance rule.
-
Ripes, visual RISC-V pipeline simulator
Morten Borup Petersen (browser build)
Type a three-instruction RAW chain, step cycle by cycle and watch the forwarding multiplexer light up; then switch forwarding off in the processor options and count the bubbles. The best companion to the table-builder widget.
-
WebRISC-V
University of Siena
Draws the instruction-versus-cycle table of the textbook datapath with a forwarding switch, so you can check a table you filled by hand.
-
Hennessy & Patterson, Appendix C condensed to 74 slides
UIUC CS433
Sections C.2–C.3 are the hazard chapter of the reference book (Appendix A in the 4th edition, which is what the WeBeep page links). The same three hazard classes, the same forwarding figures, more cases.
-
MIPS: A Microprocessor Architecture (1982)
Hennessy, Jouppi, Przybylski, Rowen, Gross, Baskett, Gill6 pages
The paper behind the warm-up: a pipeline "without pipeline interlocks" where the compiler inserted the NOPs. Read the first two pages to see static solutions taken to their limit.