---
title: Assembling a Complete CPU
module: Capstone
moduleNumber: 10
lessonNumber: 2
order: 1002
summary: >
  We bolt the parts the course built — PC, instruction memory and its
  fetch logic, register file, ALU, condition codes, data memory, and the control
  unit — into one
  complete CPU, name the lesson that built each, wire them in a deliberate order,
  and power the machine on from reset. Then we assemble a real test program (sum a
  four-element array through a call/ret procedure), give its exact bytes and memory
  layout, and trace it cycle by cycle to the answer 0xabcdabcdabcd. We close with
  how to validate such a machine, and what it takes to put two of them on one die.
topics: [Capstone]
sources:
  - book: Bryant & O'Hallaron
    ref: "CS:APP — §4 Processor Architecture (synthesis); §4.3 Sequential Y86-64 Implementations"
  - book: Bistriceanu
    ref: "Computer Architecture Notes — §2 Basic Organization / §5 CPU Implementation"
---

This is the lesson the whole course was building toward. We have every part: the
[ALU](/computer-architecture/digital-logic/multiplexers-decoders-and-the-alu) that
adds and subtracts and sets flags, the
[register file](/computer-architecture/digital-logic/register-files-and-random-access-memory)
with its two read ports and two clocked write ports (`dstE`, `dstM`), the addressed
[memory](/computer-architecture/digital-logic/register-files-and-random-access-memory),
the [Y86-64 ISA](/computer-architecture/instruction-set-architecture/the-y86-64-instruction-set)
that fixes the bytes, and the
[control logic](/computer-architecture/processor-design/assembling-seq) that drives
the muxes. We even traced
[a program through SEQ](/computer-architecture/processor-design/tracing-a-program).
What is left is the assembly itself, done the way an engineer would actually do it:
draw the complete machine with **every named part in its place**, say which lesson
built each, wire the parts in a deliberate order, define the reset state and watch
the first fetch happen, then run a real compiled program (a procedure call, a
loop, an array in memory) from power-on to `halt`. When the answer lands, we ask
the two questions any real project ends with: how do you _know_ it works, and what
would it take to build two?

## The complete CPU, part by part

A CPU is seven kinds of part, and the course built each one. **Fetch** needs a
place to keep the address of the next instruction and a place to read instruction
bytes from: the **program counter (PC)** and the **instruction memory**, whose
current output — the **fetched instruction word** — the Split and Align logic of
[module 4's fetch stage](/computer-architecture/processor-design/the-fetch-decode-execute-cycle)
breaks into fields combinationally (no register latches it; the machine's clocked
state elements remain the four SEQ counted: PC, CC, register file, data memory).
**Decode** and **write-back** need the **register file**. **Execute** needs the
**ALU** and, beside it, the **condition-code register (CC)** that latches `ZF`,
`SF`, and `OF` whenever an `OPq` instruction runs. **Memory** needs the **data
memory**. And tying them together, deciding from the decoded opcode which mux
selects what and which register gets written, is the **control unit**: the
**hardwired control logic** of a Y86-64 machine (in a microprogrammed design the
same job is done by a **microsequencer** stepping through microinstructions, but
the role is identical).

$$
% caption: The complete Y86-64 CPU with every named part placed and wired. The PC
% caption: addresses instruction memory; the fetched instruction word splits
% caption: combinationally into fields; the register file feeds the ALU, which sets the CC register;
% caption: the ALU result addresses data memory; results write back down the inner
% caption: right margin, and newPC loops down the outer one. The control unit (left)
% caption: reads icode:ifun and drives a signal to every unit.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  u/.style={draw, fill=acc!8, align=center, inner sep=3pt},
  wlab/.style={text=acc, font=\footnotesize\ttfamily}]
  \definecolor{acc}{HTML}{2348F2}
  % ===== central data spine, bottom (fetch) to top (write-back / next PC) =====
  \node[u, minimum width=20mm, minimum height=8mm]  (pc)  at (0,0)    {\texttt{PC}};
  \node[u, minimum width=30mm, minimum height=10mm] (im)  at (0,1.8)  {instruction memory\\+ \texttt{fetch word} (comb.)};
  \node[u, minimum width=30mm, minimum height=10mm] (rf)  at (0,3.9)  {register \texttt{file}};
  \node[u, minimum width=22mm, minimum height=10mm] (alu) at (0,6.0)  {\texttt{ALU}};
  \node[u, minimum width=30mm, minimum height=10mm] (dm)  at (0,8.1)  {data memory};
  \node[u, minimum width=22mm, minimum height=8mm]  (npc) at (0,10.1) {new \texttt{PC}};
  % condition codes beside the ALU
  \node[u, minimum width=12mm, minimum height=8mm] (cc) at (2.4,6.0) {\texttt{CC}};
  \draw[->] (alu.east) -- (cc.west);
  \node[wlab] at (2.4,5.45) {ZF SF OF};
  % ----- central data hand-offs (short, vertical, crossing nothing) -----
  \draw[->] (pc.north) -- (im.south)  node[wlab,midway,right]{addr};
  \draw[->] (im.north) -- (rf.south)  node[wlab,midway,right]{icode, rA, rB, valC, valP};
  \draw[->] (rf.north) -- (alu.south) node[wlab,midway,right]{valA, valB};
  \draw[->] (alu.north) -- (dm.south) node[wlab,midway,right]{valE};
  \draw[->] (dm.north) -- (npc.south) node[wlab,midway,right]{valM};
  % ----- write-back returns down the INNER right margin -----
  \draw[->, acc] (dm.east) -- (3.4,8.1) -- (3.4,3.9) -- (rf.east);
  \node[wlab, rotate=-90, anchor=center] at (3.7,6.0) {write-back valE / valM};
  % ----- newPC returns down the OUTER right margin -----
  \draw[->, acc] (npc.east) -- (4.6,10.1) -- (4.6,0) -- (pc.east);
  \node[wlab, rotate=-90, anchor=center] at (4.9,5.0) {newPC};
  % ===== control unit on the far left, spanning the height =====
  \node[u, minimum width=12mm, minimum height=106mm] (ctl) at (-5.6,5.05) {};
  \node[font=\footnotesize\ttfamily, rotate=90] at (-5.6,5.05) {control unit};
  \node[wlab, rotate=90, anchor=center] at (-6.55,5.05) {mux selects + write enables};
  % control fan: one horizontal stub per unit, crossing nothing
  \draw[->, acc] (-5.0,0)    -- (pc.west);
  \draw[->, acc] (-5.0,3.9)  -- (rf.west);
  \draw[->, acc] (-5.0,6.0)  -- (alu.west);
  \draw[->, acc] (-5.0,8.1)  -- (dm.west);
  \draw[->, acc] (-5.0,10.1) -- (npc.west);
  \draw[->, acc] (-5.0,1.5)  -- ([yshift=-3mm]im.west);
  % the opcode comes back to the control unit from the fetch split
  \draw[->, acc!70] ([yshift=3mm]im.west) -- (-5.0,2.1);
  \node[wlab, anchor=south] at (-3.3,2.15) {icode : ifun};
