---
title: The Fetch-Decode-Execute Cycle
module: Processor Design
moduleNumber: 4
lessonNumber: 1
order: 401
summary: >
  A processor is a machine that repeats one loop forever: read the next instruction
  from memory, figure out what it asks for, do it, and advance. We fix the
  stored-program idea, lay out the datapath at a high level — PC, instruction
  memory, register file, ALU, data memory — and the control unit that sequences
  them, break the work into the six stages the rest of the module builds in
  hardware, and work out exactly how fetch parses variable-length instructions
  and computes the next PC.
topics: [Processor Design]
sources:
  - book: Bryant & O'Hallaron
    ref: "CS:APP — §4.3 Sequential Y86-64 Implementations"
  - book: Bistriceanu
    ref: "Computer Architecture Notes — §5 CPU Implementation (Executing an instruction; Hardwired control)"
---

The previous module fixed the [Y86-64 instruction set](/computer-architecture/instruction-set-architecture/the-y86-64-instruction-set):
exactly what state a program can see and exactly how each instruction is encoded in
bytes. The module before that built the [combinational and storage
elements](/computer-architecture/digital-logic/multiplexers-decoders-and-the-alu):
muxes, decoders, the ALU, the register file, memory. This module spends those parts
on one goal: a circuit that, started at an address, **runs** a Y86-64 program. The
whole thing is one loop, repeated billions of times a second, and this first lesson
draws that loop and names its pieces before we wire a single gate.

## The stored-program machine

The defining idea of the modern computer is older than any chip: **the program lives
in the same memory as the data, as bytes the machine reads and obeys.** A processor
holds one piece of private state that points into that memory, the **program
counter**, and its entire behavior is a loop: read the bytes at the PC, treat them
as an instruction, carry it out, and update the PC to point at the next instruction.
Nothing tells the hardware whether a given byte is "code" or "data"; the PC decides,
by pointing at it.

> **Definition (Stored-program / von Neumann machine).** A computer whose
> instructions and data share one addressable memory, executed by repeatedly
> fetching the instruction at the program counter, performing it, and advancing the
> counter. The same bytes are instructions when the PC points at them and data when
> a load or store does.

That single loop is the **instruction cycle**, and the machine never leaves it until
a `halt` instruction sets `Stat` to `HLT`.

$$
% caption: The von Neumann loop. Starting from the PC, the machine fetches the
% caption: instruction, decodes it, executes it, and updates the PC — then repeats.
% caption: A halt instruction is the only exit.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  st/.style={draw, fill=acc!8, minimum width=24mm, minimum height=10mm,
             align=center, inner sep=2pt}]
  \definecolor{acc}{HTML}{2348F2}
  \node[st] (f) at (0,0)    {Fetch\\(read bytes at PC)};
  \node[st] (d) at (5,0)    {Decode\\(read operands)};
  \node[st] (e) at (5,-2.4) {Execute\\(compute / mem)};
  \node[st] (u) at (0,-2.4) {Update PC\\(next instruction)};
  \draw[->] (f.east) -- (d.west);
  \draw[->] (d.south) -- (e.north);
  \draw[->] (e.west) -- (u.east);
  \draw[->] (u.north) -- (f.south);
  \node[anchor=east, text=acc] at (-2.3,-1.2) {repeat};
  \draw[->, acc] (-1.4,-1.9) .. controls (-2.1,-1.2) .. (-1.4,-0.5);
  \draw[->] (e.east) -- ++(1.5,0) node[anchor=west] {halt $\Rightarrow$ stop};
\end{tikzpicture}
$$

The PC update is what makes the loop a loop. For most instructions the next PC is simply the address just past the bytes
we read; for a jump or a call it is somewhere else entirely; for a return it comes
off the stack. Getting that one value right on every instruction is what keeps the
machine on the rails.

## The datapath: the units the loop drives

The loop above is behavior; the **datapath** is the hardware that carries it out:
the functional units, wired together, that hold and move the bits. Five units do almost
all of the work, and we have already built every one of them in isolation.

