↑ ↓ to move · enter to open

C01 · Computers · Logic gates, machine code, pipelines

the cpu

A processor is a huge number of tiny switches wired into a few simple patterns. Some patterns add numbers. Others read a byte from memory, decide what it means, and act on it, over and over, billions of times a second. This page builds that up from one gate to a working toy CPU, then shows the tricks that make real ones fast.

LAB 1

adding with logic gates

A logic gate takes one or two bits and puts out one bit by a fixed rule. Poke the inputs below. Five of these gates make a full adder, which adds three bits. Chain one full adder per bit and you can add whole numbers, as long as each carry waits for the one before it. Click the A and B bits to change the numbers.

four gates · click a switch or a table row
ripple-carry adder · bit 0 is on the right
inside one full adder
settled
Width

How to read this: Gates: green = 1 (on), dark = 0 (off), and the highlighted table row is the one you're on now. AND needs both on, OR needs at least one, XOR needs exactly one, NOT flips its input. Adder: each column adds one bit of A (top), one bit of B, and the carry from its right; FA is that column's full adder and the bottom square is its answer bit. The carry passes leftward, so each column waits for the one to its right.

  • a 1 in A or B
  • a 1 in the answer
  • dashed square: not worked out yet
  • amber FA and dot: the carry still travelling
  • green wire: a carry of 1 passed left
  • red carry out: the answer didn't fit

In the gate diagram below the adder, a green wire carries a 1 and a dim wire a 0. The sum wire turns gold and the carry wire red when they carry a 1; red here just means "send 1 to the next column".

Try this: Press "all carries", then "Replay ripple", and watch the amber dot walk from right to left.

—
A
—
B
—
Adder output (n bits)
—
Carry out
—
Gates used
—
Worst-case delay

Full adder, in gates

sum = a ⊕ b ⊕ cin
cout = (a · b) + ((a ⊕ b) · cin)

⊕ is XOR (1 when the inputs differ), · is AND, + is OR. Each full adder uses 5 gates. Count every gate as one delay: a carry leaves bit 0 after 3 delays and each later bit adds 2, so an n-bit ripple adder settles in 2n + 1 delays at worst.

Now

CodePython

Why it matters

The ripple is the price of simplicity. A 64-bit ripple adder would need 129 delays in this model, so real CPUs use carry-lookahead designs that work out many carries in parallel with extra gates. Subtraction reuses the same adder: flip B's bits and set the first carry in to 1 (two's complement, from C00 · Bits & bytes). XOR also powers the trick in 014 · Missing number.

LAB 2

fetch, decode, execute

A CPU repeats three steps. Fetch the byte the program counter (PC) points to. Decode it into an operation, a register and an address. Execute it. This toy CPU has 16 bytes of memory holding both the program and its data, two registers, and two flags. Every byte is just a number; it acts as an instruction only when the PC lands on it. Click a memory row to edit it.

CPUnext: fetch

fetchdecodeexecute
Z (zero)0C (carry)0
ALU idle
address bus
data bus

RAM · 16 bytesprogram + data

addrbitshexdecas instruction
toy CPU
Program
as code

How to read this: Left: the CPU's tiny scratch pads, called registers. PC says which byte to run next, IR holds the instruction just fetched, R0 and R1 hold working numbers. Flag Z lights when the last result was zero, C when the last sum didn't fit. The ALU does the arithmetic, and the buses carry an address and a byte between CPU and memory. Right: the 16 bytes of memory.

  • amber bar on an address: the PC points here
  • amber row: being read or written now, or a register that just changed
  • red C: the last sum didn't fit
  • gold number: the program's answer
  • dashed outline: the cell you're editing

Try this: With "Add two numbers", press "Step phase" nine times and follow the amber highlights.

—
Clock cycles
—
Instructions done
—
Result
—
Status

Now

Instruction setbyte = ooo r aaaa

3 bits pick the operation, 1 bit picks R0 or R1, 4 bits give an address 0–15. Byte 0 decodes as HALT, so empty memory stops the CPU. In this toy every instruction takes exactly 3 clock cycles, one per phase.

CodePython

Why

Program and data share one memory, so a program could even overwrite its own instructions. A loop is just a jump backwards, and an if is a conditional jump that checks a flag the ALU set. Real CPUs have more registers, wider words and hundreds of instructions, and they run the same fetch, decode, execute cycle. Memory itself is the topic of C02 · Memory & RAM.

LAB 3

faster: clocks, pipelines, cores

There are three ways to get more instructions per second: tick the clock faster, finish more instructions per tick, or run more cores. A pipeline helps with the middle one. It splits each instruction into five stages and keeps all five busy, like a laundry where the washer, the dryer and the folding table each work on a different load. Branches cause trouble: the CPU must guess where to fetch next before it knows.

pipelined
8
i3

How to read this: Read across a row to see an instruction move through the five stages. In pipelined mode several rows are busy in the same column, and that is the speed-up.

  • IF fetch the instruction
  • ID decode it
  • EX do the math (branches are decided here)
  • MEM read or write memory
  • WB write the result back
  • stage done
  • happening this tick
  • struck through: work thrown away after a wrong guess
  • final step of the last instruction

Try this: Switch to "One at a time" and compare the cycle count. Then pick "Branch, guessed wrong" and spot the two red rows.

throughput calculator
3.5 GHz
1.00
8
—
Cycles for the run
—
Instructions per cycle
—
Speedup vs one at a time
—
Cycles lost to flush
—
One clock tick
—
Instructions per second

Counting cycles

one at a time: cycles = n · k
pipelined: cycles = k + n − 1 + 2 · (wrong guesses)
throughput = clock × IPC × cores

With k = 5 stages, the first instruction needs 5 cycles to get through and every later one finishes 1 cycle after the one before. In this model a branch is decided in EX, so a wrong guess throws away the 2 instructions fetched behind it.

Now

CodePython

Real chips (typical figures)

Typical laptop and desktop CPUs today clock at roughly 2 to 5 GHz and have roughly 4 to 24 cores. Their big cores are superscalar: they fetch and finish several instructions per cycle, so IPC above 1 is common, while this five-stage diagram tops out at 1. Their pipelines are deeper too, and a wrong branch guess typically costs on the order of 10 to 20 cycles. Branch predictors guess right on the large majority of branches in typical code.

The calculator is an ideal upper bound. It assumes the work splits perfectly across cores and that memory keeps up, which real programs rarely manage.