\end{tikzpicture}
$$

The discipline is the one
[SEQ](/computer-architecture/processor-design/assembling-seq) taught: functional
units stacked along a central spine, data handed straight up, and the two feedback
wires — write-back to the register file, and `newPC` to the PC — routed in separate
right-hand margins where they cross nothing. The control unit stands to one side,
reads `icode:ifun` out of the fetched instruction word, and sends a signal to every unit. One wire is
drawn small but matters enormously: the `CC` register's three flags flow back into
the control unit (through the `Cnd` condition logic), because a `jne` cannot decide
`newPC` without them. That single feedback is the machine's only means of
_decision_; everything else is data routing.

This machine uses ideal one-cycle memories, as SEQ always did. On the full die,
the [previous lesson's block diagram](/computer-architecture/capstone/the-whole-machine)
wraps these two memory boxes in TLBs, caches, and DRAM; nothing in this lesson
changes when it does, which is the point of the
[memory-hierarchy abstraction](/computer-architecture/memory-hierarchy/cache-memories-direct-mapped).

Here is the provenance, part by part: which lesson built each.

$$
% caption: Which lesson built which part. Every functional unit of the complete CPU
% caption: was constructed earlier in the course; this legend names the source. The
% caption: capstone adds nothing new — it only wires the existing parts together.
\begin{tikzpicture}[font=\footnotesize,
  p/.style={draw, fill=acc!8, minimum width=38mm, minimum height=8mm, align=center,
            inner sep=2pt},
  src/.style={anchor=west, text=acc!85, font=\footnotesize\ttfamily}]
  \definecolor{acc}{HTML}{2348F2}
  \foreach \y/\part/\where in {
    0/{\texttt{PC + new-PC mux}}/{module 4: assembling SEQ},
    -1.05/{instruction memory + \texttt{fetch word}}/{module 3: memories; module 4: fetch},
    -2.10/{register \texttt{file}}/{module 3: register files + RAM},
    -3.15/{\texttt{ALU}}/{module 3: muxes, decoders, ALU},
    -4.20/{\texttt{CC register}}/{module 3: latches + clocking},
    -5.25/{data memory}/{module 3: sram and dram},
    -6.30/{control unit}/{module 4: control logic} } {
    \node[p] at (0,\y) {\part};
    \node[src] at (2.7,\y) {\where};
  }
\end{tikzpicture}
$$

> **Definition (Control unit).** The block that turns the decoded opcode into every
> control signal the datapath needs — each mux select and each write-enable — for the
> current cycle. In a hardwired implementation it is combinational logic (HCL) over
> `icode`/`ifun`; in a microprogrammed implementation a **microsequencer** fetches
> the signals from a control store, one microinstruction per step. Either way it is
> what makes the fixed datapath behave differently for each instruction.

## Wiring order and bring-up

Assembly has an order, and the order is not arbitrary. First the **data spine**,
bottom to top: PC into instruction memory, the fetched fields into the register file's read
addresses, read ports into the ALU, ALU output into the data memory's address
port. This much is purely feed-forward: signals flow one way, and each connection
can be checked in isolation by driving the input and probing the output. Second,
the **two feedback paths**: write-back to the register file and `newPC` to the PC.
These close loops, so they come after the spine works; a loop wired around a
broken spine oscillates or latches garbage, and you cannot tell which part failed.
Third, the **CC register** beside the ALU and its `Cnd` wire to control. Last, the
**control fan**: the decoder in the control unit that reads `icode:ifun` and
drives every mux select and write-enable, one stub per unit. Control comes last
because it is meaningless until the things it controls exist: every one of its
output wires names a mux or a port that has to be there already. This is the same
inside-out order the
[SEQ assembly lesson](/computer-architecture/processor-design/assembling-seq)
followed; the capstone only makes it explicit as a checklist.

With the machine wired, it has to start. A CPU has no operator; the only thing
that distinguishes cycle 1 from cycle 1,000,000 is the state the machine wakes up
in, so that state must be defined by hardware, not by luck.

> **Definition (Reset state).** The architectural state forced while the `reset`
> signal is asserted: `PC = 0x000`, all registers zero, condition codes
> `ZF = 1, SF = 0, OF = 0`, and status `Stat = AOK`. While `reset` is high, every
> state element loads this value on each clock edge; the machine begins executing
> at the first rising edge after `reset` is released.

Every choice here is a convention, and each has a reason. `PC = 0x000` means the
machine's first act is to fetch `M[0x000]`, so whoever loads memory knows exactly
where to put the entry point. Registers start at zero so no computation depends on
power-on noise. `ZF = 1` matches what the flags would show after computing zero,
which is the honest description of a machine that has computed nothing. And
`Stat = AOK` arms the machine to run. That is the entire boot process for this
CPU: reset forces a known state, memory holds bytes at address `0x000`, and the
clock does the rest. Real x86-64 machines are no different in kind (the PC resets
to a fixed address that points into firmware ROM instead of a loaded program), and
everything a modern boot does is layered on this one mechanism.

$$
% caption: Bring-up. While reset is held, every clock edge reloads the defined
% caption: reset state: PC = 0x000, registers zero, ZF = 1. After release, cycle 1
% caption: fetches M[0x000] (the bytes 30 f4 ..), computes valE = 0x200, and the
% caption: next rising edge clocks the first real state change: rsp = 0x200 and
% caption: PC = 0x00a. From here the machine is simply running.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  an/.style={font=\footnotesize\ttfamily, anchor=west},
  sig/.style={font=\footnotesize\ttfamily, anchor=east}]
  \definecolor{acc}{HTML}{2348F2}
  % reset signal: high, then released at x=2.0
  \node[sig] at (-1.1,2.25) {reset};
  \draw[acc, thick] (-0.9,2.5) -- (2.0,2.5) -- (2.0,2.0) -- (11.2,2.0);
  % clock: rising edges at 0.25, 2.55, 4.85, 7.15, 9.45
  \node[sig] at (-1.1,0.95) {clk};
  \draw[black]
    (-0.9,0.7) -- (0.25,0.7) -- (0.25,1.2) -- (1.4,1.2) -- (1.4,0.7) --
    (2.55,0.7) -- (2.55,1.2) -- (3.7,1.2) -- (3.7,0.7) --
    (4.85,0.7) -- (4.85,1.2) -- (6.0,1.2) -- (6.0,0.7) --
    (7.15,0.7) -- (7.15,1.2) -- (8.3,1.2) -- (8.3,0.7) --
    (9.45,0.7) -- (9.45,1.2) -- (10.6,1.2) -- (10.6,0.7) -- (11.2,0.7);
  % cycle labels under the wave
  \node[font=\footnotesize\ttfamily, text=black] at (3.7,0.25)  {cycle 1};
  \node[font=\footnotesize\ttfamily, text=black] at (6.0,0.25)  {cycle 2};
  \node[font=\footnotesize\ttfamily, text=black] at (8.3,0.25)  {cycle 3};
  % event guides
  \draw[acc, dashed] (2.55,1.3) -- (2.55,3.2);
  \draw[acc, dashed] (4.85,1.3) -- (4.85,2.6);
  % staggered annotations
  \node[an, text=black] at (-0.9,3.9) {reset held: PC = 0x000, regs = 0, ZF = 1, Stat = AOK};
  \node[an, text=acc] at (2.65,3.3) {release: cycle 1 fetches M[0x000] = 30 f4 ..};
  \node[an, text=acc] at (4.95,2.7) {edge: rsp = 0x200, PC = 0x00a};