$$
% caption: A high-level datapath. The PC addresses instruction memory; the fetched
% caption: instruction names registers in the register file, whose values feed the
% caption: ALU; the ALU result addresses data memory or returns to the register
% caption: file. The control unit (right) reads icode and steers every unit.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  u/.style={draw, fill=acc!8, minimum width=22mm, minimum height=11mm,
            align=center, inner sep=2pt}]
  \definecolor{acc}{HTML}{2348F2}
  % left-to-right pipeline of units
  \node[u] (pc)   at (0,0)    {PC};
  \node[u] (imem) at (3.0,0)  {Instruction\\memory};
  \node[u] (rf)   at (6.4,0)  {Register\\f\/ile};
  \node[u] (alu)  at (9.8,0)  {ALU};
  \node[u] (dmem) at (9.8,-2.6){Data\\memory};
  % control unit to the right
  \node[u, minimum height=30mm] (ctl) at (13.2,-0.9) {Control\\unit};
  % horizontal datapath wires
  \draw[->] (pc.east)   -- (imem.west) node[midway,above,font=\scriptsize]{addr};
  \draw[->] (imem.east) -- (rf.west)   node[midway,above,font=\scriptsize]{regids};
  \draw[->] (rf.east)   -- (alu.west)  node[midway,above,align=center,font=\scriptsize]{valA,\\valB};
  \draw[->] (alu.south) -- (dmem.north) node[midway,right,font=\scriptsize]{addr};
  % writeback from data memory / ALU back to register f\/ile
  \draw[->] (dmem.west) -| (rf.south)  node[pos=0.78,left,font=\scriptsize]{valM};
  \draw[->] (alu.north) -- ++(0,0.7) -| ([xshift=8mm]rf.north)
        node[pos=0.3,above,font=\scriptsize]{valE};
  % icode to the control unit, routed over the top
  \draw[->] (imem.north) -- ++(0,2.2) -| (ctl.north)
        node[pos=0.3,above,font=\scriptsize]{icode:ifun};
  % control signals fan out to the units
  \draw[->, acc] ([yshift=6mm]ctl.west) -- ++(-0.6,0) |- (alu.east);
  \draw[->, acc] ([yshift=-6mm]ctl.west) -- ++(-0.6,0) |- (dmem.east);
  \draw[->, acc] ([xshift=-6mm]ctl.north) -- ++(0,1.1) -| ([xshift=-5mm]rf.north)
        node[pos=0.4,above,font=\scriptsize,text=acc]{control signals};
\end{tikzpicture}
$$

- **The program counter (PC)** is a single 64-bit register holding the address of
  the current instruction. It is the only state outside memory and the register
  file, and it is updated once per instruction.
- **Instruction memory** is the part of memory the fetch stage reads. Given the PC it
  returns the instruction bytes: the `icode:ifun` opcode, an optional register byte,
  an optional 8-byte constant. (In Y86-64 there is one memory; "instruction memory"
  and "data memory" are two read/write ports onto it.)
- **The register file** holds the fifteen program registers `%rax`–`%r14`. It has two
  read ports (so both ALU operands can be read at once) and two write ports (so an
  instruction can update two registers — an ALU result and a memory value — in one
  cycle).
- **The ALU** does the arithmetic: it adds, subtracts, ANDs, and XORs under a
  function-code control input, and on arithmetic instructions it sets the condition
  codes `ZF`/`SF`/`OF`.
- **Data memory** is the part of memory loads and stores touch, addressed by an
  address the ALU usually computes.

Two more pieces glue these together. **Condition codes** are three flip-flops the ALU
writes and the branches read. And **multiplexers** sit at the input of nearly every
unit, choosing, under control-unit signals, which of several possible values that
unit should see this cycle. The next operand might be a register or an immediate; the
write-back value might be the ALU result or a loaded word; the next PC might be the
fall-through address, a jump target, or a return address. Every such choice is a mux.

