8 lessons

Executing Instructions

Fetch, decode, execute, write back — then the pipeline that overlaps them, the hazards that break the overlap, and the forwarding and stalls that patch it up.

SourceCompilerInstructionsFront EndExecutionRegistersCachesMemoryI/OBehavior
Fetch, Decode, Execute — and Why That Story Is Incomplete

Every introduction to CPUs teaches a tidy four-step cycle. It is genuinely useful and it has not described a shipping processor since the early 1990s. Both halves of that sentence matter: learn the model, then learn precisely which parts of it modern hardware abandoned.

Q · What are the steps a CPU takes to run a single instruction — and how much does that tidy four-step story still describe a modern processor?
Instruction Fetch: Code Is Data Too

Before a CPU can do anything with an instruction it has to load it from memory, through a cache, at an address it may have had to guess. The front end is a supply chain, and a starved front end leaves the most sophisticated execution engine in the world with nothing to do.

Q · Where do instruction bytes come from, and what happens to a program when the CPU cannot get them fast enough?
Decode: Turning Bytes Into Intent

A fetched block is just bytes. Decode is where the CPU works out where one instruction ends and the next begins, what operation is requested, and which registers it touches — and how hard that is depends enormously on the instruction encoding the ISA chose.

Q · How does a CPU turn a block of undifferentiated bytes into an operation with operands — and why is that harder on some architectures than others?
Execute: Not All Operations Cost the Same

The execute phase is where the work happens, in a set of specialised functional units. Two things surprise people: different operations take very different numbers of cycles, and an operation's latency and its throughput are separate numbers that can differ by an order of magnitude.

Q · What actually performs the work of an instruction, and why do some operations cost far more than others?
Load and Store: Why Arithmetic Happens in Registers

Almost every ISA makes you bring data into a register before you can compute with it, and write it back explicitly. That looks like bureaucracy until you notice that a load is the one instruction whose cost varies by two orders of magnitude depending on where the data happens to be.

Q · Why do CPUs insist on moving data into registers before operating on it, and what makes a load different from every other instruction?
Pipelining: Throughput Without Making Anything Faster
▶ lab

A pipelined CPU does not execute any single instruction more quickly than an unpipelined one. It overlaps them, so instructions complete more often. Understanding that pipelining buys throughput and not latency explains most of what modern CPUs do and why they do it.

Q · How does overlapping instruction execution increase performance, and what exactly does it improve — and not improve?
Pipeline Hazards: The Three Ways Overlap Fails

Pipelining assumes the next instruction can always start. Three situations break that assumption — a needed value is not ready, the next address is not known, or two instructions want the same hardware — and every hardware performance problem is a variation on one of them.

Q · What prevents a pipeline from starting a new instruction every cycle, and how do the three causes differ?
Forwarding and Stalls: Paying for Dependencies

When one instruction needs another's result, the hardware has two options: route the value directly to where it is needed, or wait. Forwarding covers most cases at no cost. The case it cannot cover — a load feeding the very next instruction — is the shape of every serious memory performance problem.

Q · When an instruction depends on the one before it, what does the hardware do — and when does that dependency actually cost time?