\end{tikzpicture}
$$

The first fetch is not special. Cycle 1 runs the same
fetch–decode–execute sequence as every later cycle; the machine cannot tell boot
from steady state. Everything rests on the two facts the hardware
guarantees: a defined PC and defined bytes at that address.

## The test program: an array sum with call and ret

The countdown loops we traced in
[module 4](/computer-architecture/processor-design/tracing-a-program) exercised
arithmetic and a branch, but a real program does more: it keeps data in memory,
walks a pointer across it, and calls procedures. So the capstone's test program is
chosen to touch **every instruction class the ISA defines**: immediate moves
(`irmovq`), a memory read (`mrmovq`), register arithmetic that sets flags
(`addq`, `subq`, `xorq`), a conditional branch (`jne`), the stack pair
(`call`/`ret`), and `halt`. It sums a four-element array through a procedure, the
same shape as CS:APP's `asum`: `main` sets up the stack and the arguments, then
calls `sum(array, 4)`.

```asm [asum.ys]
# main: set up the stack, then sum(array, 4)
irmovq stack, %rsp    # rsp = 0x200      (stack pointer)
irmovq array, %rdi    # arg 1: base of array
irmovq $4, %rsi       # arg 2: element count
call sum              # push return addr, jump to sum
halt

# long sum(long *start, long count)
sum:
irmovq $8, %r8        # r8 = 8   (element stride)
irmovq $1, %r9        # r9 = 1   (decrement constant)
xorq %rax, %rax       # sum = 0  (and sets ZF = 1)
loop:
mrmovq (%rdi), %r10   # r10 = *start
addq %r10, %rax       # sum += *start
addq %r8, %rdi        # start++
subq %r9, %rsi        # count--
jne loop              # repeat while count != 0
ret                   # pop return addr into PC

.align 8
array:
.quad 0x000d000d000d
.quad 0x00c000c000c0
.quad 0x0b000b000b00
.quad 0xa000a000a000

.pos 0x200
stack:                # stack grows down from 0x200
```