The register file deserves a closer look, because its shape is dictated by what a
single instruction must do in one cycle. `popq %rbx`, for instance, updates _two_
registers at once — it writes the incremented `%rsp` and the loaded word into
`%rbx` — and it reads `%rsp` while doing so. So the register file has **two read
ports and two write ports**, each an independent address-plus-data channel into the
same array of fifteen 64-bit registers. Reads are combinational (present an ID, the
value appears after a gate delay); writes are clocked (they commit only at the
cycle's rising edge). A register ID is four bits, so `0x0`–`0xE` name `%rax`–`%r14`
and the spare code `0xF` is `RNONE`: addressing a port with `RNONE` reads zero and
writes nowhere, which is how an instruction that needs only one operand leaves the
other port idle.

$$
% caption: The register file: two read ports (srcA, srcB return valA, valB) and two
% caption: write ports (dstE, dstM commit valE, valM). Reads are combinational; writes
% caption: land at the clock edge. Addressing a port with RNONE (0xF) idles it.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  rf/.style={draw, fill=acc!8, minimum width=30mm, minimum height=26mm, align=center}]
  \definecolor{acc}{HTML}{2348F2}
  \node[rf] (rf) {Register\\f\/ile\\\scriptsize(15 regs)};
  % read ports on the left (in) and right (out)
  \draw[->] (rf.west) ++(-2.2,0.8) -- ([yshift=8mm]rf.west) node[pos=0,anchor=east,font=\scriptsize]{srcA};
  \draw[->] (rf.west) ++(-2.2,-0.8) -- ([yshift=-8mm]rf.west) node[pos=0,anchor=east,font=\scriptsize]{srcB};
  \draw[->] ([yshift=8mm]rf.east) -- ++(2.2,0) node[anchor=west,font=\scriptsize]{valA};
  \draw[->] ([yshift=-8mm]rf.east) -- ++(2.2,0) node[anchor=west,font=\scriptsize]{valB};
  % write ports from the bottom
  \draw[->, acc] (-1.4,-3.1) node[anchor=north,font=\scriptsize]{dstE, valE} -- ([xshift=-7mm]rf.south);
  \draw[->, acc] (1.4,-3.1) node[anchor=north,font=\scriptsize]{dstM, valM} -- ([xshift=7mm]rf.south);
  % clock tick
  \node[anchor=south, font=\scriptsize, text=acc] at (0,2.0) {writes commit at clock edge};
\end{tikzpicture}
$$

## The control unit: sequencing the datapath

The datapath can compute anything, but it does not know _what_ to compute on a given
cycle. That is the **control unit's** job. It reads the one field that names the
operation, `icode` (with `ifun` for variants), and from it computes every control
signal the datapath needs: which registers to read and write, what function the ALU
performs, whether memory reads or writes, and where the next PC comes from. In a
**hardwired** control unit — the kind we build in this module — that computation is
pure combinational logic, written in HCL: a set of Boolean and `case` expressions of
`icode`. There is no little program inside the processor; the control _is_ the
circuit.

> **Definition (Control unit).** The combinational logic that derives every datapath
> control signal from the instruction's `icode`/`ifun`. In a hardwired
> implementation these are HCL `case` expressions evaluated each cycle; the
> alternative — a microprogrammed control unit that steps through stored
> micro-instructions — trades speed for flexibility and is sketched in
> [lesson 3](/computer-architecture/processor-design/control-logic-and-sequencing).

## Breaking the cycle into stages

To turn the loop into a circuit we slice it into a fixed sequence of **stages**, each
a clean band of computation that hands its results to the next. CS:APP's sequential
design (SEQ) uses six, and every Y86-64 instruction flows through the same six in the
same order. Instructions that do not need a stage simply pass through it.

