Learning from the past: 1-bit and 2-bit history tables, and the BTB

After this lesson you will fill the exam's predictor table for any loop and any initial state, explain why one bit of memory does worse than no memory at all on a loop, and say what the branch target buffer adds that no direction predictor can.

A loop runs ten times. Its closing BNE is taken nine times and falls through once: it goes the same way 90 % of the time. The dumbest rule of the previous lesson, "always predict taken", is right 9 times out of 10.

Now give the hardware a memory: one bit per branch that stores what the branch did last time, and predict that. Remembering must beat guessing. Run the loop again and count — the one-bit predictor is right 8 times out of 10. Learning made it worse.

By the end of the lesson you will know where the two lost predictions go, why a second bit wins one of them back, and why even a perfect direction predictor cannot fetch the next instruction without a second, smaller table: the branch target buffer.

Hardware that learns at run time

Lesson 4 left the branch problem half solved. A static rule — always not taken, always taken, backward taken and forward not — is fixed before the program runs, so it cannot tell a loop that runs a million times from an if that flips with the data. In the five-stage pipeline of this course the branch outcome and its target are computed in ID, so every wrong guess costs one cycle: the wrong-path instruction becomes a NOP and fetch restarts at the right address.

Dynamic branch prediction — hardware that observes how each branch behaved in the past, at run time, and predicts its next outcome from that history (notes, p. 54). Nothing is decided by the compiler: the same binary adapts to its input.

The notes state the key assumption plainly (p. 54): "if a branch behaved a certain way in the past, it's likely to behave the same way again". It is temporal locality applied to control flow. The hardware that exploits it is two tables, both consulted in the Instruction Fetch stage:

A fetch then works in three steps (p. 54): the outcome predictor says T or NT; if T, the BTB supplies the PTA; the next instruction is fetched from the PTA or from PC + 4. Notice when: at the end of IF, before the instruction is decoded. Both tables are indexed with the PC of the instruction being fetched — the hardware does not yet know that it is a branch. Keep that in mind: it is why one of the two tables needs tags and the other does not.

PC +4 PC + 4 BHT ST WT SNT T / NT whether? BTB tagPTA 0x210x200 —— PTA where? next PC
Fig. 1. The fetch stage with both predictors. The PC indexes the BHT (whether) and the BTB (where) in the same cycle; the BHT's Taken answer, together with a BTB hit, drives the multiplexer that chooses between the PTA and PC + 4. The highlighted rows are the entries the PC selected.

The notes list the four cases of a right or wrong guess (p. 55); with the branch resolved in ID a wrong guess always costs the same one cycle:

The four execution scenarios of p. 55, with the course convention (branch resolved in ID).
PredictionActual outcomeWhat the pipeline doesPenalty
Not Taken (fetch PC + 4)Not Takencorrect: nothing0
Not Taken (fetch PC + 4)Takenflush the sequential instruction (NOP), fetch from the BTA computed in ID1 cycle
Taken (fetch from the PTA)Takencorrect: nothing0
Taken (fetch from the PTA)Not Takenflush the target instruction (NOP), fetch PC + 41 cycle