The array values are chosen so the answer proves itself. Each quad fills a
different nibble of every 16-bit group, so the running sum assembles the digits
`a`, `b`, `c`, `d` in place, and the correct total is unmistakable:
$\texttt{0xabcdabcdabcd}$. A single transposed byte anywhere in the machine and
the pattern breaks visibly.

The assembler lays the code out from address `0x000`. Each `irmovq` is 10 bytes,
each `OPq` is 2, `call` and `jne` are 9 (opcode byte plus 8-byte destination),
`ret` and `halt` are 1. That fixes every address, and fixing the addresses
resolves every label: `sum` lands at `0x028`, `loop` at `0x03e`, `array` at
`0x058` (already 8-aligned), and `stack` is pinned to `0x200` by the `.pos`
directive. The bytes follow the
[ISA encodings](/computer-architecture/instruction-set-architecture/the-y86-64-instruction-set):
register nibbles `%rax`=`0`, `%rsp`=`4`, `%rsi`=`6`, `%rdi`=`7`, `%r8`=`8`,
`%r9`=`9`, `%r10`=`a`, and every constant little-endian.

$$
% caption: The assembled bytes of asum.ys from address 0x000. Each irmovq is 30,
% caption: then f:rB, then the 8-byte little-endian value; call is 80 plus the
% caption: destination 0x028; the OPq instructions are two bytes; jne is 74 plus
% caption: the destination 0x03e; ret is 90 and halt is 00. The label addresses
% caption: (sum = 0x028, loop = 0x03e) appear literally inside the call and jne.
\begin{tikzpicture}[font=\footnotesize,
  ad/.style={anchor=east, text=acc, font=\ttfamily\footnotesize},
  by/.style={anchor=west, font=\ttfamily\footnotesize},
  ins/.style={anchor=west, font=\ttfamily\footnotesize, text=black}]
  \definecolor{acc}{HTML}{2348F2}
  \foreach \y/\a/\bytes/\ins in {
    0/{0x000}/{30 f4 00 02 00 00 00 00 00 00}/{irmovq {\char36}0x200,\%rsp},
    -0.6/{0x00a}/{30 f7 58 00 00 00 00 00 00 00}/{irmovq {\char36}array,\%rdi},
    -1.2/{0x014}/{30 f6 04 00 00 00 00 00 00 00}/{irmovq {\char36}4,\%rsi},
    -1.8/{0x01e}/{80 28 00 00 00 00 00 00 00}/{call sum},
    -2.4/{0x027}/{00}/{halt},
    -3.2/{0x028}/{30 f8 08 00 00 00 00 00 00 00}/{sum: irmovq {\char36}8,\%r8},
    -3.8/{0x032}/{30 f9 01 00 00 00 00 00 00 00}/{irmovq {\char36}1,\%r9},
    -4.4/{0x03c}/{63 00}/{xorq \%rax,\%rax},
    -5.2/{0x03e}/{50 a7 00 00 00 00 00 00 00 00}/{loop: mrmovq (\%rdi),\%r10},
    -5.8/{0x048}/{60 a0}/{addq \%r10,\%rax},
    -6.4/{0x04a}/{60 87}/{addq \%r8,\%rdi},
    -7.0/{0x04c}/{61 96}/{subq \%r9,\%rsi},
    -7.6/{0x04e}/{74 3e 00 00 00 00 00 00 00}/{jne loop},
    -8.2/{0x057}/{90}/{ret}} {
    \node[ad] at (0,\y) {\a};
    \node[by] at (0.3,\y) {\bytes};
    \node[ins] at (7.7,\y) {\ins};
  }
  \draw[acc!50] (-1.05,0.35) -- (-1.05,-8.55);
  % section separators: main / sum / loop body
  \draw[acc!35, dashed] (-1.05,-2.8) -- (11.6,-2.8);
  \draw[acc!35, dashed] (-1.05,-4.8) -- (11.6,-4.8);
\end{tikzpicture}
$$

The program is only part of the memory image. The array sits right after the code,
and the stack, empty at reset, hangs below `0x200`, growing toward lower
addresses when `call` pushes.