$$
% caption: The six SEQ stages as a ring. Every instruction passes through all six
% caption: in order; the PC update closes the loop back to the next fetch. Stages an
% caption: instruction does not need (e.g. memory for an OPq) pass through idle.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  s/.style={draw, fill=acc!8, minimum width=26mm, minimum height=9mm,
            align=center, inner sep=2pt}]
  \definecolor{acc}{HTML}{2348F2}
  \node[s] (f)  at (0,0)     {Fetch};
  \node[s] (d)  at (0,-1.4)  {Decode};
  \node[s] (e)  at (0,-2.8)  {Execute};
  \node[s] (m)  at (0,-4.2)  {Memory};
  \node[s] (w)  at (0,-5.6)  {Write-back};
  \node[s] (p)  at (0,-7.0)  {PC update};
  \foreach \a/\b in {f/d, d/e, e/m, m/w, w/p} \draw[->] (\a.south) -- (\b.north);
  % loop back from PC update to fetch along the left margin
  \draw[->, acc] (p.west) -- ++(-1.6,0) |- (f.west);
  \node[text=acc, anchor=south, rotate=90, font=\scriptsize] at (-3.3,-3.5) {next instruction};
  % per-stage one-line job
  \node[anchor=west, font=\scriptsize] at (1.7,0)    {read bytes at PC; compute valP};
  \node[anchor=west, font=\scriptsize] at (1.7,-1.4) {read register operands valA, valB};
  \node[anchor=west, font=\scriptsize] at (1.7,-2.8) {ALU computes valE; set CC};
  \node[anchor=west, font=\scriptsize] at (1.7,-4.2) {read or write data memory (valM)};
  \node[anchor=west, font=\scriptsize] at (1.7,-5.6) {write valE / valM to registers};
  \node[anchor=west, font=\scriptsize] at (1.7,-7.0) {select newPC};
\end{tikzpicture}
$$

The stages are worth naming once, because the rest of the module fills in
exactly what each one computes for each instruction.

- **Fetch** reads the instruction bytes at the PC, splits out `icode:ifun`, the
  register byte, and the constant `valC`, and computes `valP`, the address of the
  next instruction in sequence.
- **Decode** reads up to two register operands from the register file into `valA`
  and `valB`.
- **Execute** uses the ALU — to compute an arithmetic result, a memory address, or a
  stack adjustment — producing `valE`, and on arithmetic instructions sets the
  condition codes. It also evaluates the branch condition `Cnd`.
- **Memory** reads a word from data memory into `valM`, or writes a value to data
  memory.
- **Write-back** writes up to two results back to the register file: `valE` to one
  register, `valM` to another.
- **PC update** computes the address of the next instruction: normally `valP`, but
  `valC` for a call or taken jump, and `valM` for a return.

Not every instruction uses every stage, but every instruction passes through all six
in lockstep — a stage it does not need simply produces a value nothing uses. An `OPq`
like `addq` reads registers (Decode), computes in the ALU (Execute), and writes a
register (Write-back), but its Memory stage does nothing: `addq` touches no memory, so
Memory is a cycle spent idle. A `nop` uses only Fetch and PC update; a `jmp` adds
Execute (to evaluate the always-true condition) but skips Decode, Memory, and
Write-back; a `ret` is the busiest short instruction, exercising Decode, Execute,
Memory, Write-back, _and_ a non-default PC update. Keeping the stage sequence fixed —
rather than letting instructions take custom paths — is what lets one control unit and
one datapath serve all twelve opcodes, at the cost of stages an instruction
leaves idle; [pipelining](/computer-architecture/pipelining/from-seq-to-pipe)
later recovers that cost.

## How fetch finds the instruction boundaries

Everything downstream depends on fetch getting one job exactly right: carving a
stream of undifferentiated bytes into instructions. Y86-64 instructions are
**variable-length** (1, 2, 9, or 10 bytes), so there is no fixed stride the PC can
advance by. The machine cannot look ahead, and it does not need to: **the first byte
alone determines the length of the whole instruction.** Its high nibble is `icode`,
its low nibble `ifun`, and `icode` fixes the format:

