Lab · Exploration
From transistor to CPU
Start with one transistor switching an LED, wire switches into gates, gates into an adder, feedback into memory, and memory plus a clock into a tiny CPU — then watch a real 6502 run a program you can read byte by byte.
Part 1 of 7 in How things work
UsesCircuit simulatorDigital logic simulator6502 assemblerAtari 8-bit computer: emulator, BASIC, assembler and debugger
A computer is the most complicated thing most of us own, and it is made almost entirely of one very simple part, repeated. A 6502 — the processor in the Apple II, the Commodore 64, the BBC Micro and the Atari 800 — has about 3,500 transistors. A modern laptop chip has tens of billions. In both, each transistor does the same humble job: it is a switch that one wire can turn on and off.
This exploration climbs from that switch to a working processor in six steps, and at every step there is a live circuit on the page for you to poke. Nothing is hidden behind a diagram: each level is built, visibly, from the one below it. By the end you will have run a program on a CPU made of gates you can see, and then on a real 6502, and the two programs will look remarkably alike.
Step 1: a switch that a wire can flip
A transistor has three connections. In the bipolar kind used below, a small current into the base lets a much larger current flow from the collector to the emitter. Push a milliamp into the base and the transistor turns hard on; take it away and it turns off. For analogue work we care about the region in between, where the transistor amplifies. For digital work we deliberately avoid it: we only ever drive the transistor fully on or fully off.
Here is the simplest useful circuit there is. A pulse generator, Vin, swings between 0 V and 5 V
every millisecond. It feeds the base of transistor Q1 through a 4.7 kΩ resistor. Q1’s collector
pulls current through a red LED and a 220 Ω resistor from the 5 V supply.
Scroll down inside the frame to the Transient (scope) plots. The orange trace is the input, the
blue trace is vc, the voltage at the collector — the point between the LED and the transistor.
Try this:
-
Look at the two traces side by side. When
vinis low,vcsits high, at about 4.2 V. Whenvingoes high,vcdrops to almost nothing. The Currents plot shows why: about 13.5 mA flows through the LED only while the input is high. -
Select
Rband change it to100k, then press Run transient. Less base current means the transistor is no longer driven hard on, andvcno longer falls cleanly to zero. That in-between region is exactly what digital designers keep away from. -
Put it back to
4k7and changeRledto1k. The LED current falls, but the shape ofvcdoes not: on is still on, off is still off.
What to notice: the output is the opposite of the input. High in, low out; low in, high out. Read
vc as the output and you have not just built a switch, you have built a logic gate — a NOT gate,
or inverter. Everything else in this exploration is made of the same trick, applied over and over.
Real chips use MOSFETs rather than bipolar transistors, because a MOSFET’s gate draws almost no current, and they pair an n-type with a p-type transistor (CMOS) so that one is always off and the circuit draws almost no power when it is not switching. The palette has an NMOS part if you want to try building one. The idea is the same: a voltage on one wire decides whether another wire is connected.
Step 2: from switches to gates
Put two transistors in series, so current only flows when both are on, and the output is pulled low only when both inputs are high: that is a NAND gate. Put them in parallel, so either can pull the output low, and you have NOR. Add an inverter after either and you get AND and OR. From here on we stop drawing transistors and draw gates instead, the way chip designers do. It is the first abstraction on the climb, and it is a safe one: every gate below could be swapped for a handful of transistors without changing a thing.
Two switches, A and B, feed seven gates. Bright wires and outputs are 1, dim ones are 0.
Try this:
-
With both switches off, notice that NAND, NOR, XNOR and NOT A are already lit. A gate whose name starts with N is the inverse of its namesake.
-
Flip
Aon. AND stays dark (it needs both), OR lights (it needs either), XOR lights (it wants them different). -
Now turn
Bon too. XOR goes dark again, XNOR lights. XOR is the odd one out of the seven, and it is about to become important: it is the gate that adds.
What to notice: NAND on its own is enough to build every other gate — NOT is a NAND with its inputs tied together, AND is NAND then NOT, and so on. That is why early logic families sold chips full of nothing but NAND gates, and why "everything is NAND" is the usual first surprise in a digital course.
Step 3: gates that add
Add two one-bit numbers and there are only four cases: 0 + 0 = 0, 0 + 1 = 1, 1 + 0 = 1 and 1 + 1 = 10 in binary — that is, a sum bit of 0 and a carry of 1. Look at those sum bits: 0, 1, 1, 0. That is XOR. Look at the carries: 0, 0, 0, 1. That is AND. Two gates make a half adder.
It is only half an adder because it cannot accept a carry coming in from the column to its right. A full adder takes three inputs — A, B and a carry in — and makes a sum and a carry out. You can build one from two half adders and an OR gate.
This opens on the Truth table tab, which simulates the circuit for every combination of its
inputs. The top part of the circuit is the half adder (inputs A, B, outputs S and C); the
bottom part is a full adder packaged as a reusable component (inputs A2, B2, Cin, outputs
Sum and Cout).
Try this:
-
Find the rows where
A2,B2andCINare all 1. BothSUMandCOUTare 1: one plus one plus one is three, which is 11 in binary. -
Scroll down past the table: for each output the tool reads the logic back as an expression and minimises it. The full adder’s sum turns out to be a three-way XOR.
-
Switch to the Circuit tab and double-click the Full adder block to look inside it. A component is just a circuit with pins — the second abstraction on the climb.
Chain four full adders, each one’s carry out feeding the next one’s carry in, and you can add two four-bit numbers.
The switches come in pairs: A0/B0 is the lowest bit, A3/B3 the highest. The four sum bits
and the final carry come out on the right, with the sum shown in hex.
Try this:
-
Turn on
A0andB1: 1 + 2. The display reads 3. -
Now set A to 7 (
A0,A1,A2on) and B to 1 (B0on). Every column produces a carry that the next column has to absorb, and the display jumps to 8. -
Set every switch on: 15 + 15. The display shows E and
Carrylights: 30 is 1 1110 in binary, one bit too many for four, so the fifth bit falls out as the carry. -
Turn on Gate delays in the toolbar and repeat 7 + 1. Now each gate takes a moment, and you can watch the carry ripple from bit 0 to bit 3, the sum briefly showing wrong values on the way.
What to notice: this is a ripple-carry adder, and the ripple is its weakness. A 64-bit version has to wait for a carry to crawl through 64 stages. Real processors spend extra gates on carry-lookahead logic that works out all the carries at once. Speed in hardware is often bought with more transistors.
If you would rather write this than wire it, the Adders and hierarchy lesson of the HDL trainer has you build the same full adder and four-bit chain in Verilog, the language chips are actually designed in.
Step 4: memory from feedback
Everything so far has been combinational: the outputs depend only on the inputs right now. Turn the switches back and the answer goes back too. A computer also needs to remember — the number it is adding to, the instruction it is on — and the trick that gives gates a memory is wonderfully small. Feed a gate’s output back into its own input.
Two NOR gates, each feeding the other. Set and Reset are push buttons. When the page opens,
the outputs are red: unknown. Nobody has told the circuit what to remember yet, and the
simulator is honest about it.
Try this:
-
Hold
Setfor a moment and let go.Qgoes to 1 and stays there, even though nothing is pressing it any more. Each gate is holding the other in place. -
Press
Reset.Qdrops to 0,Q̄rises, and that state holds too. -
Press
Setagain while it is already set. Nothing changes. The latch only cares about which button was pressed last.
What to notice: that is one bit of memory, built from two NOR gates — eight transistors in CMOS. This SR latch is the ancestor of every register in a CPU. Add a little gating so that it only listens when a clock signal says so, and you have a flip-flop: a bit that changes only on the tick of a clock. Line up four flip-flops and you have a four-bit register. Wire their outputs back to their inputs through some logic and you have a circuit that steps through states on its own — the binary counter example does exactly that, counting 0 to 15 from four flip-flops and two AND gates.
The clock is the quiet hero of digital design. Between ticks, the combinational logic is free to glitch and ripple as much as it likes, as you saw in the adder. On the tick, every flip-flop captures the settled answer at once. A designer’s main job is to make sure the slowest path through the logic settles before the next tick; the length of that path sets the clock speed.
Step 5: a CPU you can see inside
We now have every ingredient. A register to hold a number. An adder to change it. A counter to step through a list. Some memory to hold that list. Put them together with one more idea, and you have a processor.
The idea is that the list is instructions. A counter, called the program counter or PC, points at a byte in a read-only memory. That byte is decoded: some of its bits say what to do (the opcode), the rest give a number to do it with (the operand). The decoded bits steer multiplexers — switches made of gates — that route the right values into the adder and the right result into the right register. On the next clock tick, the result is captured and the program counter moves on. Then it all happens again.
This is a whole four-bit CPU in about two dozen parts. Find the pieces from earlier: the Counter on
the left is the program counter, ROM holds the program, DEC decodes the opcode, the ALU is an
adder that can also subtract, A is the accumulator register, C is the carry flag (a single
flip-flop, with a yellow LED) and OUT is an output register. Hex displays show the PC, A and OUT. It starts running as soon as it
loads.
The program in the ROM is four bytes long:
00 LDI 0 ; A ← 0
13 loop: ADD 3 ; A ← A + 3
20 OUT ; OUT ← A
31 JMP loop ; PC ← 1
Each byte is one instruction: the high hex digit is the opcode, the low digit the operand. So 13
means "opcode 1 (ADD), operand 3".
Try this:
-
Watch the
OUTdisplay, on the far right: 3, 6, 9, C, F, then 2. Four bits can only count to 15, so 15 + 3 wraps round to 2 — and the carry flag notes that it happened. -
Press Pause, then Cycle to advance one clock period at a time. The display under the counter is the PC; watch it go 1, 2, 3, then jump back to 1.
-
Turn on Gate delays and run slowly. Every instruction becomes a little wave of activity spreading from the ROM through the decoder and ALU, settling before the next tick.
-
Select the ROM to edit the program. Try
LDI 5,l: OUT,SUB 2,JC l,HLT. It counts 5, 3, 1 and then stops, because the third subtraction borrows, clears the carry flag, and the conditional jumpJCfalls through to the halt.
What to notice: the program is data. Nothing in the hardware changed when you edited the ROM, yet the machine did something different. That is the whole point of a processor, and it is why the same chip can run a word processor, a game, or this web page. The second program also shows the other essential ingredient: a conditional jump. A machine that can choose what to do next based on a result is, given enough memory, able to compute anything computable.
Step 6: a real 6502
The 6502 was launched in 1975 at a price of $25, when its rivals cost several times as much, and it ended up in a huge share of the home computers and consoles of the next decade. It is an eight-bit processor rather than a four-bit one, with three registers (A, X and Y), a stack, more addressing modes, and around 150 opcodes instead of eight. But at heart it is our tiny CPU, grown up: a program counter, a decoder, an ALU, an accumulator and a handful of flags.
Here is the "count in threes" program again, written for the 6502.
The listing on the right shows each instruction’s address and the bytes it assembles to: A9 00
for lda #0, 18 for clc, 69 03 for adc #3, 8D 00 02 for sta $0200 and 4C 02 06 for
jmp loop. Eleven bytes in all.
Try this:
-
Compare it with the tiny CPU’s ROM. Load, add, output, jump: the same four ideas. The 6502’s instructions are longer because its addresses are sixteen bits, so
jmp loopneeds two bytes to say whereloopis —02 06, low byte first. -
Notice the extra
clc(clear carry). The 6502 has no plain add:adcalways adds the carry flag too, so that a sixteen-bit sum can be built from two eight-bit ones. Delete theclcand the program may count in fours whenever the previous sum overflowed. -
Switch to the Opcode table tab and filter for
ADC. There are eight versions of it, one for each way of finding the number to add, each with its own cycle count.
Assembling is only half of it. Below is an Atari 800XL, emulated in WebAssembly, with a 6502 that runs the real Atari operating system. The example program is fifteen lines long and does something no amount of reading quite prepares you for.
Try this:
-
Press Assemble & run. The machine powers on, the program is assembled and loaded at
$2000, and the screen fills with scrolling bands of colour. -
Read the loop. It reads
VCOUNT, the number of the scan line the TV beam is drawing; adds the frame counter so the pattern moves; thensta WSYNC, which freezes the CPU until the beam reaches the end of the line; then stores the value inCOLBK, the background colour. Every coloured stripe on the screen is one trip round a six-instruction loop. -
Press Pause and open the Debugger tab. The registers you see there — PC, A, X, Y, S and the flags — are the 6502’s equivalents of the tiny CPU’s counter, accumulator and carry flip-flop. Press Step and watch the PC move through the loop one instruction at a time.
-
Replace
adc RTCLOKwithadc #0, or addasl aafterlda VCOUNTto double the line number, and run it again. Small edits, very different pictures.
What to notice: that loop is racing a television. Each 6502 instruction takes two to six clock cycles, at about 1.8 MHz, and a scan line lasts 114 cycles. Programming these machines meant counting cycles the way we counted gate delays in the adder: the logic has to settle before the next tick, only now the tick is the edge of the picture.
The climb, looking back
Six steps, each a small idea:
-
A transistor is a switch controlled by a wire, and wired the right way it is a NOT gate.
-
A few transistors make NAND and NOR, and NAND alone can make every other gate.
-
XOR and AND make a half adder; two of those make a full adder; a chain of them adds numbers.
-
Feedback turns gates into memory; a clock makes that memory change in step.
-
A counter, a ROM, a decoder, an adder and a register make a processor, and the program is just data in the ROM.
-
Grow every part — wider words, more registers, more opcodes — and you have a 6502. Grow it again, with caches, pipelines and billions of transistors, and you have the chip you are reading this on.
At no point did anything magic happen. Each level is the one below it, wrapped up and given a name. The only genuinely surprising thing is how few kinds of idea it takes.
Where to go next
-
Digital logic simulator — build your own circuits, or open the traffic-light state machine, seven-segment decoder and glitch examples.
-
Boolean logic — minimise expressions and draw the Karnaugh maps behind the adder’s equations.
-
Circuit simulator — the transistor level, with real device models and ngspice to compare against.
-
HDL trainer — learn Verilog from wires and gates up to UARTs, VGA and FIFOs.
-
FPGA playground — a small CPU in Verilog, synthesised and placed on a real FPGA in the browser; the RISC-V example goes further.
-
6502 assembler — assemble, disassemble and browse every opcode with its cycle counts.
-
Atari 8-bit computer — more 6502 examples, from display-list interrupts to player-missile graphics, with a full debugger. The 6502 also lives in the Apple II, Commodore 64 and BBC Micro tools.