$$
% caption: The memory image at reset. Code occupies 0x000-0x057, the four array
% caption: quads follow at 0x058-0x077, and the stack region is empty with rsp
% caption: initialized to 0x200. The one cell the program will write is 0x1f8: call
% caption: pushes the return address 0x027 there, and ret pops it back.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  ad/.style={anchor=east, text=acc, font=\ttfamily\footnotesize},
  vv/.style={anchor=west, font=\ttfamily\footnotesize, text=black}]
  \definecolor{acc}{HTML}{2348F2}
  % region boxes, low addresses at the top
  \draw[fill=acc!8]  (-1.5,0)    rectangle (1.5,-1.6);
  \node[align=center] at (0,-0.8) {code:\\\texttt{main} + \texttt{sum}};
  \draw[fill=acc!8]  (-1.5,-1.6) rectangle (1.5,-3.0);
  \node[align=center] at (0,-2.3) {array\\(4 quads)};
  \draw[dashed, black] (-1.5,-3.0) rectangle (1.5,-4.4);
  \node[text=black, font=\footnotesize\ttfamily] at (0,-3.7) {(unused)};
  \draw[fill=acc!20] (-1.5,-4.4) rectangle (1.5,-5.0);
  \node[font=\scriptsize] at (0,-4.7) {stack cell};
  % boundary addresses on the left
  \node[ad] at (-1.7,0)    {0x000};
  \node[ad] at (-1.7,-1.6) {0x058};
  \node[ad] at (-1.7,-3.0) {0x078};
  \node[ad] at (-1.7,-4.4) {0x1f8};
  \node[ad] at (-1.7,-5.0) {0x200};
  % array values on the right
  \node[vv] at (1.8,-1.85) {0x058: 000d 000d 000d};
  \node[vv] at (1.8,-2.15) {0x060: 00c0 00c0 00c0};
  \node[vv] at (1.8,-2.45) {0x068: 0b00 0b00 0b00};
  \node[vv] at (1.8,-2.75) {0x070: a000 a000 a000};
  % stack annotations
  \node[vv, text=acc] at (1.8,-4.7) {call writes 0x027 here};
  \node[vv, text=acc] at (1.8,-5.0) {$\gets$ rsp = 0x200 at reset};
  % stack growth arrow
  \draw[->, acc] (-2.6,-5.0) -- (-2.6,-4.2);
  \node[font=\footnotesize\ttfamily, text=acc, rotate=90, anchor=south] at (-2.85,-4.9) {stack grows};
\end{tikzpicture}
$$

These bytes are the whole input. The machine starts with `PC = 0x000`, the image
above sitting in memory, and from there it runs itself.

## Tracing it, cycle by cycle

The assembled CPU executes **one instruction per cycle**: in a single tick it
fetches at the PC, decodes the fields, reads registers, runs the ALU, touches
memory if needed, writes back, and computes `newPC`; the new register,
condition-code, memory, and PC values clock in at the rising edge. The whole run
is 29 cycles: three setup moves, the `call`, three cycles of `sum` prologue, four
loop iterations of five cycles each, `ret`, and `halt`. Here are the cycles where
something new happens.

$$
% caption: Key cycles of the 29-cycle run. Cycles 1-4 set up the stack and
% caption: arguments and execute the call, whose memory write is the pushed return
% caption: address; cycles 5-7 are the sum prologue (xorq zeroing rax sets ZF = 1);
% caption: cycles 8-12 are the first loop iteration in full, including the mrmovq
% caption: that reads the first array element; cycles 27-29 exit the loop, pop the
% caption: return address, and halt with the answer in rax.
\begin{tikzpicture}[font=\footnotesize,
  h/.style={anchor=west, text=acc, font=\footnotesize\ttfamily},
  c/.style={anchor=west, font=\ttfamily\footnotesize}]
  \definecolor{acc}{HTML}{2348F2}
  \draw[acc!40] (-0.3,0.45) -- (14.9,0.45);
  \node[h] at (-0.2,0.85) {cyc}; \node[h] at (0.75,0.85) {PC};
  \node[h] at (2.05,0.85) {instruction}; \node[h] at (5.45,0.85) {what happens};
  \node[h] at (10.35,0.85) {state clocked in};
  \foreach \y/\cy/\pc/\ins/\ef/\st in {
    0/1/{0x000}/{irmovq {\char36}0x200,\%rsp}/{valE = 0 + 0x200}/{\%rsp = 0x200},
    -0.65/2/{0x00a}/{irmovq {\char36}array,\%rdi}/{valE = 0x058}/{\%rdi = 0x058},
    -1.3/3/{0x014}/{irmovq {\char36}4,\%rsi}/{valE = 4}/{\%rsi = 4},
    -1.95/4/{0x01e}/{call sum}/{M[0x1f8] = 0x027 (valP)}/{\%rsp = 0x1f8, PC = 0x028},
    -2.85/5-7/{0x028..}/{sum prologue}/{r8 = 8, r9 = 1, xorq}/{\%rax = 0, ZF = 1},
    -3.75/8/{0x03e}/{mrmovq (\%rdi),\%r10}/{valM = M[0x058]}/{\%r10 = 0x000d000d000d},
    -4.4/9/{0x048}/{addq \%r10,\%rax}/{0 + 0x000d000d000d}/{\%rax = 0x000d000d000d},
    -5.05/10/{0x04a}/{addq \%r8,\%rdi}/{0x058 + 8}/{\%rdi = 0x060},
    -5.7/11/{0x04c}/{subq \%r9,\%rsi}/{4 - 1, f\/lags set}/{\%rsi = 3, ZF = 0},
    -6.35/12/{0x04e}/{jne loop}/{ZF = 0: branch}/{PC = 0x03e},
    -7.25/{..}/{}/{cycles 13-26: iterations 2-4 (see the walk below)}/{}/{},
    -8.15/27/{0x04e}/{jne loop}/{ZF = 1: fall through}/{PC = 0x057},
    -8.8/28/{0x057}/{ret}/{valM = M[0x1f8] = 0x027}/{\%rsp = 0x200, PC = 0x027},
    -9.45/29/{0x027}/{halt}/{Stat = HLT}/{\%rax = 0xabcdabcdabcd}} {
    \node[c] at (-0.2,\y) {\cy}; \node[c, text=acc] at (0.75,\y) {\pc};
    \node[c] at (2.05,\y) {\ins};
    \node[c] at (5.45,\y) {\ef}; \node[c] at (10.35,\y) {\st};
    \draw[acc!25] (-0.3,\y-0.33) -- (14.9,\y-0.33);
  }
  % band separators around the condensed rows
  \draw[acc!50] (-0.3,-2.5) -- (14.9,-2.5);
  \draw[acc!50] (-0.3,-3.4) -- (14.9,-3.4);
  \draw[acc!50] (-0.3,-6.85) -- (14.9,-6.85);
  \draw[acc!50] (-0.3,-7.75) -- (14.9,-7.75);