- Does the instruction have a **register byte**? Yes for `rrmovq`/`cmovXX`, `OPq`,
  `pushq`, `popq`, `irmovq`, `rmmovq`, and `mrmovq`; no for `halt`, `nop`, `jXX`,
  `call`, and `ret`. Call this bit `need_regids`, or $r$.
- Does it have an **8-byte constant** `valC`? Yes for `irmovq`, `rmmovq`, `mrmovq`
  (the immediate or displacement) and for `jXX` and `call` (the destination
  address). Call this bit `need_valC`, or $c$.

Both bits are one-line HCL predicates on `icode`, and together they give the
instruction length and therefore the fall-through address:

$$
\texttt{valP} \;=\; \texttt{PC} + 1 + r + 8c.
$$

```c [seq-fetch.hcl]
bool need_regids = icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ,
                              IIRMOVQ, IRMMOVQ, IMRMOVQ };

bool need_valC   = icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL };

bool instr_valid = icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ,
                              IMRMOVQ, IOPQ, IJXX, ICALL, IRET,
                              IPUSHQ, IPOPQ };
```

The four possible lengths come from the four combinations of $r$ and $c$: 1 byte
($r=0, c=0$, e.g. `ret`), 2 bytes ($r=1, c=0$, e.g. `addq`), 9 bytes
($r=0, c=1$, e.g. `jne`), and 10 bytes ($r=1, c=1$, e.g. `irmovq`).

$$
% caption: The four Y86-64 instruction lengths, each determined by the first byte
% caption: alone. The high nibble (icode) fixes whether a register byte and an 8-byte
% caption: constant follow, and hence the increment from PC to valP.
\begin{tikzpicture}[font=\footnotesize,
  b/.style={draw, fill=acc!8, minimum width=11mm, minimum height=7mm, inner sep=1pt},
  w/.style={draw, fill=acc!8, minimum width=40mm, minimum height=7mm, inner sep=1pt},
  nm/.style={anchor=east, font=\ttfamily}]
  \definecolor{acc}{HTML}{2348F2}
  \node[font=\scriptsize, text=acc, anchor=south] at (0,0.42) {icode:ifun};
  \node[nm] at (-1.0,0) {ret};
  \node[b] at (0,0) {9:0};
  \node[anchor=west] at (5.4,0) {$\mathtt{valP}=\mathtt{PC}+1$};
  \node[nm] at (-1.0,-1.2) {addq rA,rB};
  \node[b] at (0,-1.2) {6:0};
  \node[b] at (1.1,-1.2) {rA:rB};
  \node[anchor=west] at (5.4,-1.2) {$\mathtt{valP}=\mathtt{PC}+2$};
  \node[nm] at (-1.0,-2.4) {jne Dest};
  \node[b] at (0,-2.4) {7:4};
  \node[w] at (2.55,-2.4) {Dest (8 bytes)};
  \node[anchor=west] at (5.4,-2.4) {$\mathtt{valP}=\mathtt{PC}+9$};
  \node[nm] at (-1.0,-3.6) {irmovq V,rB};
  \node[b] at (0,-3.6) {3:0};
  \node[b] at (1.1,-3.6) {F:rB};
  \node[w] at (3.65,-3.6) {V (8 bytes)};
  \node[anchor=west] at (6.2,-3.6) {$\mathtt{valP}=\mathtt{PC}+10$};
\end{tikzpicture}
$$

Trace it on a real byte stream. Suppose memory from address `0x000` holds
`30 f2 09 00 00 00 00 00 00 00 60 20 90` and the PC starts at `0x000`.

- Fetch reads byte `30`: `icode = 3` (`irmovq`), so $r=1$, $c=1$, length 10. The
  register byte `f2` gives `rB = %rdx`, the next 8 bytes give `valC = 9`, and
  `valP = 0x000 + 10 = 0x00a`.
