The Classic Five-Stage Pipeline

Think of a laundromat. You have four loads to wash, dry, fold and put away. The slow way is to carry one load all the way through — wash, dry, fold, store — before you even start the next. The clever way is a pipeline: the moment the first load leaves the washer, the second load goes in, while the first moves to the dryer. All four machines run at once, each on a different load. You finish in a fraction of the time even though no single load got any faster.

A pipelined processor does exactly this with instructions. You already met the idea of overlapping instructions and the fetch–decode–execute cycle. The classic RISC five-stage pipeline — the one at the heart of MIPS, early ARM, and every computer-architecture textbook — chops the work of one instruction into five equal steps and keeps five instructions in flight at once, each in a different step.

The five stages

Every instruction marches through the same five stages, in order, one stage per clock cycle:

StageNameWhat happens
IFInstruction Fetchread the instruction word from memory; bump the program counter
IDInstruction Decodedecode the opcode; read source registers from the register file
EXExecutethe ALU computes — an arithmetic result, or a memory address
MEMMemory accessload reads data memory / store writes it (other instructions idle here)
WBWrite-Backwrite the result into the destination register

Between each pair of stages sits a pipeline register — a bank of flip-flops (IF/ID, ID/EX, EX/MEM, MEM/WB) that latches everything a stage produces at the tick of the clock, so the next stage can pick it up next cycle. These registers are the guardrails that keep five instructions from crashing into one another; without them the pipeline is just a tangle of wires.

The diagram every architect draws

Here is the picture. Each row is one instruction; each column is one clock cycle; each coloured cell shows which stage that instruction is in during that cycle. Press play (or step forward) and watch the diagonal staircase form: the pipeline fills for the first four cycles, runs full at cycle 5, then drains over the last four.

Two numbers to read off this figure. The latency of any single instruction is still 5 cycles — I1 needs cycles 1 through 5. But once the pipe is full, a new instruction completes every single cycle: that is a steady-state throughput of one instruction per cycle, \text{CPI} = 1. Pipelining does nothing for latency; it multiplies throughput.

How many cycles, exactly?

Run N instructions through a k-stage pipeline. The first instruction needs k cycles to reach the end (that is the fill). After it, each of the remaining N-1 instructions pops out one cycle later. So the total is

T_{\text{pipe}} \;=\; k \;+\; (N-1) \quad\text{cycles.}

The unpipelined machine, doing one whole instruction at a time, takes N \times k cycles. The speedup is their ratio:

S \;=\; \frac{N k}{\,k + (N-1)\,} \;\xrightarrow[\;N \to \infty\;]{}\; k.

For a long stream of instructions the fill and drain become a rounding error and the speedup approaches k — the ideal is speedup equal to the number of stages. Our five-stage machine tops out near 5\times. That is the whole promise of pipelining in one line.

Worked example — and why it isn't quite 5×

Push N = 3 instructions through our k = 5 stages. The pipeline takes 5 + (3-1) = 7 cycles; the unpipelined machine takes 3 \times 5 = 15. The speedup is only 15/7 \approx 2.14\times — nowhere near 5, because with just three instructions the fill and drain dominate. Now try N = 1000: 5000 / 1004 \approx 4.98\times, almost the full 5. The pipeline only pays off when you keep it fed. Run the code and watch the ratio climb toward k.

// Cycles to run N instructions on a k-stage pipeline vs a non-pipelined machine. function pipelinedCycles(n: number, k: number): number { return k + (n - 1); // k-cycle fill, then one instruction per cycle } function speedup(n: number, k: number): number { return (n * k) / pipelinedCycles(n, k); } const k = 5; // IF, ID, EX, MEM, WB console.log(`Non-pipelined does one instruction every ${k} cycles.`); for (const n of [1, 2, 3, 10, 100, 1000]) { const cyc = pipelinedCycles(n, k); console.log(`N=${n}\tpipe=${cyc} cyc\tspeedup=${speedup(n, k).toFixed(2)}x`); } console.log(`Ceiling as N grows: ${k}x (the number of stages).`);

People tried. The Pentium 4's "Prescott" core ran a 31-stage pipeline chasing raw clock speed. It backfired. Deeper pipes mean each stage does less real work but still pays a fixed latch-and-clock overhead, so the useful fraction of every cycle shrinks. Worse, a mispredicted branch now throws away thirty instructions' worth of work instead of a handful, and the fill/drain penalty balloons. Prescott ran hot, mispredicted expensively, and Intel abandoned the "megahertz race" for the wider, cooler Core designs. There is a sweet spot, and it is closer to 10–20 stages than to 30.

The seductive mistake is to think "five stages, so each instruction is five times faster." Exactly backwards. Look at the diagram again: I1 still occupies cycles 1 through 5 — its latency is unchanged, and each stage's clock period may even be a touch longer because of the pipeline-register overhead. What improves is throughput: the rate at which finished instructions stream out the far end. Pipelining is about keeping every unit busy, not about rushing any one instruction through. Latency and throughput are different axes — never conflate them.

Why this shape won

The five-stage split is not sacred — it is a balance. RISC instruction sets were deliberately designed so that fetch, decode, a single ALU op, one memory access, and a register write are each about the same amount of work, so the stages take roughly equal time and the clock can tick as fast as the slowest stage allows. Almost everything later in this module — data hazards, control hazards, structural hazards, precise exceptions — is about the messy reality that instructions are not truly independent, and the pipeline occasionally has to stall, forward, or flush to keep giving correct answers. This clean picture is the baseline we will now start to complicate.