A computer is switches, wired so that patterns of on and off stand for numbers, and arranged so that some of those numbers stand for instructions. This page builds one from the bottom β two voltages, then a gate, then an adder, then a cell that remembers, then a processor running a program you can edit. Nothing is hidden on the way up, and you can check every step yourself.
A wire is either near 0 volts or near the supply voltage. Call them 0 and 1. Eight wires side by side give 256 possible patterns, and we agree that each pattern stands for a number. Toggle the switches.
Each place is worth twice the one to its right, exactly as the columns of a decimal number are worth ten times the one to their right.
Hexadecimal is only shorthand: each hex digit is exactly four bits, so a byte is always two of them. Nobody wants to read 11010110 aloud.
A logic gate is a few transistors wired so the output voltage depends on the input voltages in a fixed way. That is the whole idea. Pick a gate, flip its inputs, and fill in its truth table as you go β the table is blank until you have actually tried each combination.
NAND is AND followed by NOT. In CMOS it costs four transistors and is the cheapest useful gate there is β AND is literally built as a NAND with an inverter bolted on the end. It is also functionally complete: wire enough NANDs together and you can reproduce every other gate, which means every circuit on this page could be made of nothing else. Toggle the inputs and check.
Nothing new gets introduced here. Arithmetic is a pattern of the gates you have already met, and so is memory β the only difference is that a memory circuit feeds its own output back into its input.
1 + 1 = 10 in binary. XOR gives the sum bit, AND gives the carry. That is the entire circuit.
To chain adders together each one has to accept a carry coming in as well as producing one going out. Three inputs, two outputs, five gates.
Each full adder here is exactly the five-gate circuit above. Set both numbers, then step the carry along the chain and watch each stage wait for the one below it to make up its mind.
Bit 0 cannot be wrong, but bit 3 has no idea what its answer is until the carry has physically travelled through every stage below it. A carry crossing one full adder passes through an AND and then an OR: two gate delays. Four bits is eight, and a 64-bit ripple adder is 128.
At roughly 5 picoseconds per gate that is about 0.64 nanoseconds β but one tick of a 4 GHz clock lasts only 0.25 nanoseconds. The sum would not be ready in time. That is why real processors do not use this circuit: they use carry-lookahead adders, which compute the carries in parallel from the inputs instead of passing them along.
The clock has to be slow enough that the slowest path in the whole chip settles before the next tick. Every clock speed you have ever seen quoted is that limit.
Each gate's output is wired back to the other's input. Set S and the latch goes to 1; take S away again and it stays at 1. That is a stored bit β the other half of what a computer needs.
Six of these hold one bit of the SRAM in a CPU cache, which is why cache is fast and expensive. Main memory cheats instead: DRAM stores each bit as a charge on a tiny capacitor, one transistor per bit, and the charge leaks away, so every row has to be read and rewritten thousands of times a second. That refreshing is what the D in DRAM means β dynamic.
Set both S and R to 1 and the circuit does something it was never meant to: both outputs go to 0, and Q is no longer the opposite of QΜ. Release them together and which value the latch lands on is a genuine race between the two gates. Real designs forbid that input.
Registers are latches. The ALU is adders. The control unit is gates decoding the top four bits of whatever number arrived. Put them together and you get a machine that runs in a three-beat loop forever: fetch, decode, execute. This one genuinely works β step it and check the arithmetic.
The accumulator is the only place this CPU can do arithmetic. Everything else is moving numbers to and from it β which is exactly what the earliest machines did, and what the assembly on the left says out loud.
Write one instruction per line. A label ends in a colon; DATA reserves a byte. Assembling turns this text into the sixteen numbers in the table beside it.
Sixteen bytes. The highlighted row is where the program counter is pointing next.
Look down the table. Every byte gets read as a number and as an instruction, because nothing in the memory records which it is. The number 10 sitting in a data cell is 00001010, and the processor would happily execute it as HALT if the program counter ever wandered in there. The last column is the assembler's opinion, not the machine's.
This is the stored-program idea, written down by von Neumann in 1945 and used by essentially every computer since. It is why software can be a file you download rather than wiring you solder, why a compiler can write a program, and also why so many security holes exist: talk a machine into treating your data as instructions and it will run them.
A MOSFET has three terminals. Put a voltage on the gate and it pulls charge into a thin channel under it, so current can flow between the other two; take the voltage away and the channel empties and current stops. No lever, no contact, nothing to wear out, and it switches in picoseconds.
Process names such as "3 nm" measure nothing physical any more β they are marketing labels. The real gate lengths are nearer 16 nm and the tightest wiring pitch about 24 nm, which is roughly 100 silicon atoms across.
Apple M4 β 28 Γ 10βΉ transistors Β· NVIDIA B200 β 208 Γ 10βΉ over two diesSwitching power goes as capacitance Γ voltageΒ² Γ frequency. For thirty years every shrink let the voltage drop too, so chips got faster without getting hotter. That stopped: below about 1 volt the transistors leak whether or not they are switched on, so voltage flattened out and power density started climbing towards the impossible.
The answer was to stop making one core faster and start putting more of them on the die β which moves the problem to the programmer, because most tasks do not split neatly into parallel pieces.
Pentium 4, 2004: 3.8 GHz Β· fastest desktop today: ~6 GHz Β· but 1 core β 24, and 192 in a server partA crystal oscillator vibrates at a fixed frequency β often 25 MHz β because of its physical shape, and a phase-locked loop multiplies that up to the gigahertz the cores run at. Every register on the chip updates on the same edge of that signal, which is what keeps billions of switches in step.
"Overclocking" is raising the multiplier so the clock ticks before the slowest path has finished settling. Sometimes the answer is still right. Sometimes it is not.
Source code is text β bytes, in the same memory. A compiler reads it and emits machine code for a real instruction set, which is the same trick as the assembler above but with a far larger opcode map. Nothing about the process is magical; you can read the output.
On x86-64, a whole function that adds two integers comes out as four bytes:
int add(int a,int b){return a+b;}That 0.7 V on a wire is physics. Everything above it is agreement: that high means 1, that eight bits make a byte, that 01000001 means "A" in ASCII, that the top four bits of an instruction are the opcode, that a file starting with certain bytes is a PNG.
All of it could have been decided differently, and some of it was β ASCII beat EBCDIC, little-endian beat big-endian on the desktop. The machine has no opinion. It only ever sees voltages, and it is doing exactly what the switches make it do.
Level 1 is a wire. Level 2 is four transistors. Level 3 is a few dozen gates. Level 4 is a few thousand β early microprocessors really were this small: the Intel 4004 of 1971 had 2,300 transistors and ran at 740 kHz.
A modern core is the same picture with more of everything, plus caches, branch prediction and the ability to have a hundred instructions in flight at once. The three-beat loop underneath has not changed.
Memory is a hierarchy because signals take time to travel and big things are slow to search. These are typical figures for a desktop x86 core at 3.2 GHz, where one cycle is 0.31 nanoseconds. The right-hand column is what each wait would feel like if that cycle lasted a second β the arithmetic is done on the page from the nanosecond figures.
Cache latencies vary by chip and the disk and network figures are round numbers, but the shape is right and it is the shape that matters: a processor that reaches main memory on every operation spends almost all of its life waiting. Caches exist to make that rare.