- At `0x00a`, byte `60`: `icode = 6` (`OPq`, and `ifun = 0` says `addq`), so
  $r=1$, $c=0$, length 2. The register byte `20` names `%rdx` and `%rax`;
  `valP = 0x00c`.
- At `0x00c`, byte `90`: `icode = 9` (`ret`), $r=0$, $c=0$, length 1;
  `valP = 0x00d`, though `ret` will discard it and take the return address instead.

Three instructions, three different lengths, and at no point did the hardware guess:
each first byte fixed how many bytes belonged to its instruction, and `valP`
landed exactly on the next boundary.

Fetch is also the machine's first line of defense against a broken program. Two
things can go wrong before an instruction even runs, and fetch catches both by
setting the two-bit **status code** `Stat` that every cycle carries alongside the
instruction. If the `icode` nibble is not one of the twelve valid opcodes,
`instr_valid` goes false and `Stat` becomes `INS`, an illegal-instruction halt,
rather than executing garbage. If the PC points outside valid memory, `imem_error`
raises `Stat = ADR`. A clean instruction leaves `Stat = AOK`, `halt` sets `Stat =
HLT`, and the rule is simply that the machine begins another cycle only while `Stat`
is `AOK`.

$$
% caption: The four status codes fetch can raise, from the first instruction byte and
% caption: the fetch address. AOK proceeds; HLT, ADR, and INS each stop the machine.
% caption: Stat rides alongside the instruction so a later stage can act on it.
\begin{tikzpicture}[font=\footnotesize,
  lbl/.style={anchor=east, text=acc, font=\ttfamily\footnotesize},
  row/.style={anchor=west, font=\scriptsize}]
  \definecolor{acc}{HTML}{2348F2}
  \draw[acc!40] (-0.5,0.45) -- (10.8,0.45);
  \foreach \y/\code/\mean in {
    0/{AOK}/{normal: icode valid, address in range -- proceed},
    -0.75/{HLT}/{halt instruction fetched -- machine stops cleanly},
    -1.5/{ADR}/{imem\_error: PC outside valid memory -- stop},
    -2.25/{INS}/{instr\_valid false: icode not a real opcode -- stop}} {
    \node[lbl] at (1.1,\y) {\code};
    \node[row] at (1.5,\y) {\mean};
    \draw[acc!40] (-0.5,\y-0.37) -- (10.8,\y-0.37);
  }
\end{tikzpicture}
$$

Suppose the byte at the PC were `f0`. Its high nibble `f` is not among the twelve
opcodes (the largest valid `icode` is `0xB`, `popq`), so `instr_valid = 0`,
`Stat = INS`, and the machine halts here instead of decoding a phantom instruction
with a phantom length. This is why a valid-opcode check belongs in fetch and nowhere
else: fetch is the one stage that has seen the raw byte before any downstream logic
has committed to a length or a register read.

In hardware, fetch is a small datapath of its own: instruction memory produces ten
bytes starting at the PC; a **split** unit divides byte 0 into `icode` and `ifun`;
an **align** unit routes bytes 1–9 into `rA`, `rB`, and `valC` (bytes 1–8 form
`valC` when there is no register byte, bytes 2–9 when there is); and a dedicated
**PC-increment** adder computes $\texttt{PC} + 1 + r + 8c$. There is no reason to
occupy the main ALU with the PC increment (it is busy computing the instruction's
own result), so fetch gets its own small adder.