\end{tikzpicture}
$$

Three cycles deserve a closer look, because each one runs a mechanism the
countdown trace never touched.

**Cycle 4, the `call`.** This is the only instruction in the program that both
writes memory and takes a non-sequential `newPC`. The ALU computes
`valE = R[%rsp] - 8 = 0x1f8`; the Memory stage writes `valP = 0x027` (the address
of the instruction after the `call`, the `halt`) into `M[0x1f8]`; write-back puts
`valE` into `%rsp`; and `newPC = valC = 0x028`. One cycle, three effects — and the
return address is now _data_, sitting in memory like any other quad, exactly as
the [procedures lesson](/computer-architecture/machine-level-x86-64/procedures)
promised.

**Cycle 7, the `xorq`.** Zeroing a register by xoring it with itself is the
idiom from [the machine-level module](/computer-architecture/machine-level-x86-64/arithmetic-and-logic),
and it has a side effect the trace makes visible: the result is zero, so `ZF`
becomes 1. If the loop guard were checked _here_, it would fall through. The
program is correct only because `subq` reruns the flags every iteration before
`jne` reads them; flag liveness is part of the program's logic.

**Cycle 8, the `mrmovq`.** The first true memory read: `valE = R[%rdi] + 0 =
0x058`, and the Memory stage returns `valM = M[0x058] = 0x000d000d000d`, the
little-endian bytes `0d 00 0d 00 0d 00 00 00` reassembled into a quad. On the full
machine this is the access that would traverse the d-TLB and cache; here the ideal
memory answers in-cycle.

From there the loop turns four times, and the sum builds its answer nibble by
nibble. Each element contributes a different hex digit to every 16-bit group, so
you can watch correctness accumulate:

$$
% caption: The running sum in rax after xorq and after each of the four loop
% caption: iterations. Each array element fills a different nibble of every 16-bit
% caption: group, so the digits a, b, c, d assemble in place and the final value
% caption: 0xabcdabcdabcd is visibly correct - any wrong byte anywhere breaks the
% caption: pattern.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  vb/.style={draw, fill=acc!8, minimum width=34mm, minimum height=7mm,
             font=\footnotesize\ttfamily},
  nn/.style={anchor=west, font=\footnotesize\ttfamily, text=black}]
  \definecolor{acc}{HTML}{2348F2}
  \node[vb] (v0) at (0,0)    {0x000000000000};
  \node[vb] (v1) at (0,-0.95) {0x000d000d000d};
  \node[vb] (v2) at (0,-1.9)  {0x00cd00cd00cd};
  \node[vb] (v3) at (0,-2.85) {0x0bcd0bcd0bcd};
  \node[vb, fill=acc!25] (v4) at (0,-3.8) {0xabcdabcdabcd};
  \draw[->] (v0.south) -- (v1.north);
  \draw[->] (v1.south) -- (v2.north);
  \draw[->] (v2.south) -- (v3.north);
  \draw[->] (v3.south) -- (v4.north);
  \node[nn] at (2.1,0)     {after xorq (cycle 7)};
  \node[nn] at (2.1,-0.95) {iter 1: + M[0x058] = 000d000d000d};
  \node[nn] at (2.1,-1.9)  {iter 2: + M[0x060] = 00c000c000c0};
  \node[nn] at (2.1,-2.85) {iter 3: + M[0x068] = 0b000b000b00};
  \node[nn, text=acc] at (2.1,-3.8) {iter 4: + M[0x070] = a000a000a000};
\end{tikzpicture}
$$

Meanwhile `%rdi` walks `0x058, 0x060, 0x068, 0x070` and `%rsi` counts
`4, 3, 2, 1, 0`. The iteration-4 `subq` (cycle 26) produces zero and sets
`ZF = 1`, so the cycle-27 `jne` falls through to `0x057`. **Cycle 28, the `ret`**,
undoes the `call` symmetrically: Memory reads `valM = M[0x1f8] = 0x027`, the ALU
computes `valE = R[%rsp] + 8 = 0x200` for write-back into `%rsp`, and
`newPC = valM` — control returns to `main` not because the machine remembers the
call, but because the address was parked in memory and fetched back. Cycle 29
fetches `halt` at `0x027`, `Stat` becomes `HLT`, and the machine stops with
$\texttt{\%rax} = \texttt{0xabcdabcdabcd}$.

Trace any one of those cycles into the block diagram and every value is _derived,
not asserted_. In cycle 9 the PC holds `0x048`; the control unit, reading
`icode:ifun = 6:0` out of the fetched instruction word, drives the register file to read `%r10` and
`%rax` as `valA` and `valB`, steers both into the ALU with `alufun = add`, asserts
`set_cc`, routes the ALU output past the idle data memory to the register-file
write port with `dstE = %rax`, and — seeing `icode` is neither call, jump, nor
ret — selects `newPC = valP = 0x04a`. Not one wire was set by hand. The opcode
configured the fixed datapath, and the datapath did the rest.