Look at the symmetry of that table. A dynamic predictor does not change what a misprediction costs — the pipeline fixes that: one cycle here, fifteen to twenty in a deep out-of-order core (Agner Fog's measurements on real Intel and AMD cores; background, not in the notes). It changes how often you pay. In the formula sheet's "CPI = 1 + stall cycles per instruction" the branch term reads as follows (lesson 4 wrote the same thing as \(1 + f_b \cdot \text{penalty} \cdot p_{\text{mis}}\)):

\[ \text{CPI} = \text{CPI}_{\text{ideal}} + f_b\,(1 - a)\,P \]
\(f_b\)
fraction of the executed instructions that are branches
\(a\)
prediction accuracy; \(1 - a\) is the misprediction rate
\(P\)
misprediction penalty in cycles: 1 in this pipeline, since the branch is resolved in ID

Two predictors, two stakes. With one instruction in five a branch (\(f_b = 0.2\)) and \(P = 1\), a predictor that is right 80 % of the time adds \(0.2 \times 0.2 \times 1 = 0.04\) to the CPI; one that is right 90 % adds \(0.02\). Make the penalty 15 cycles and the same two numbers become \(0.60\) and \(0.30\) — a \(1.6\times\) against a \(1.3\times\) slowdown on a base CPI of 1. That is why the industry kept inventing predictors long after the first one worked.

The predictor decides how often you pay for a branch; the pipeline decides how much.

One bit per branch: remember the last outcome

The simplest learning machine remembers one thing per branch: what it did last time.

Branch History Table (BHT; Hennessy & Patterson say branch prediction buffer) — a table indexed by the address of the branch instruction, whose entry is a tiny finite-state machine; the state of the machine is the prediction (notes, p. 56).

Two phrases of p. 56 are worth keeping verbatim for an open question: the BHT is "a cache-like structure that maps branch addresses to prediction states", and its history is implicit — "rather than storing an explicit sequence of past outcomes, each entry implicitly encodes the recent behavior of the branch through its FSM state". Explicit history registers come in the next lesson; here the whole past of a branch is compressed into one or two bits.

With one bit the machine has two states. The bit is the last outcome: if it says T, predict Taken; if NT, predict Not Taken. After the branch resolves, a correct prediction leaves the bit alone and a wrong one flips it — which is the same as writing the actual outcome into the bit.

T NT T NT NT T predicts Taken predicts Not Taken
Fig. 2. The 1-bit predictor as the notes draw it (p. 56). The label on an arrow is the outcome of the branch; after one surprise the prediction has already changed sides.

Indexing: low-order bits of the PC, and no tags

Which entry belongs to which branch? The notes (p. 57): "use k lower bits (right side) of the branch's address as the index", which gives \(2^k\) entries; and, in bold, "No tags: any branch with the same low-order bits shares the entry (can cause interference)". One practical detail: instructions are four bytes long and aligned, so the lowest two address bits are always 00 and a real table takes its \(k\) bits just above them; the exam phrase "low-order bits" is fine.

bits 31 … k+2 bits k+1 … 2 1 0 not used: no tag k index bits 00 picks the row tag? no tag column BHT T NT T NT T T / NT (1 bit) 2ᵏ rows
Fig. 3. Figure 15 of the notes, redrawn. The \(k\) index bits pick a row; nothing records which branch wrote it. The crossed-out column is the tag a cache would have — the BHT deliberately does without it.

Why is a table without tags acceptable? Because the worst a wrong entry can do is a wrong prediction, which the pipeline catches when the branch resolves: correctness is never at stake, only accuracy — and a tag would cost more bits than the one or two it protects. Two branches whose addresses agree in the \(k\) index bits overwrite each other's state: the conflict problem (p. 57), called branch predictor aliasing in the deepening on the next lesson's pages. The partial cures (p. 58) are the obvious ones: a bigger table, so that fewer branches collide, and hashing the address bits to spread out branches that share low-order bits.

Example 5 of the notes: two misses on a loop

Now the puzzle of the hook, on the loop the exam papers use. The 10 June 2025 paper writes it with ADDI.U $R1, $R0, 0 and ADDI.D $F2, $F0, $F0; the 2026 paper drops the dollar signs, and so does this notebook:

INIT:  ADDUI R1, R0, 0
       ADDUI R2, R0, 40      ; R2 = 20 in the June 2025 paper
LOOP:  LD    F0, 0(R1)
       FADD  F2, F0, F0
       SD    F2, 0(R1)
       ADDUI R1, R1, 4
       BNE   R1, R2, LOOP

With R2 = 40 the BNE is executed ten times: taken nine times and not taken at the exit — the pattern the notes write as T T T T T T T T T NT (p. 57). Suppose the loop has been run before, so the entry still holds the NT of the previous exit. Walk the ten executions:

1-bit predictor on the ten-iteration loop, second run of the loop (the entry holds NT from the previous exit).
Execution of the BNE12345678910
Bit before (= prediction)NTTTTTTTTTT
Branch outcomeTTTTTTTTTNT
Resultmisshithithithithithithithitmiss
Bit afterTTTTTTTTTNT

Two misses, and both have a reason. At the exit the bit still says T, because the branch was taken nine times in a row; the NT is mispredicted and flips the bit. At the next entry the bit says NT, because that is what the branch did last — the T is mispredicted and flips it back. "With 100% of 10 iterations, the BHT only catches 8 out of 10 iterations, the accuracy is 80%" (p. 57). A one-off anomaly costs two misses: the surprise itself, and its echo one execution later, when the predictor has just learned the anomaly and the old behaviour resumes. A one-bit predictor is always exactly one step behind. That is half of the puzzle.

The notes name two shortcomings (p. 57): the bit flips after a single misprediction, unstable on exactly the loops it should excel at, and the conflicts above. A bigger table does nothing for the loop exit: that miss is not interference, it is the inability of one bit to represent "nine times T, then NT".

Counting rules for the exam. A loop closed by a BNE at the bottom with \(N\) iterations executes its branch \(N\) times (\(N - 1\) taken, then not taken). A loop tested at the top (BEQ … DONE, then J LOOP at the bottom) executes the exit branch \(N + 1\) times (\(N\) not taken, then taken). The misprediction rate divides by the number of executions of the branch — the number of BHT accesses, warm-up misses included — and "the state left in the BHT" is the state after the last update. The May 2025 midterm asked for a top-tested loop with R1 = 0 … 100 on a 1-bit entry initialised Taken: 101 accesses and 2 mispredictions, the first one because the entry said T and the branch fell through, the last one at the exit.

Two bits: tolerate one surprise

The cure is a predictor that does not change its mind after one surprise. The notes call the 1-bit behaviour flip-flopping: "1 misprediction is enough to change the prediction", two misses per loop, "exiting the loop (NT mispredicted as T)" and "re-entering the loop (T mispredicted as NT)" (p. 59). The fix is a second bit that records not the last outcome but the predictor's confidence.

2-bit Branch History Table — each entry is a four-state machine: Strongly Taken (ST) and Weakly Taken (WT) predict Taken; Weakly Not Taken (WNT) and Strongly Not Taken (SNT) predict Not Taken (notes, p. 59). With the encoding ST = 11, WT = 10, WNT = 01, SNT = 00 the prediction is simply the high bit.

The rule of motion: an outcome that agrees with the prediction pushes the state toward the strong end; an outcome that contradicts it moves the state toward the other side. From a strong state it lands in the weak state of the same direction — the prediction survives one anomaly. From a weak state it crosses the line and the prediction flips; how far it crosses is where the two drawings of this machine differ. The notes' figure (p. 59) is reproduced below; the two dashed arcs are the alternative described right after it.

ST WT WNT SNT predict T predict T predict NT predict NT T NT NT T NT T NT T NT T dashed: pure saturating counter
Fig. 4. The 2-bit predictor of the notes (p. 59). Solid arrows: the notes' figure, which is Hennessy & Patterson's. Dashed: where a pure saturating counter would go instead on the same two outcomes. Everything else is identical.

Look closely at the two vertical arrows of the notes' figure: from WT a Not Taken jumps straight to SNT, and from WNT a Taken jumps straight to ST. That is the machine of Hennessy & Patterson's figure, the course's reference book. A pure saturating counter — count up on Taken, down on Not Taken, stop at 3 and at 0 — would instead go WT → WNT and WNT → WT, the dashed arcs. On every loop pattern of this course the two machines give identical tables; they differ only when the outcome alternates while the machine sits in a weak state:

The one kind of pattern where the two 2-bit machines differ: outcomes NT T NT T NT T, both starting in WT.
Execution123456
Branch outcomeNTTNTTNTT
Saturating counter: state / predictionWT / TWNT / NTWT / TWNT / NTWT / TWNT / NT
Resultmissmissmissmissmissmiss
Notes' figure: state / predictionWT / TSNT / NTWNT / NTSNT / NTWNT / NTSNT / NT
Resultmissmisshitmisshitmiss

Neither machine learns the alternation — the saturating counter is always one step behind, the notes' machine at least settles on NT and gets every other outcome right. Both are "2-bit predictors". For the exam: write the state names, which are unambiguous, reproduce the figure you were shown in class, and if a pattern alternates say which machine you use.

FSM clicker: press the outcome, watch the state

Choose a machine and a starting state, then press what the branch actually did. The current state wears the highlighter, so does the transition you just took. The machine not selected shows its two differing transitions dashed, so the difference is always in view.

  1. Select the 1-bit machine, start in a Taken state and press Taken nine times, then Not Taken once, then Taken once (a loop exit and a re-entry). Before pressing: how many mispredictions will the counter show at the end?
    What you should see

    Two: the exit (predicted T, outcome NT) and the re-entry (predicted NT, outcome T). One surprise, two misses — the second is the echo of the first.

  2. Select the notes' 2-bit machine, start in Strongly Taken, and press the same sequence. How many misses now, and where does the state end up?
    What you should see

    One miss, at the exit: ST → WT and the prediction stays Taken. The re-entry is predicted right and returns the state to ST. The weak state absorbed the anomaly.

  3. Still the notes' machine: start in Weakly Taken and press Not Taken once. Is it true that "two consecutive mispredictions are needed to change the prediction"?
    What you should see

    No: after one Not Taken the state is SNT and the next prediction is Not Taken. The two-misses rule holds only from a strong state. (A saturating counter would land in WNT — same prediction, different state.)

  4. Start in Weakly Taken and press NT, T, NT, T, NT, T, first with the notes' machine, then with the saturating counter. Which one mispredicts more?
    What you should see

    The saturating counter misses all six (it bounces WT ↔ WNT, always one step behind); the notes' machine misses four and ends in WNT: after the first miss it bounces SNT ↔ WNT, predicting Not Taken and getting only the T outcomes wrong. The two variants differ on exactly one transition out of each weak state — the dashed arrows — and on nothing else.

Effect on the loop: one miss instead of two

Back to the ten-iteration loop, second run, the entry left in WT by the previous exit (p. 60):

2-bit predictor on the same loop, second run. Both machines give this table.
Execution of the BNE12345678910
State beforeWTSTSTSTSTSTSTSTSTST
PredictionTTTTTTTTTT
Branch outcomeTTTTTTTTTNT
Resulthithithithithithithithithitmiss
State afterSTSTSTSTSTSTSTSTSTWT

"Exit NT causes 1 misprediction, but FSM moves from Strongly Taken to Weakly Taken. So the prediction remains Taken" (p. 60). At the next entry the branch is taken, the prediction is Taken, and the state returns to ST. "Only 1 misprediction per loop, improving accuracy to 90% (from 80%)." The weak state absorbed the exit without forgetting the bias.

12345678910 outcome TTTTTTTTTNT 1-bit says NTTTTTTTTTT 2 misses: entry and exit

Before: 1 bit — 80 %

12345678910 outcome TTTTTTTTTNT 2-bit says TTTTTTTTTT 1 miss: the exit only

After: 2 bits — 90 %

Fig. 5. The same loop, second run, two predictors. The orange crosses are mispredictions. The 1-bit predictor pays for the exit twice; the 2-bit predictor pays once, because Weakly Taken still predicts Taken at the re-entry.

Why two bits and not four? The studies Hennessy & Patterson report show that 2-bit counters get almost all the benefit of longer ones, and a longer counter is slower to follow a real change of behaviour — the balance between "prediction stability" and "adaptability" of p. 60. A bias of nine to one is as much as a counter can ever learn.

The 2-bit counter was invented twice: by Tom McWilliams and Curt Widdoes in 1977 for the Lawrence Livermore S-1 supercomputer, and independently by Jim Smith at Control Data in 1979. Smith published it at ISCA 1981 in "A Study of Branch Prediction Strategies"; his 1999 Eckert–Mauchly award citation lists "saturating counters for branch prediction" first, and almost every microprocessor since builds on that paper.

The exam table: 10 June 2025, Question 5

The only official exercise on these pages is a quiz worth 3 points. The loop is the one above with R2 = 20, so R1 takes 4, 8, 12, 16, 20 at the BNE: five executions, outcomes T T T T NT. The twist: a "single-entry 2-bit Branch History Table initialized in the state Strongly Not-Taken" — the loop has never run, and the entry starts as far from Taken as it can. The paper's table has three rows and one column per iteration, with the first column filled in:

The table of the 10 June 2025 quiz, completed with the saturating counter (with the notes' figure the 3rd state reads Strongly Taken — same prediction). The paper gives the first column; the last row is the one you keep in your head.
Iteration1st2nd3rd4th5th
Prediction StateStrongly Not TakenWeakly Not TakenWeakly TakenStrongly TakenStrongly Taken
PredictionNot TakenNot TakenTakenTakenTaken
Branch OutcomeTakenTakenTakenTakenNot Taken
(hit or miss)missmisshithitmiss

Three misses in five executions: a misprediction rate of 3/5 = 60 %, and the state left after the last update is ST → Weakly Taken. Three sanity checks save you from the distractors (60, 90, 99, 100, 80 %): 100 % and 99 % are impossible, because any counter that has seen two Taken in a row predicts the third right; 90 % is not a whole number of misses out of five (read as an accuracy, it is the notes' ten-iteration loop); 80 % would be four misses, and an entry started in SNT already predicts right at the third execution — read as an accuracy, 80 % is 1 miss in 5, the answer of someone who counted the exit and forgot that the two warm-up misses count. In the third column the notes' figure gives Strongly Taken instead of Weakly Taken (WNT → ST on a Taken); the prediction is Taken either way, and so is the rest of the table.

BHT playground: a counted loop, execution by execution

A single BHT entry follows the branch of a counted loop. The table has the rows of the June 2025 paper (Prediction State, Prediction, Branch Outcome) plus the hit-or-miss row, one column per execution of the branch. Change the predictor, the initial state, the loop length and how many times the loop is run.

  1. Press the "10 June 2025" preset. Before looking: in which columns are the misses, and what is the state after the fifth execution?
    What you should see

    Misses in the 1st, 2nd and 5th columns: 3 of 5, a 60 % misprediction rate; the state left is Weakly Taken. The two warm-up misses from Strongly Not Taken count as much as the exit miss. (The widget follows the notes' figure, so its 3rd column reads Strongly Taken; switch to the saturating counter for Weakly Taken — same predictions, same misses.)

  2. Keep N = 5 and set "times the loop is run" to 2. The second run of the loop: how many misses does the 2-bit entry make, and how many would a 1-bit entry make? Predict, then switch the predictor.
    What you should see

    2-bit: one miss in the second run, at the exit (ST → WT, prediction stays Taken, the re-entry is right). 1-bit: two misses per run, at the exit and at the re-entry — 1-bit misses twice per loop execution, 2-bit once. That is the whole reason for the second bit.

  3. Switch to the top-tested loop shape, 1-bit, initial state Taken, one run, and push N to the end of the slider, 12 (the May 2025 midterm had R1 = 0 … 100). How many columns, how many misses?
    What you should see

    13 columns: N + 1 = 13 executions (12 Not Taken, then the exit Taken) and 2 misses — the first, because the entry said Taken, and the last. With N = 100 the same reasoning gives 101 accesses and 2 misses.

  4. Set N = 1 with the bottom-tested shape and a 2-bit entry in Strongly Taken. What happens?
    What you should see

    One execution, Not Taken at once: one miss out of one, 100 %, and the state drops to Weakly Taken. A loop that runs once is a branch that is never taken — an "always taken" bias is the wrong bias for it.

One thing no counter can do, whatever its width: predict a pattern. The exit of a counted loop is perfectly predictable — after nine Taken comes a Not Taken, every time — and so is a branch that alternates T NT T NT; both defeat every counter, because a counter stores a bias, not a sequence. Capturing the sequence needs explicit history: lesson 6.

Where to? The branch target buffer

Suppose the BHT is perfect. In IF the processor knows the BNE will be taken. Where does it fetch from? The target is PC plus the offset encoded in the instruction, and in our pipeline that sum is computed in ID — one cycle too late. The notes' deepening says it in one sentence (p. 63): "even if we can predict that the branch will be taken, we still don't know where to fetch from". The fetch unit must "stall instruction fetch, or fetch sequentially and later flush": one bubble on every taken branch, even when the direction was predicted correctly.

C1C2C3C4 BNE IF ID EX SUBI IF LD IF ID flushed: 1 cycle lost

Before: BHT only, target unknown in IF

C1C2C3C4 BNE IF ID EX LD IF ID EX target in the next cycle

After: BTB hit in IF

Fig. 6. The loop's BNE, correctly predicted taken, with and without a BTB. Without one, the fetch unit has nowhere to go until ID has computed the target: the sequential SUBI is fetched and thrown away. With a hit (highlighted) the PTA replaces PC + 4 at the end of C1 and the LD at the top of the loop follows at once.

Branch Target Buffer (BTB) — "a specialized cache used to store target address of taken branches" (notes, p. 61): a table indexed by the branch address whose data is the Predicted Target Address, so that fetch can continue from the target in the same cycle. The core idea in one line, also from p. 61: the BHT "predicts whether a branch will be taken", the BTB "predicts where the program should go if the branch is taken".

The structure is that of a direct-mapped cache (p. 61). The branch address is split into a tag and an index; the index selects one entry; the stored tag is compared with the address tag, and only an equal tag is a hit — the tags "ensure the indexed entry really belongs to the current branch". Each entry holds the tag and the PTA, "often combined with T/NT bits from a Branch History Table (1-bit or 2-bit)" (Figure 17 of the notes), so one lookup answers both questions. Only taken branches are stored, and an entry is written when a taken branch resolves and its target is known (p. 64): the first execution of every branch is a cold miss, as in any cache.

BTB lookup: whether, where, and why the tag

A four-entry BTB indexed by address bits 3–2 serves the loop of this lesson and the code after it. Pick the instruction being fetched; the address splits into tag and index, the indexed entry lights up, the tag comparison and the BHT's bit decide what the multiplexer feeds into the PC. The readouts give the three cases of the notes' Table 4 and what each costs in this pipeline.

  1. BTB empty, fetch the BNE at 0x210 with the BHT predicting Taken. What is the next PC, and what does the branch cost if it is taken?
    What you should see

    A miss: entry 0 is empty. The fetch unit defaults to PC + 4 = 0x214 even though the BHT said Taken — "predict Taken, BTB miss". If the branch is taken, 1 cycle is lost and the entry is allocated when the target is computed, so the next execution hits.

  2. Switch the contents to "after the loop ran". Same fetch: next PC and cost?
    What you should see

    Tag 0x21 matches entry 0: hit. The PTA 0x200 replaces PC + 4 in this same IF cycle — "predict Taken, BTB hit", 0 cycles if the branch is taken. Set the actual outcome to Not Taken and it costs 1 cycle: the instruction fetched from 0x200 is flushed.

  3. Keep that BTB and fetch the FMUL at 0x230, which is not a branch. First with the tag compared, then with the comparison switched off. Where does fetch go?
    What you should see

    With tags: entry 0 holds tag 0x21, the address tag is 0x23 — miss, next PC 0x234, nothing happens. Without tags: a false hit, and the fetch unit jumps to 0x200 after a multiply. The BTB predicts where, and a wrong "where" redirects fetch — that is why the BTB carries tags while the untagged BHT, which only predicts whether, can afford to be wrong.

  4. Fetch the BNE with the BTB full but the BHT predicting Not Taken. Is the BTB consulted?
    What you should see

    No: "predict Not Taken, BTB not used", next PC 0x214. A BTB hit means nothing without a Taken prediction. If the branch is in fact taken, 1 cycle.

The notes summarise the behaviour in their Table 4 (p. 62). The cost column is the one you add yourself, for the course pipeline:

Table 4 of the notes, with the cost of each case when the branch is resolved in ID.
PredictionBTB useActionCost if takenCost if not taken
Predict Not TakenBTB not usedFetch from PC + 41 cycle0
Predict Taken (BTB hit)BTB usedFetch from the PTA stored in the BTB01 cycle
Predict Taken (BTB miss)BTB missStall or default to PC + 4, then calculate the BTA in ID; allocate the entry1 cycle0

On a hit with a Taken prediction "the next PC is immediately set to the target address, in the same cycle" (p. 64): a correctly predicted taken branch now costs nothing. On a miss "it's as if there's no BTB for that branch at all" (p. 64): fetch defaults to PC + 4, ID computes the real target, a taken branch costs its usual cycle — and the entry is allocated, so the next execution hits. "Clearly, the best option is to have a BTB with a certain rate of misses rather than no BTB at all." The two advantages the notes list (p. 62) are the words for an open question: it "eliminates delay from calculating the branch target address manually" and "enables speculative instruction fetch from correct target, improving pipeline efficiency".

Why the BTB has tags and the BHT has none

Here the "indexed before decode" remark pays off. A BTB hit means "the instruction at this address is a taken branch, and here is where it goes" — and the fetch unit acts on it at once. Without tags, any instruction whose low-order address bits match a stored branch would hit, and the fetch of an ordinary FMUL would be redirected into the middle of a loop: a wrong-path fetch that must be detected and undone. With tags a miss safely means "treat this as not a branch". The BHT can live without tags because its one or two bits are only used once the instruction is known to be a branch, and a wrong bit costs accuracy, never correctness.

The BHT predicts whether and may be wrong; the BTB predicts where and must not redirect a non-branch — so the BTB carries tags.

"The BTB is a direct-mapped cache … tags are used for associative lookup." The notes (p. 61) mix two words. In a direct-mapped structure the index selects one entry and a single tag comparison validates it — what Figures 16 and 17 draw. "Associative lookup" means comparing the address with all stored tags in parallel, a fully associative buffer. Both organisations exist; at the exam write "a cache: index, tag compare, hit or miss" and you are safe either way.

What a BTB is worth, in cycles and in bits

Hennessy & Patterson's textbook example gives the expected penalty per branch when a BTB is present. Call \(p_{hit}\) the hit rate, \(p_{ok}\) the accuracy of the prediction on a hit and \(p_{taken}\) the fraction of taken branches. A branch costs \(P\) cycles in two situations only:

  1. A branch costs \(P\) cycles exactly when fetch went the wrong way. With a BTB there are two ways for that to happen; a miss on a not-taken branch is not one of them, because PC + 4 was the right choice anyway.

  2. Case A — a hit whose prediction was wrong. Probability \(p_{hit}\,(1 - p_{ok})\), cost \(P\):

    \[ p_{hit}\,(1 - p_{ok})\,P \]
  3. Case B — a miss on a branch that turns out taken: fetch defaulted to PC + 4. Probability \((1 - p_{hit})\,p_{taken}\), cost \(P\):

    \[ (1 - p_{hit})\,p_{taken}\,P \]
  4. Add the two. With the textbook's numbers — 90 % hits, 90 % accuracy on a hit, 60 % of branches taken — and \(P = 1\):

    \[ \begin{aligned} \text{penalty} &= p_{hit}\,(1 - p_{ok})\,P \\ &\quad + (1 - p_{hit})\,p_{taken}\,P \end{aligned} \] \[ = 0.9 \times 0.1 + 0.1 \times 0.6 = 0.15 \]

    cycles per branch. (The textbook's own pipeline resolves branches a stage later, \(P = 2\), and gets 0.30.) Multiply by \(f_b\) for the contribution to the CPI.

And why keep two tables instead of one big BTB with direction bits? Count the bits. With 32-bit addresses and 1024 entries the tag has \(32 - 10 - 2 = 20\) bits, the PTA 30 (word-aligned) and the counter 2: 52 bits per entry, 6.5 KB for the table. A 2-bit BHT with 4096 entries — four times as many branches — costs \(4096 \times 2\) bits = 1 KB. Direction is cheap and tolerates collisions, so it gets a large untagged table; targets are expensive and must not collide, so they get a small tagged one. Hence what the BTB does not do (p. 64): it does not decide the direction, does not compute the target, does not replace the BHT; "it simply remembers previously computed target addresses for quick access during fetch, like a cache for branch targets". And only taken branches, because the "target" of a not-taken branch is PC + 4, which the fetch unit already has.

The puzzle resolved, and the words for the open question

Back to the loop of the hook: always taken 90 %, one bit 80 %, two bits 90 %. The dynamic predictor only ties with the static rule — so what was it for? For every branch whose bias the compiler cannot know: the loop that runs twice in one run and a million times in another, the if that follows the data. There the static rule is a coin toss and the counter learns in two executions — with no delay slots, no profiling run, no recompilation. And with a BTB beside it the nine correctly predicted taken branches cost 0 cycles instead of 1 each. The simplest learner lost to the dumbest rule on the one loop where that rule was already perfect; the second bit and the target buffer are what make learning pay.

The January 2026 paper asked "What are the main benefits to introduce the dynamic branch prediction in a modern microprocessor?", and the June 2026 paper wants "the main concepts and benefits" of "dynamic branch prediction and speculative execution" in five lines. Five lines, each with its why:

The matching five lines for "Explain the main purpose to introduce the Branch Target Buffer" (January 2026, Question 2) are the model answer in the exam section below. Their skeleton: whether versus where; the target is computed in ID; a tagged cache read in IF; the stored target in the same cycle, zero cycles on a hit; filled when a taken branch resolves; PC + 4 and the normal penalty on a miss.

Exam-style questions

Let's consider the Dynamic Branch Prediction techniques used in modern microprocessors. (a) What are the main benefits to introduce the dynamic branch prediction in a modern microprocessor? (b) Explain how works a Branch History Table.

Show model answer

(a) The hardware predicts each branch at run time from its past behaviour, so the pipeline keeps fetching instead of stalling. Benefits: fewer mispredictions and hence a lower CPI (in \(\text{CPI} = \text{CPI}_{\text{ideal}} + f_b (1 - a) P\) the predictor raises the accuracy \(a\), the penalty \(P\) is fixed by the pipeline); adaptation to the actual input data and program phases, which a static compile-time rule cannot see; it is essential in deep and wide pipelines, where every misprediction wastes depth × width instructions; it enables speculative execution past unresolved branches, with results committed only when the branch resolves; it needs no compiler support, delay slots or profiling, so existing binaries benefit.

(b) A Branch History Table is a table indexed by the low-order bits of the branch PC, without tags (so two branches may share an entry: aliasing). Each entry is a small finite-state machine: 1 bit storing the last outcome, or a 2-bit machine with the states Strongly Taken, Weakly Taken, Weakly Not Taken, Strongly Not Taken, predicting Taken in the first two. The table is read in IF with the fetch PC and the prediction decides whether to fetch PC + 4 or the target; when the branch resolves the entry is updated with the outcome. With 2 bits a single anomaly, such as a loop exit, moves a strong state to the weak state of the same direction without changing the prediction, so a loop branch is mispredicted once per execution of the loop instead of twice.

The first two of the five sub-points of Question 2 of the January 2026 paper; the June 2026 paper asks the same in one sub-point of the 8-point question. A complete answer has the mechanism (indexed by the PC, no tags, FSM per entry, read in IF, updated at resolution), the 1-bit vs 2-bit contrast with the loop-exit argument, and benefits stated as cause and effect, not as adjectives. Do not write "reduces the penalty": it reduces the rate.

Explain the main purpose to introduce the Branch Target Buffer.

Show model answer

The branch target address is computed in the ID stage, so even a correct Taken prediction in IF leaves the fetch unit without an address: one bubble on every taken branch. The Branch Target Buffer removes this control hazard. It is a small cache indexed by the branch PC, with tags, whose data is the predicted target address of taken branches (often together with the T/NT prediction bits). On a hit with a Taken prediction the next PC is set to the stored target in the same IF cycle, so a correctly predicted taken branch costs zero cycles. An entry is written when a taken branch resolves and its target is known; on a miss, fetch defaults to PC + 4 and the branch pays the normal penalty if taken. The tags are necessary because a false hit would redirect the fetch of a non-branch instruction — unlike the BHT, which only predicts the direction and can be untagged.

The third sub-point of Question 2 of the January 2026 paper. The examiner looks for "whether versus where", "in the same cycle", "indexed by the PC with tags", "stores taken branches, filled at resolution", and the three cases (predict NT; predict T and hit; predict T and miss). Do not write "eliminates the control hazard" without qualification: it eliminates it on a hit with a correct prediction.

Let's consider the following LOOP to be executed on a processor with a single-entry 2-bit Branch History Table initialized in the state Strongly Not-Taken:

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

After the last iteration, how much is the misprediction rate on the BNE instruction? Motivate your answer by completing the table (rows Prediction State / Prediction / Branch Outcome, one column per iteration; the first column is given: Strongly Not Taken, Not Taken, Taken).

  • 60 % Five executions (R1 = 4, 8, 12, 16, 20), misses at the 1st, 2nd and 5th: 3/5.
  • 90 % Impossible on five executions (it would be 4.5 misses); read as an accuracy, 90 % is the notes' ten-iteration steady state, not this cold start.
  • 99 % Impossible: after two Taken in a row any 2-bit counter predicts the third Taken correctly.
  • 100 % Impossible for the same reason: the 3rd and 4th executions are predicted right.
  • 80 % Four misses would need the warm-up to last four executions; from SNT it lasts two.
Show model answer

The BNE is executed with R1 = 4, 8, 12, 16, 20: five times, Taken four times and Not Taken at the exit.

Iteration1st2nd3rd4th5th
Prediction StateStrongly Not TakenWeakly Not TakenWeakly TakenStrongly TakenStrongly Taken
PredictionNot TakenNot TakenTakenTakenTaken
Branch OutcomeTakenTakenTakenTakenNot Taken

Mispredictions at the 1st, 2nd and 5th execution: misprediction rate = 3 / 5 = 60 % (Answer 1). With the FSM of the lecture figure the 3rd state is Strongly Taken (WNT → ST on a Taken); the predictions and the rate are the same.

The 10 June 2025 paper, Question 5, worth 1 point for the answer and 1 for the table. Count the executions from the register values, not from the word "iterations", and count the warm-up misses. Write the state names in full, as the paper does.

Same loop and same Branch History Table. After the last iteration, what is the state of the prediction left in the Branch History Table?

  • Strongly Taken That is the state before the 5th execution; the exit Not Taken moves it one step down.
  • Weakly Taken After four Taken the entry is in Strongly Taken; the final Not Taken moves it to Weakly Taken, in both FSM variants.
  • Strongly Not Taken The initial state; after four Taken the counter is at the other end.
  • Weakly Not Taken One Not Taken from Strongly Taken reaches only the weak Taken state; a second one would be needed.
Show model answer

Before the 5th execution the state is Strongly Taken (after four Taken). The outcome is Not Taken, so the state moves one step: Strongly Taken → Weakly Taken (Answer 2). The question asks for the state after the last update, one transition beyond the last column of the table.

Second part of the same quiz. The trap is to answer with the state used for the last prediction (Strongly Taken) instead of the state left by it.

Let's consider a processor with a 1-entry 1-bit Branch History Table initialized as Taken, executing the following code (only the BEQ accesses the BHT):

      ADDUI R1, R0, 0
      ADDUI R2, R0, 100
LOOP: BEQ   R1, R2, DONE
      ADD   R5, R5, R4
      ADDUI R1, R1, 1
      J     LOOP
DONE:

How many mispredictions occur on the BEQ? (State also the number of BHT accesses.)

Show model answer

The BEQ is executed with R1 = 0, 1, …, 100: 101 accesses to the BHT. Outcomes: Not Taken 100 times, then Taken at R1 = 100. The entry starts as Taken: 1st access, predict Taken, outcome Not Taken → misprediction, bit ← NT; accesses 2 to 100 predict Not Taken correctly; 101st access, predict Not Taken, outcome Taken → misprediction. Total: 101 accesses, 2 mispredictions (rate 2/101 ≈ 2 %).

Quiz 5 of the May 2025 midterm as the notes report it (its options paired accesses and mispredictions; "101 and 2" is the right pair). A top-tested loop executes its exit branch N + 1 times; the first miss comes from the initialisation, the second from the exit — both are changes of direction, and a 1-bit entry pays one miss per change.

An inner loop of 8 iterations, closed by a BNE (taken 7 times, then not taken), is executed 3 times by an outer loop. Only the inner BNE accesses a single-entry Branch History Table. (a) With a 1-bit BHT initialized Not Taken, give the number of BHT accesses, the number of mispredictions, the misprediction rate and the final state. (b) Same with a 2-bit BHT initialized Strongly Not Taken. (c) How many mispredictions per execution of the inner loop does each predictor make in steady state?

Show model answer

(a) 3 × 8 = 24 accesses; outcomes T T T T T T T NT, three times. The 1-bit entry mispredicts at access 1 (NT predicted, T), at 8 (exit), at 9 (re-entry: the entry holds NT), at 16, 17 and 24: 6 mispredictions, 6/24 = 25 %, final state Not Taken (the last outcome).

(b) From Strongly Not Taken: access 1 predicts NT (miss, → WNT), access 2 predicts NT (miss, → WT with a saturating counter, → ST with the lecture figure), accesses 3–7 predict T correctly (the state is ST from access 4 at the latest), access 8 predicts T but the branch exits (miss, ST → WT); access 9 predicts T from WT correctly (→ ST), accesses 10–15 hit, 16 misses (→ WT), 17 hits, 18–23 hit, 24 misses (→ WT). Mispredictions at 1, 2, 8, 16, 24: 5, rate 5/24 ≈ 21 %, final state Weakly Taken.

(c) Steady state: 2 per inner-loop execution with 1 bit (exit and re-entry), 1 with 2 bits (exit only). The 2-bit predictor also paid one extra warm-up miss from Strongly Not Taken.

An exercise in the style of the June 2025 quiz with the counting extended over several executions of the loop. The examiner checks the three sources of misses — initialisation, exit, re-entry — and that you know which one the second bit removes. Both 2-bit variants give the same numbers here.

During the execution of a program, the number of mispredictions depends on the initialization and the size of the Branch History Table (BHT). True or False? Motivate your answer.

  • True Initialisation sets the warm-up misses (a 2-bit entry started Strongly Not Taken misses the first two taken executions of a loop; started Strongly Taken it misses none); the size sets how many branches share an untagged entry, so a small table makes unrelated branches overwrite each other's state (aliasing) and mispredict.
  • False Both effects are real: the June 2025 quiz counts the two warm-up misses from Strongly Not Taken, and an untagged table of 2^k entries aliases every pair of branches with equal low-order PC bits.
Show model answer

True. (1) Initialization: the initial state of the entry decides whether the first executions of a branch are predicted correctly — a loop branch whose entry starts Strongly Not Taken costs two warm-up mispredictions, one that starts Weakly Not Taken costs one, one that starts Taken costs none. (2) Size: the BHT is indexed by k low-order bits of the PC without tags, so with 2^k entries all branches sharing those bits share the entry and interfere (aliasing); a larger table spreads the branches over more entries and reduces the interference. (The number of mispredictions also depends on the predictor's FSM, 1-bit or 2-bit, and on the program's branch patterns.)

Quiz 4 of the May 2025 midterm, a True/False with "motivate". The motivation earns the point: name both mechanisms and the word aliasing.

Check yourself

A loop branch is taken 9 times and not taken once, and the loop is executed many times. In steady state, what accuracy does a 1-bit BHT reach on this branch?

  • 90 % That is the accuracy of "always taken" and of the 2-bit predictor: one miss per loop. The 1-bit predictor misses twice.
  • 80 % Two misses in ten executions: the exit (predicted T) and the re-entry (predicted NT, the echo of the exit).
  • 100 % No counter predicts the exit: it has no way to know that the ninth Taken is the last one.
  • 10 % The predictor is wrong twice, not eight times — it tracks the bias, just one step late.

A 2-bit entry is in the state Weakly Taken. Which statements are true?

  • Its prediction is Taken Both Taken states predict Taken; "weak" says how the next update behaves, not how sure the guess is.
  • A single Not Taken outcome makes the next prediction Not Taken From a weak state one contradicting outcome flips the prediction: to WNT in a saturating counter, to SNT in the notes' figure.
  • Its prediction is "undecided" The prediction is binary; the fetch unit needs a direction, and WT gives Taken.
  • Two consecutive Not Taken outcomes are needed before it predicts Not Taken That holds only from Strongly Taken. From Weakly Taken one is enough.

A picture to remember: strong = "I am sure, one surprise will not move me"; weak = "I am still Taken, but one more and I switch".

In \(\text{CPI} = \text{CPI}_{\text{ideal}} + f_b (1 - a) P\), what does replacing a 1-bit BHT by a 2-bit BHT change?

  • Only \(a\), the accuracy The predictor changes how often a branch is mispredicted; nothing else in the formula is its business.
  • \(P\), the penalty The penalty is set by the pipeline — where the branch resolves. The notes' "reduces misprediction penalty" is the red-pen error of this lesson.
  • \(f_b\), the branch fraction The program has as many branches as before; the predictor executes none of them.
  • \(a\) and \(P\) together Only \(a\). A shorter penalty would need a different pipeline, not a different predictor.

Why does the BTB need tags while the BHT does not?

  • A false BTB hit would redirect the fetch of a non-branch; a wrong BHT bit only lowers accuracy on a real branch The BTB is consulted before decode and its hit changes the next PC at once; the BHT's bit is only acted on for an instruction that is a branch, and the pipeline corrects a wrong direction at resolution.
  • Because the BTB is bigger It is smaller: its entries hold a 30-bit address, so there are fewer of them. Size is not the reason for the tags.
  • Because the BHT is read in ID, after decode, and the BTB in IF Both are read in IF with the fetch PC. The difference is what a hit does: the BTB's hit redirects fetch, the BHT's bit is just a direction.
  • Because tags are needed for 2-bit counters The counters have nothing to do with it: a tagged BHT would work, it would just cost more bits than it protects.

The BHT predicts Taken, the BTB misses (the fetch unit defaults to PC + 4), and the branch turns out Not Taken. How many cycles are lost in this pipeline?

  • 0 On a BTB miss the fetch unit defaults to PC + 4, which is exactly where a not-taken branch goes. The "Taken" prediction was wrong but could not be acted on.
  • 1 One cycle would be lost if the branch were taken (the default PC + 4 was wrong) — not here.
  • 2 The course pipeline resolves branches in ID; the maximum cost of any case is one cycle.

When does a branch get an entry in the BTB?

  • When it resolves as taken and its target is known The target is computed in ID and written into the BTB with the branch's tag; the first execution is a cold miss.
  • When the compiler emits it The BTB is hardware filled at run time; the compiler knows nothing about it.
  • When it is fetched for the first time At fetch the target is unknown — that is the whole problem the BTB solves.
  • Every branch, taken or not, when it resolves Only taken branches are stored: the "target" of a not-taken branch is PC + 4, which the fetch unit already has.

Which of these branch behaviours are perfectly predictable in principle, yet defeat every 1-bit or 2-bit counter even after warm-up?

  • Strictly alternating: T NT T NT … A counter is always one step behind an alternation; the notes' machine gets half right, the saturating counter none.
  • The exit of a counted loop of 10 iterations, run many times The exit is predictable in principle (after nine T comes NT) but a counter stores a bias, not a position in a sequence; it misses the exit every time.
  • A branch taken 99 % of the time Its rare exceptions are not predictable from the past, so nothing could beat a counter here: it learns the bias in two executions and misses only those exceptions — that is what it is for.
  • A branch that is always taken After at most two warm-up executions a counter predicts it right forever.

Patterns need history, not wider counters — the subject of the next lesson.

Key take-aways

What to watch and read