$$
% caption: The fetch stage as a mini-datapath. Instruction memory yields ten bytes at
% caption: the PC; Split divides byte 0 into icode and ifun; Align routes bytes 1-9
% caption: into rA, rB, and valC; a dedicated adder computes valP = PC + 1 + r + 8c,
% caption: with r and c derived from icode.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  u/.style={draw, fill=acc!8, minimum width=18mm, minimum height=10mm,
            align=center, inner sep=2pt}]
  \definecolor{acc}{HTML}{2348F2}
  \node[u, minimum width=14mm] (pc) at (0,0) {PC};
  \node[u, minimum width=24mm, minimum height=13mm] (imem) at (3.2,0) {Instruction\\memory};
  \node[u] (split) at (7.0,0.9) {Split};
  \node[u] (align) at (7.0,-0.9) {Align};
  \node[u, minimum width=24mm] (incr) at (10.8,0.9) {PC increment\\adder};
  \draw[->] (pc.east) -- (imem.west) node[midway,above,font=\scriptsize]{addr};
  \draw[->] ([yshift=2.5mm]imem.east) -- ++(0.5,0) |- (split.west)
        node[pos=0.75,above,font=\scriptsize]{byte 0};
  \draw[->] ([yshift=-2.5mm]imem.east) -- ++(0.4,0) |- (align.west);
  \node[font=\scriptsize, anchor=north] at (5.2,-1.05) {bytes 1-9};
  \draw[->] (split.north) -- ++(0,0.55) node[anchor=south,font=\scriptsize]{icode, ifun};
  \draw[->] (align.east) -- ++(1.0,0) node[anchor=west,font=\scriptsize]{rA, rB, valC};
  \draw[->] (split.east) -- (incr.west) node[midway,above,font=\scriptsize]{r, c};
  \draw[->] (pc.south) -- ++(0,-1.5) -| (incr.south);
  \draw[->] (incr.east) -- ++(0.8,0) node[anchor=west,font=\scriptsize]{valP};
\end{tikzpicture}
$$

## Where the six stages go next

SEQ commits to one instruction per clock cycle, and the whole loop must settle inside
that cycle. That is a deliberate teaching simplification, and the very next design in
CS:APP starts undoing it. The first move is a bookkeeping one called **SEQ+** (Bryant
& O'Hallaron, _CS:APP_ §4.5.1): the PC-update stage is shifted from the _end_ of the
cycle to the _beginning_, so the machine computes the address of the instruction it is
_about_ to run from state saved on the previous cycle. SEQ+ has no PC
register at all — the program counter is reconstructed each cycle from a handful of
saved signals (`pIcode`, `pValC`, `pValM`, …). CS:APP notes this is an instance of
**circuit retiming** (Leiserson & Saxe, 1991), a transformation that relocates state
across combinational logic without changing what the circuit computes, used here to
balance stage delays. It leads directly to pipelining: once every stage begins
and ends at a clean register boundary, you can let several instructions occupy
different stages at once.

Real processors carry the same six-stage skeleton, but the fetch-and-decode front end
looks nothing like Y86-64's tidy nibble-splitter. x86-64 instructions run from 1 to 15
bytes with prefixes, escape bytes, and mode-dependent operands, so decode is a serious
pipeline of its own. Modern x86 cores translate each architectural instruction into
one or more fixed-format internal operations — "micro-operations," or µops — and the
back end schedules those, out of order, across many functional units (Bryant &
O'Hallaron, §4.1 aside on RISC vs. CISC; and CS:APP §5.7 on modern processors). The
principle the aside on SEQ+ states plainly is what licenses all of this: a processor
may represent its state however it likes, so long as it produces the correct
programmer-visible values for any machine-language program. SEQ is the baseline
against which those later liberties make sense.

> **Takeaway.** A processor is a stored-program machine running one loop forever:
> fetch the instruction at the PC, decode its operands, execute, touch memory, write
> back, and update the PC. The datapath — PC, instruction memory, register file, ALU,
> data memory, with muxes at their inputs — is the hardware; the control unit, reading
> `icode`, decides each cycle what that hardware does. SEQ cuts the loop into
> six stages, the same six for every instruction, and fetch keeps the loop aligned:
> the first byte's `icode` fixes the instruction's length, so
> `valP = PC + 1 + need_regids + 8 need_valC` always lands on the next boundary.

The [next lesson](/computer-architecture/processor-design/the-seq-stages) makes the
six stages precise, writing down exactly what each one computes for each Y86-64
instruction.