> **Takeaway.** The assembled CPU runs a real program end to end: reset forces
> `PC = 0x000`, three `irmovq` cycles build the environment, `call` pushes `0x027`
> and enters `sum`, four `mrmovq`/`addq` iterations accumulate
> `0 -> 0x000d000d000d -> 0x00cd00cd00cd -> 0x0bcd0bcd0bcd -> 0xabcdabcdabcd`
> while `subq`/`jne` count the loop down, `ret` pops the parked return address
> into the PC, and `halt` stops the machine 29 cycles after it woke. Every value
> in the trace follows from the wiring — which means the assembled parts _are_ a
> working processor.

## Validating the machine

A trace that ends in the right answer is evidence, not proof. Real hardware teams
spend more effort on **verification** than on design, and the structure of that
effort follows the structure of the machine: test the parts, then the contracts
between them, then the whole.

**Unit tests, one part at a time.** Each functional unit has a small, closed
specification, so test it against that spec in isolation. The ALU is combinational:
drive operand pairs and check outputs: exhaustively at narrow widths (every 8-bit
pair is only 65,536 cases per function), then structured 64-bit cases targeting
the carry chain: `0 + 0`, `1 + (-1)`, alternating patterns, and the overflow
boundaries from
[integer arithmetic](/computer-architecture/foundations/integer-arithmetic). The
register file is stateful, so its test is temporal: write a distinctive value to
each register, read it back on both ports, and check the corner the
[clocking lesson](/computer-architecture/digital-logic/memory-elements-latches-flip-flops-and-clocking)
worried about: a read of the register being written this cycle must return the
_old_ value, because the write lands at the edge. Memories get address-in-data
patterns (write `0x58` at `0x58`) so any addressing error shows as a mismatch.

**The control table.** The control unit is a pure function from `icode:ifun` (and
`Cnd`) to a bundle of mux selects and write-enables, and the
[control-logic lesson](/computer-architecture/processor-design/control-logic-and-sequencing)
wrote that function down as a table. So the test is table-against-table: for each
of the ISA's opcodes, apply the opcode, read every control output, and compare
with the specified row. This catches the classic assembly bug (a mux wired to the
right control signal but with its inputs swapped) before any program runs.

**Per-instruction programs against the ISA model.** The
[ISA](/computer-architecture/instruction-set-architecture/what-an-isa-is) is the
machine's specification, and it is executable: an ISA-level simulator (CS:APP's
`yis`) applies each instruction's defined effect to an architectural state with no
hardware in sight. So write one tiny program per instruction (a `mrmovq` and a
`halt`, a `call` and a `halt`), run each on the hardware and on the model, and
compare the **complete architectural state** (registers, `CC`, memory, `PC`,
`Stat`) after every instruction. Any divergence identifies the faulty instruction
directly. Then add the behavioral pairs: `jne` taken and not taken, `call`
followed by `ret`, flags set then read.

**Integration.** Only now run `asum.ys`, and the cycle table above is
what the comparison looks like: the hardware's state trace laid against the
model's, cycle by cycle, with `0xabcdabcdabcd` as the visible checksum at the end.
A pipelined build adds one more layer, the hazard suite from
[module 5](/computer-architecture/pipelining/data-hazards-stalling-and-forwarding):
load-use pairs, `ret` followed immediately by work, a mispredicted branch with
in-flight wrong-path instructions, each written to force one forwarding or
stall path and checked the same way, against the ISA model that never pipelines
anything.

$$
% caption: The validation ladder. Unit tests check each part against its own spec;
% caption: the control table and per-instruction programs check the contracts, with
% caption: the ISA-level simulator as the golden model; integration runs whole
% caption: programs and compares complete state traces.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  vb/.style={draw, fill=acc!8, minimum width=78mm, minimum height=9mm, align=center},
  st/.style={anchor=west, font=\footnotesize\ttfamily, text=acc!80}]
  \definecolor{acc}{HTML}{2348F2}
  \node[vb] (l1) at (0,0)   {unit tests: ALU vectors, register ports, memory patterns};
  \node[vb] (l2) at (0,1.4) {contracts: control table + one program per instruction};
  \node[vb] (l3) at (0,2.8) {integration: \texttt{asum.ys} state trace vs the ISA model};
  \draw[->, acc] (l1.north) -- (l2.south);
  \draw[->, acc] (l2.north) -- (l3.south);
  \node[st] at (4.1,0)   {parts};
  \node[st] at (4.1,1.4) {contracts};
  \node[st] at (4.1,2.8) {whole machine};
\end{tikzpicture}
$$

> **Takeaway.** Validation mirrors assembly: test each part against the lesson
> that built it, test the control fan against the control table, test each
> instruction against the ISA model, and only then trust a whole-program trace.
> The ISA is the spec at every level — the hardware is correct exactly when no
> program can tell it apart from the model.

## Scaling up: the same machine, faster

What we built is the simplest correct CPU: one instruction per cycle, every stage
finishing before the next instruction begins. The rest of computer architecture is
this exact machine made faster, with the datapath unchanged in spirit.

