MIPS, SPARC and HP-PA each have one architecturally visible delay slot. RISC-V's designers rejected delay slots, with condition codes, as features that "complicate higher performance implementations"; its specification says control-transfer instructions in RV32I "do not have architecturally visible delay slots". McFarling had written in 1993 that delayed branches are "decreasingly effective as the number of delay slots to fill increases". The course uses RISC-V syntax with a MIPS-style slot as a convention; at the exam the exam text wins.
Why the pipeline hates branches: static prediction and the delay slot
After this lesson you will count what a branch costs in the 5-stage pipeline, pick the static scheme that fits a loop or an if, and fill a delay slot legally — the convention every VLIW exercise of the exam is built on.
Take the loop of the June 2025 paper, Question 5. The BNE at its bottom runs five times: four jumps back, one fall-through. A predictor with no memory at all — it cannot even remember what happened last time — gets this branch right four times out of five.
Point the same predictor at the loop of the 2025 midterm, whose exit test BEQ R1, R2, DONE sits at the top, and it is wrong 100 times out of 101. The only difference between the two branches is the sign of one number inside the instruction.
By the end of the lesson you will know which number, why the basic 5-stage pipeline throws away three cycles on every branch, and why every VLIW exercise of the exam says "branch solved in ID stage, 1 cycle delay slot".
A branch answers two questions, and both come late
You know from your first architecture course what a conditional branch does: BNE R1, R2, LOOP compares two registers and continues at the label if they differ, at PC + 4 otherwise. The notes write RISC-V beq x1, x3, L1; this notebook writes branches as the exam papers do, without the dollar sign of the older papers ($R1, $F2). Here is the loop of the June 2025 paper in that spelling (the paper prints ADDI.U for ADDUI and ADDI.D for FADD):
INIT: ADDUI R1, R0, 0
ADDUI R2, R0, 20
LOOP: LD F0, 0(R1)
FADD F2, F0, F0
SD F2, 0(R1)
ADDUI R1, R1, 4
BNE R1, R2, LOOP
What makes a branch special is who is waiting for its answer: the fetch unit needs the next PC every cycle, and a branch delivers it in two parts, both late.
Branch outcome (BO in the notes) — one bit: taken (T, continue at the label) or not taken (NT, continue at PC + 4). Branch target address (BTA) — where a taken branch continues: PC + offset, the offset being the sign-extended immediate of the instruction. A scheme that knows "taken" but not "where" still cannot fetch.
In the basic pipeline of the notes (pp. 30–31) the ALU compares the registers and adds PC + offset in EX, and the PC is written at the end of ME: for three cycles after the branch is fetched, fetch does not know where to go. That gap is the control hazard, a "pipeline hazard due to uncertainty in branch outcome during instruction fetch" in the notes' summary box (p. 32), caused by every instruction that modifies the PC, jumps included. Fetch can only stall until the PC is known, or fetch and flush: guess, keep going, throw the guessed instructions away if the guess was wrong.
Before: outcome in EX, PC written in ME — 3 bubbles
After: outcome and target in ID — 1 bubble
Read the penalty off the figure: the next PC is known at the end of stage r of the branch (ME is stage 4, ID is 2), so the fetch slots of cycles 2 … r are lost.
Branch penalty = (stage at whose end the PC is written) − 1: three cycles with the PC written in ME, one cycle with the branch solved in ID.
On the notes' four-instruction sequence (p. 34), counted as the formula sheet counts, cycles = IC + 4 + stalls:
| PC written at the end of | Fetch does | Stalls | Cycles = IC + 4 + stalls |
|---|---|---|---|
| ME | waits | 3 | 4 + 4 + 3 = 11 |
| ID | waits | 1 | 4 + 4 + 1 = 9 |
| ID | guesses right | 0 | 4 + 4 + 0 = 8 |
| ID | guesses wrong, flushes | 1 | 4 + 4 + 1 = 9 |
Early branch evaluation: move the comparison into ID
Nothing forces the comparison to wait for EX: BNE needs an equality test, a cheap tree of XOR gates, and its target is PC-relative, so an adder can produce PC + offset right after decoding. The notes (p. 35) list what the ID stage gains — comparison and addition logic, a multiplexer with control signals to write the PC, wider data paths for the offset and the register values — and both answers are ready at the end of ID: the right panel of Fig. 1.
The price: a branch that is hungry for its operands
The comparator in ID wants its operands one stage earlier than an ALU would. If the instruction right before the branch produces one of them, forwarding cannot help — the producer is still in EX when the branch asks in ID — so the branch waits one cycle, two after a load. Hence the sentence of every VLIW exercise of the three papers, "1 Integer ALU with 1 cycle latency to next Int/FP/L/S & 2 cycle latency to next Branch": the loop counter must be updated at least one instruction before the branch that tests it.
ADDUI R1, R1, 4 # produces R1 in EX
BNE R1, R2, LOOP # needs R1 in ID: one stall cycle
| C1 | C2 | C3 | C4 | C5 | C6 | C7 | |
|---|---|---|---|---|---|---|---|
ADDUI | IF | ID | EX | ME | WB | ||
BNE | IF | stall | ID | EX | ME | WB |
One independent instruction between them removes the stall. Early resolution buys a short penalty and a hungrier branch: both halves are exam material.
Stall or flush: the CPI formula
Stalling pays the penalty on every branch; a guessed fetch pays it only when wrong. The derivation turns that into the one formula of this lesson that is not on the formula sheet.
-
The formula sheet's cycle count for IC instructions on the 5-stage pipeline (4 = the pipeline fill):
\[ \text{cycles} = \text{IC} + 4 + \text{stalls} . \] -
A fraction \(f_b\) of the instructions are branches; each costs \(r - 1\) cycles when fetch guessed wrong, with probability \(p_{\text{mis}}\):
\[ \text{stalls}_b = \text{IC} \cdot f_b \,(r - 1)\, p_{\text{mis}} . \] -
Divide by IC; for a long program the fill term \(4 / \text{IC}\) vanishes:
\[ \text{CPI} = 1 + f_b\,(r - 1)\,p_{\text{mis}} . \] -
Stalling is "always wrong", \(p_{\text{mis}} = 1\). A predictor pays only when wrong: always not taken has \(p_{\text{mis}} = p_T\), the taken fraction; always taken has \(1 - p_T\).
-
With \(f_b = 0.2\), \(p_T = 0.6\) and the branch solved in ID: stall 1.20, always not taken 1.12, always taken 1.08. With the PC written in ME: 1.60, 1.36, 1.24 — a machine built for CPI = 1 runs at 1.6 before a single cache miss.
- \(f_b\)
- fraction of executed instructions that are branches (about one in five in integer code)
- \(r\)
- stage at whose end the next PC is written: 2 for ID, 4 for ME
- \(p_{\text{mis}}\)
- probability that fetch went the wrong way: 1 when stalling, \(p_T\) for always not taken, \(1 - p_T\) for always taken
Guessing with no memory: the four static schemes
Branch prediction is speculation: guess the outcome, fetch along the guessed path, flush and restart if the guess was wrong. One rule keeps it safe (p. 37): "the processor must avoid updating its internal state (registers, memory, etc.) until the branch outcome is known with certainty". With the branch solved in ID that is free, since the wrongly fetched instruction is still in IF; the out-of-order machines of lesson 17 need a reorder buffer for it.
A static scheme guesses the same way for a given branch every time — a fixed hardware rule or a compiler hint; "static" means nothing is learned at run time, not "the compiler decides". Dynamic schemes (lessons 5 and 6) learn from the branch's history. The notes' four static rules, each with its cost and its failure case:
Always not taken, always taken — and why one of them needs a table
Branch always not taken costs nothing: keep fetching PC + 4 "without any need to determine or access the Branch Target Address" (p. 39). When the branch turns out taken, the one instruction fetched after it becomes a NOP and fetch restarts at the target — one cycle in the ID-resolved pipeline (the notes' Figure 12, left panel below). The right bet for an if whose else path is rare — the notes' example (p. 39) is if (z > 0) w = x; else w = y; with z usually positive, so the branch to the else part is usually not taken — and the wrong one for every loop-closing branch.
Branch always taken mirrors it in direction but not in cost: to fetch the target in the next cycle you must know it while the branch is still in IF, before decoding — and in IF nothing can be computed about a branch, only remembered, indexed by its PC. That memory is the Branch Target Buffer, "a specialized cache in the processor designed to predict the target address of a taken branch instruction before the branch condition is actually resolved" (p. 41): key, the address of the branch; value, the predicted target. In the notes' Example 1 (p. 42) the entry 0x100 → 0x80 sends fetch to 0x80 as soon as the branch at 0x100 is fetched; if the branch is then not taken, the instruction from 0x80 is flushed and fetch resumes at 0x104 — again one cycle. On a miss the processor "might default to sequential execution (PC + 4) or wait for the BTA to be calculated". The BTB is lesson 5; here, remember that without it always taken has nothing to fetch, since the target is known no earlier than the outcome.
Predicted not taken, actually taken (notes' Fig. 12)
Predicted taken via the BTB, actually not taken (notes' Fig. 13, corrected)
Backward taken, forward not taken
The two uniform rules are each right on one kind of branch, so combine them with the one bit that tells the kinds apart: the direction. BTFNT predicts a backward branch (target below the current PC) as taken, because backward branches close loops and a loop of N iterations takes its bottom branch N − 1 times; a forward branch as not taken, because forward branches usually guard an else path or an error handler that is rarely entered. The notes (p. 44) call it "just a comparison of the target address vs the current PC"; in hardware it is the sign bit of the offset. It is not adaptive — a forward branch taken 90 % of the time is mispredicted 90 % of the time. And the sign bit is only known after decoding, when the ID-resolved pipeline knows the outcome anyway: in the course's pipeline the guess pays off only if it is stored, with the target, in the BTB entry of the branch, so that it is available in IF. The tables of this lesson assume that.
BNE jumps back (taken 4 times in 5), the midterm's BEQ jumps forward (taken once in 101). BTFNT reads the sign of the offset and gets both right.Profile-driven prediction
The fourth scheme lets the compiler decide per branch, from evidence: run the program on representative inputs, record how often each branch was taken, and encode the verdict as a hint bit in the instruction, 1 if usually taken, 0 if not. The notes' pattern (p. 45), T T T T T T T T NT NT NT, gives the hint "taken" and about 27 % mispredictions if future runs look like the profile. The processor only reads a bit; the costs are a profile-compile cycle, a profile that goes stale when the inputs change, and an instruction format with a spare bit — RISC-V has none, so compilers there lay the code out so that the frequent path falls through.
The notes' Table 2 (p. 47), with the delayed branch of section 4 included:
| Technique | Prediction source | Complexity | Risk | Best for |
|---|---|---|---|---|
| Always not taken | assume PC + 4 | very low | mispredicts backward branches | if-then-else |
| Always taken | assume the jump to the BTA | moderate (BTB) | mispredicts forward branches | loops (backward branches) |
| BTFNT | direction of the branch | low | errors in irregular control flow | mixed code |
| Profile-driven | data of prior runs | high (compile time) | profile mismatch | stable, performance-tuned code |
| Delayed branch | compiler-scheduled slot | high (compiler) | wasted work if the slot cannot be filled | RISC pipelines such as MIPS |
Putting numbers on it: the two exam loops
The exam asks for a table and a rate, so do both loops of the hook by hand once. The June 2025 BNE executes with R1 = 4, 8, 12, 16, 20 against R2 = 20: five executions, T T T T NT. The midterm BEQ executes with R1 = 0 … 100 against R2 = 100: 101 executions, NT 100 times, then T at the exit.
| Scheme | Loop A (backward BNE) | Loop B (forward BEQ) |
|---|---|---|
| stall, no guess | pays on all 5: 5 cycles | pays on all 101: 101 cycles |
| always not taken | 4 of 5 = 80 % | 1 of 101 ≈ 1 % |
| always taken, BTB hit | 1 of 5 = 20 % | 100 of 101 ≈ 99 % |
| BTFNT | 1 of 5 = 20 % | 1 of 101 ≈ 1 % |
| profile hint (T for A, NT for B) | 1 of 5 = 20 % | 1 of 101 ≈ 1 % |
| 2-bit BHT from Strongly NT | 3 of 5 = 60 % | — |
To turn a rate into cycles, count. The 2025 program executes 2 + 5 × 5 = 27 instructions; with branch stalls only (the body's load-use hazard is left out on purpose), stalling costs 27 + 4 + 5 = 36 cycles (CPI 1.33), always not taken 35 (1.30), always taken 32 (1.19). In the formula sheet's loop notation, m = 5 and k = 1 stall per iteration give CPI∞ = (m + k) / m = 1.2 for the stalled loop; a correctly predicted branch has k = 0.
The 2025 paper's table has columns "1st … 5th iteration" and rows "Prediction State", "Prediction", "Branch Outcome". For a static scheme the state row is constant: write the prediction row, the outcome row T T T T NT, mark the mismatches, then the rate. A bare "80 %" loses the motivation point.
The delay slot: the bubble becomes a contract
The delayed branch stops guessing and changes the rules: the instruction right after the branch — the branch delay slot — "is always executed, regardless of whether the branch is taken or not" (p. 46), and the branch takes effect only after it. The bubble gets a meaning and the compiler gets the job of filling it; if it finds nothing it writes a NOP, which is exactly the stall you were trying to avoid.
FMUL F4, F4, F0) is fetched while the branch is in ID; the branch steers only the fetch of cycle 3.| C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 | |
|---|---|---|---|---|---|---|---|---|
BNE | IF | ID | EX | ME | WB | |||
FMUL (slot) | IF | ID | EX | ME | WB | |||
LD at LOOP | IF | ID | EX | ME | WB | |||
| next | IF | ID | EX | ME | WB |
The compiler's checklist (p. 46): the candidate must be independent of the branch decision — it must not produce a register the branch compares and must not be a branch itself — and safe to execute whether the branch is taken or not. It can come from three places.
From before: always a win
Take an instruction above the branch that the branch does not depend on and move it below. It had to execute on both paths, so the slot is useful whatever the outcome, with no safety condition beyond independence and no code growth. The notes' Example 2 (p. 48) in the papers' mnemonics: the ADD writes R1 and reads R2, R3; the branch reads R2 and R4; nothing links them.
ADD R1, R2, R3
BEQ R2, R4, L1
NOP # delay slot
BEQ R2, R4, L1
ADD R1, R2, R3 # delay slot
From the target: a bet on "taken"
When nothing independent sits above the branch, copy the first instruction of the target into the slot and retarget the branch to the instruction after it. Taken, the slot did exactly what came next — for a loop, almost every time. Not taken, the slot instruction executes all the same, so it must be harmless on the fall-through path: typically it writes a register that path overwrites before reading. The notes' Example 3 (p. 49), with the loop made explicit:
L1: SUB R4, R5, R6
ADD R1, R2, R3
BEQ R1, R0, L1
NOP # delay slot
L1: SUB R4, R5, R6 # kept: first entry
L2: ADD R1, R2, R3 # new target
BEQ R1, R0, L2
SUB R4, R5, R6 # slot: the copy
The SUB now exists twice — the instruction duplication of p. 50. Only this branch is retargeted, to L2; the original stays at L1, because the first entry into the loop and any other branch that jumps to L1 still need it there. The price is code size and two copies to keep consistent; the gain is one cycle on every taken iteration — why the notes recommend it for loops, "particularly do-while constructs".
The example also hides the stall of section 1: ADD R1, R2, R3 produces R1 and BEQ R1, R0, L1 tests it in the very next cycle. Any instruction between the two would cure it; the quiz asks about this.
From the fall-through: a bet on "not taken"
The mirror bet moves the instruction that follows the branch on the sequential path into the slot. Not taken, the slot was needed anyway; taken, it still executes, so its result must be dead on the target path. The notes' Example 4 (p. 51): OR R7, R8, R9 is the fall-through instruction, SUB R4, R5, R6 at L1 the target.
ADD R1, R2, R3
BEQ R1, R0, L1
NOP # slot
OR R7, R8, R9 # not taken
L1: SUB R4, R5, R6 # taken
ADD R1, R2, R3
BEQ R1, R0, L1
OR R7, R8, R9 # slot
L1: SUB R4, R5, R6
The condition: R7 is not read at L1 or after it before being written again. Rarely-taken forward branches are the natural customers.
What the slot really costs, and why RISC-V has none
Two background facts complete the picture. A variant in which the slot is squashed exists — the cancelling branch (MIPS "branch likely"), whose slot executes only if the branch goes the predicted way: "from target" fills become safe, at the price of a flush when the prediction fails. And the slot writes the depth of one pipeline into the instruction set: a deeper pipeline has several bubbles and one slot hides only the first, a superscalar front end would need several slots, and an exception in the slot of a taken branch must restart at two non-adjacent addresses. Compilers fill a single slot usefully only about half of the time (Hennessy & Patterson: about 60 % filled, 80 % of those useful).
The exam's convention: "branch solved in ID stage, 1 cycle delay slot"
Now read the sentence every VLIW exercise of the 2024, 2025 and 2026 papers repeats: "The branch is completed with 1 cycle delay slot (branch solved in ID stage). No branch prediction." "Solved in ID" is early evaluation, hence the integer unit's "2 cycle latency to next Branch". "1 cycle delay slot" is the bubble of that pipeline, counted as a cycle of the iteration and written as "(delay slot)" in the row after the branch; nothing is scheduled in it, because the branch is the last instruction of the iteration and the exercise forbids the loop transformations that would move an instruction past it. "No branch prediction": the fetch after the slot waits for the ID-stage decision. The 2026 paper's LOOP1 (lesson 20 derives it):
| Memory Unit | Floating Point Unit | Integer Unit | |
|---|---|---|---|
| C1 | LD F2, 0(R1) | ||
| C2 | |||
| C3 | |||
| C4 | FADD F6, F2, F2 | ||
| C5 | |||
| C6 | |||
| C7 | SD F6, 0(R1) | ADDUI R1, R1, 4 | |
| C8 | |||
| C9 | BNE R1, R3, LOOP1 | ||
| C10 | (delay slot) | ||
In every exam table the delay slot is a cycle you count: the branch goes two cycles after the ADDUI that it tests, the slot is the next row, and the critical path ends there.
The puzzle, solved
The number in the hook is the branch offset. The June 2025 BNE points back to LOOP, its offset is negative, and a predictor that reads that bit says "taken": right on four iterations, wrong at the exit. The midterm BEQ points forward to DONE, its offset is positive, the same predictor says "not taken" and is right 100 times out of 101 — "always taken", blind to the sign, is the one wrong 100 times. The three lost cycles of the basic pipeline are the distance from IF to the end of ME; the course's pipeline moves the decision to ID, pays one, and the delayed branch gives even that cycle a job.
Exam-style questions
Explain the main concepts and benefits of each one of the following techniques for handling branches in a pipelined RISC-V processor: 1. Branch always not taken; 2. Branch always taken with a Branch Target Buffer; 3. Backward taken, forward not taken; 4. Delayed branch with delay-slot scheduling.
Show model answer
1. Branch always not taken. Fetch continues at PC + 4 as if the branch were an ordinary instruction; no hardware and no target address are needed. When the branch is not taken the cost is zero; when it is taken the one instruction fetched after the branch is flushed (turned into a NOP) and fetch restarts at the target: a 1-cycle penalty with the branch solved in ID. Good for if-then-else with a rare else path, bad for loop-closing branches, which are taken almost always.
2. Branch always taken with a BTB. Fetch continues at the target. The target is needed while the branch is still in IF, before decoding, so a Branch Target Buffer — a cache indexed by the address of the branch instruction whose entry holds the predicted target address — supplies it; on a hit the target is fetched in the next cycle. When the branch is not taken the instruction fetched from the target is flushed and fetch resumes at PC + 4 (1 cycle). On a BTB miss the processor falls back to PC + 4 or waits for the target. Good for backward loop branches; without a BTB the scheme has no benefit in a 5-stage pipeline because the target is not known before the outcome.
3. BTFNT. Use the direction of the branch, i.e. the sign of the offset: backward branches (loops) are predicted taken, forward branches (if-then-else, rarely entered paths) not taken. Needs only one bit of the instruction and no learning hardware; better accuracy than either uniform rule on mixed code. Not adaptive: a forward branch that is usually taken is mispredicted most of the time; and the direction is only known after decoding, so the guess is stored in the BTB entry to be usable in IF.
4. Delayed branch. The instruction in the slot after the branch is always executed, whatever the outcome; the branch takes effect after it. The compiler fills the slot with an instruction from before the branch (independent of it: always useful), from the target (useful when taken; must be harmless when not; usually duplicated at the label) or from the fall-through (useful when not taken; harmless when taken). A filled slot hides the 1-cycle bubble of the ID-resolved pipeline; a NOP in the slot is a stall. Benefit: no guessing and no flush logic; drawbacks: the slot ties the ISA to one pipeline depth, deeper or multiple-issue pipelines cannot be covered by one slot, and about half of the slots are not usefully filled — which is why RISC-V has no delay slot.
The 2026 paper gives five lines per sub-point: name the mechanism, say what it costs, what it buys, and when it fails. For point 2 the examiner looks for "indexed by the branch PC" and "target needed in IF"; for point 4 for "always executed" and the three sources with their conditions.
Consider the following loop executed on a 5-stage pipeline where the branch is solved in the ID stage (misprediction penalty 1 cycle):
INIT: ADDUI R1, R0, 0
ADDUI R2, R0, 20
LOOP: LD F0, 0(R1)
FADD F2, F0, F0
SD F2, 0(R1)
ADDUI R1, R1, 4
BNE R1, R2, LOOP
For (a) branch always not taken, (b) branch always taken with a BTB that always hits, (c) BTFNT, complete the table (prediction, branch outcome, penalty for each iteration), then give the misprediction rate on the BNE and the total branch stall cycles.
Show model answer
The BNE executes with R1 = 4, 8, 12, 16, 20 against R2 = 20: five executions, outcomes T T T T NT.
| Iteration | 1st | 2nd | 3rd | 4th | 5th |
|---|---|---|---|---|---|
| Branch Outcome | T | T | T | T | NT |
| (a) Prediction: always NT | NT | NT | NT | NT | NT |
| (a) Penalty | 1 | 1 | 1 | 1 | 0 |
| (b) Prediction: always T | T | T | T | T | T |
| (b) Penalty | 0 | 0 | 0 | 0 | 1 |
| (c) Prediction: BTFNT (backward → T) | T | T | T | T | T |
| (c) Penalty | 0 | 0 | 0 | 0 | 1 |
(a) 4 mispredictions of 5 = 80 %, 4 stall cycles. (b) 1 of 5 = 20 %, 1 stall cycle. (c) LOOP is above the BNE, the offset is negative, the branch is predicted taken: identical to (b), 20 %, 1 stall cycle.
The rate is only worth the point with the row of outcomes underneath it. The commonest slip is counting four executions instead of five: list the values of R1 at the branch before writing anything else.
In a program 20 % of the executed instructions are conditional branches and 60 % of the branches are taken. The pipeline solves branches in the ID stage and uses branch always not taken; branches are the only source of stalls and the pipeline fill is negligible. Compute the CPI.
Show model answer
Always not taken mispredicts exactly the taken branches, so \(p_{\text{mis}} = 0.6\). For comparison: stalling gives 1.20, always taken with a perfect BTB 1.08; with the PC written in ME (penalty 3) the three become 1.60, 1.36, 1.24.
Write the formula first, then the numbers. The examiner checks that the penalty is 1 for an ID-resolved branch and that the misprediction probability of "not taken" is the taken fraction, not its complement.
The pipeline solves branches in ID and has one delay slot that is always executed. Fill the slot of the following loop with the "from target" strategy: write the scheduled code, give the cycles per iteration before and after, and state the conditions that make the transformation legal.
LOOP: LD F0, 0(R1)
ADDUI R1, R1, 8
FADD F2, F2, F0
FMUL F4, F4, F0
BNE R1, R2, LOOP
NOP # delay slot
Show model answer
LD F0, 0(R1) # copy of the target, runs once
LOOP: ADDUI R1, R1, 8 # new target
FADD F2, F2, F0
FMUL F4, F4, F0
BNE R1, R2, LOOP
LD F0, 0(R1) # delay slot: next iteration's load
Before: 5 instructions + 1 NOP = 6 cycles per iteration (m = 5, k = 1, CPI∞ = 1.2). After: 5 cycles per iteration (k = 0, CPI∞ = 1), because the slot now holds the next iteration's load. Legal because: the moved LD does not produce an operand of the branch (R1, R2); the slot LD writes F0, which the next FADD reads with the ADDUI in between, so no load-use stall appears; the ADDUI stays at least one instruction before the BNE that tests R1 (2-cycle ALU-to-branch latency); and on the exit path the extra load past the end of the array must be harmless — the address readable and F0 dead after the loop. The copy before the loop is the duplication cost of the strategy.
Four things earn the marks: the retargeted label, the copy before the loop, the cycle count before/after, and the exit-path condition. Forgetting the copy makes the first iteration read an F0 that was never loaded.
In a 5-stage pipeline where the branch outcome and the target address are computed in the ID stage, the penalty of a mispredicted branch under branch always not taken is:
Show model answer
1 cycle: penalty = resolution stage − 1 = 2 − 1.
The quiz is matched against the course's pipeline, in which "branch solved in ID stage" is the standing assumption.
With the delayed branch technique, the instruction placed in the branch delay slot:
Show model answer
It is always executed, regardless of the branch outcome.
Single answer. The distractor "flushed" is attractive because of the notes' wording; the rule of the ISA is the one on p. 46.
Which statements about the Branch Target Buffer used with branch always taken are true? (Multiple answers.)
Show model answer
True: indexed by the branch PC; stores the predicted target; on a hit the target is fetched in the next cycle. False: it does not decide the direction, and always not taken does not need it.
The 2026 paper has "Multiple Choice – Multiple answer" quizzes; tick every true statement and no false one.
Check yourself
Always taken needs a Branch Target Buffer and always not taken does not. Why?
A loop runs 10 times; its branch sits at the bottom and jumps back. How many mispredictions do always not taken and always taken make, in that order?
Which statements about the branch delay slot are true?
The slot is a contract, not a guess: always executed, filled by the compiler, and a NOP there is the bubble back again.
Early evaluation moved the branch comparison into ID. What is the hidden cost, in the words the exam papers use?
The notes' Example 3 has ADD R1, R2, R3 immediately followed by BEQ R1, R0, L1. In the course's pipeline, with the branch solved in ID, what happens at the branch?
A forward branch guards a rarely entered error handler and is taken 2 % of the time; a backward loop branch is taken 95 % of the time. Which schemes predict both branches well?
The two uniform rules are each an expert on one kind of branch; BTFNT and a good profile know which expert to ask.
Key take-aways
- A branch produces its outcome and its target address late, while fetch needs the next PC every cycle; the branch penalty is the resolution stage minus one — 3 cycles with the PC written in ME, 1 with the branch solved in ID.
- Early evaluation adds a comparator, an adder and a mux to ID and makes the branch hungry for its operands: an ALU result reaches a following branch only after 2 cycles, a load's after 3 — the exam's "2 cycle latency to next Branch".
- Stalling pays the penalty on every branch; a predictor pays it only when wrong: CPI = 1 + fb · penalty · pmis, with pmis = 1 for stalling, pT for always not taken, 1 − pT for always taken.
- Always not taken costs no hardware and loses on loops; always taken wins on loops but needs the target in IF, hence a Branch Target Buffer indexed by the branch PC; BTFNT reads the sign of the offset and gets both loops and ifs right; profile-driven prediction puts a hint bit chosen from earlier runs into the instruction.
- The delay-slot instruction is always executed, never flushed. Filling it from before the branch is always a win; from the target (copy, retarget, duplicate) or from the fall-through it is a bet that must be harmless on the other path; a NOP in the slot is the stall back again.
- The exam's VLIW convention "branch solved in ID stage, 1 cycle delay slot, no branch prediction" means: the branch goes two cycles after the ADDUI it tests, the next row reads (delay slot), and the critical path is counted through it.
What to watch and read
-
How Branch Prediction Works in CPUs
Computerphile, Matt Godbolt26 min
Why a pipeline has to guess and what a wrong guess costs, built up with drawings from "always guess the same" — the static schemes of this lesson — to the counters of the next one.
-
Ripes, a visual RISC-V pipeline simulator
Morten Borup Petersen10 min
Type the June 2025 loop, step cycle by cycle and watch the instruction after a taken branch being flushed in a real 5-stage datapath: Fig. 3 in motion.
-
Hennessy & Patterson, Appendix C — lecture slides (CS433, Illinois)
University of Illinois45 slides
The static schemes exactly as the exam expects them: freeze or flush, predict not taken, predict taken ("not practical for our basic pipeline" without a target), the three ways to fill the slot and a worked CPI-penalty example to redo by hand.
-
Branch direction prediction (Imperial College lecture slides)
Paul H. J. Kelly45 slides
The delay-slot statistics quoted in this lesson (about 60 % of slots filled, 80 % of those useful) and the bridge to the history tables of lesson 5.
-
The RISC-V unprivileged ISA, RV32I control-transfer instructions
RISC-V International5 min
The primary source for "no architecturally visible delay slots": read it once so that the exam's MIPS-style slot on RISC-V syntax does not confuse you.