- **Pipelined (PIPE).** Insert registers between the stages and let several
  instructions occupy the datapath at once, as the
  [complete PIPE](/computer-architecture/pipelining/the-complete-pipe-processor)
  does. The functional units are the very same PC, register file, ALU, and data
  memory; the additions are pipeline registers, forwarding paths, and a control
  unit that stalls or bubbles each register to handle hazards. On `asum.ys` the
  effect is concrete: the `mrmovq`/`addq` pair in the loop body is a load-use
  hazard costing one bubble per iteration, and each `ret` injects three — the
  [previous lesson's swimlane](/computer-architecture/capstone/the-whole-machine)
  is this program's inner loop.
- **Real x86-64 silicon.** A modern core is the same idea scaled hard: a deep
  pipeline, several ALUs, out-of-order issue, aggressive branch prediction, and a
  multi-level cache feeding it: the mechanisms the
  [previous lesson's honesty section](/computer-architecture/capstone/the-whole-machine)
  flagged as beyond scope. The instruction set is larger and the encodings
  messier, but underneath, an opcode still configures a fixed datapath of adders,
  register files, and memories, cycle by cycle.

## Two of them on one die

There is a second axis of scaling, and after
[module 9](/computer-architecture/multithreading-and-multicore/processes-threads-and-parallelism)
we can be precise about it. Duplicating the core is the easy part: the block
diagram above, stamped twice. What the duplication _demands_ is three new
mechanisms, none of which exists anywhere in the single-core machine:

1. **Coherence for the caches.** Each core needs private caches to run at speed,
   and the moment two caches can hold the same line, the machine needs a
   [coherence protocol](/computer-architecture/multithreading-and-multicore/cache-coherence):
   every line carries a MESI state, and a write in one core invalidates the copy
   in the other before it may proceed. Without this, our `asum` array could be
   summed from stale bytes.
2. **An interconnect.** The single wire from CPU to memory becomes a shared
   fabric: a snooping bus at two cores, a
   [ring or mesh](/computer-architecture/multithreading-and-multicore/multicore-organization)
   beyond that, carrying both memory traffic and the coherence messages, with the
   shared last-level cache hanging off it.
3. **Atomic instructions.** Software on two cores must be able to build locks,
   and ordinary load–modify–store sequences interleave. The ISA grows an atomic
   read-modify-write family (`lock`-prefixed ops, `xchg`, `cmpxchg`) and fences,
   the machinery of
   [memory consistency and synchronization](/computer-architecture/multithreading-and-multicore/memory-consistency-and-synchronization).
   The coherence protocol is what makes them enforceable, by letting a core
   hold a line exclusive for the duration of one read-modify-write.

$$
% caption: The dual-core extension of the assembled CPU. The core is duplicated
% caption: verbatim; what is new is everything between the cores: MESI coherence
% caption: across the private caches, a shared LLC on an interconnect, and atomic
% caption: read-modify-write support so software can build locks.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  u/.style={draw, fill=acc!8, align=center, inner sep=3pt},
  wl/.style={font=\footnotesize\ttfamily, text=black}]
  \definecolor{acc}{HTML}{2348F2}
  \node[u, minimum width=30mm, minimum height=9mm] (c0) at (1.5,3.5) {Core 0\\+ atomic RMW};
  \node[u, minimum width=30mm, minimum height=9mm] (c1) at (7.1,3.5) {Core 1\\+ atomic RMW};
  \node[u, minimum width=30mm, minimum height=8mm] (p0) at (1.5,2.0) {\texttt{private L1/L2}};
  \node[u, minimum width=30mm, minimum height=8mm] (p1) at (7.1,2.0) {\texttt{private L1/L2}};
  \draw[->] (c0.south) -- (p0.north);
  \draw[->] (c1.south) -- (p1.north);
  \draw[<->, acc, dashed] (p0.east) -- (p1.west);
  \node[font=\footnotesize\ttfamily, text=acc, anchor=south] at (4.3,2.1) {MESI coherence};
  \node[u, minimum width=104mm, minimum height=8mm, fill=acc!4] (llc) at (4.3,0.6)
        {\texttt{shared LLC + interconnect}};
  \draw[->] (p0.south) -- (1.5,1.0);
  \draw[->] (p1.south) -- (7.1,1.0);
  \node[u, minimum width=40mm, minimum height=8mm] (dr) at (4.3,-0.9) {memory controller + DRAM};
  \draw[->] (4.3,0.2) -- (dr.north);
\end{tikzpicture}
$$

And once the hardware exists, something must feed it two instruction streams:
[threads](/computer-architecture/multithreading-and-multicore/processes-threads-and-parallelism),
scheduled by the kernel our
[interrupt machinery](/computer-architecture/exceptions-and-io/interrupts-and-the-kernel)
already lets in every millisecond, or even
[two thread contexts inside one core](/computer-architecture/multithreading-and-multicore/hardware-multithreading),
sharing the pipeline we just assembled. The capstone machine is the unit cell;
module 9 is the crystal.

So the machine in the block diagram is the real thing in its clearest form.
Everything faster is this datapath plus
mechanisms to overlap and feed it; everything bigger is this datapath duplicated
plus mechanisms to keep the copies consistent; everything below is the gates we built
it from. That is the whole course in one picture: a switch became a gate, gates
became an ALU and a register file, an ISA fixed the bytes, control wired the
parts, and the assembled machine ran a program to the right answer, with nothing
directing it but its own PC and the bytes it pointed at.

> **Takeaway.** The capstone adds no new part. It wires the course's parts (PC,
> instruction memory and its fetch logic, register file, ALU, CC, data memory,
> control unit)
> along a spine, defines a reset state, and lets the clock run: 29 cycles later
> `asum.ys` has called a procedure, summed an array, returned, and halted with
> `0xabcdabcdabcd` in `%rax`. Validation checks the same structure in the same
> order (parts, contracts, whole machine, always against the ISA model). And the
> path onward is two-dimensional: pipeline the datapath for speed, or duplicate it
> and add coherence, an interconnect, and atomics for cores. From a transistor to
> a multicore, the machine is now something you can read off the page.
