◈ computers mapVol 1 · Ch 10/19
How Computers Work from the transistor up · chapter 10

10The Bus

Chapter 9 left us with a working memory and an ugly problem. Every part we've built — the ALU, the registers, now a whole bank of RAM — needs to hand numbers to every other part. The obvious way is one private cable from each component straight to each of the others. But then the cabling grows as the square of the number of parts. Ten components already want forty-five separate connections, and the count runs away from you. That's the rat's nest we ended on. This chapter is the one clean idea that dissolves it, and it's almost embarrassingly simple. Instead of a private wire between every pair, we run one shared set of wires — a bus — straight past every component, and let each one tap in exactly once. The wiring drops from to N. But sharing a wire is dangerous in a way a private wire never was. Here's the catch the last chapter promised you: if two components shove opposite voltages onto the same line at the same instant, you don't get a garbled number. You get a near-zero-resistance path straight from the power rail to ground. By V = IR with R heading for zero, that's a current spike big enough to literally cook the chip. So the bus buys cheap wiring at the price of one ironclad rule: exactly one component may talk at a time. Enforcing that rule takes a genuinely new part — the tri-state buffer. It can do something none of our gates could: not drive a 1, not drive a 0, but electrically vanish, releasing the wire so someone else can use it. Build that, hang one on every component, and we can finally run a real computation the way the machine itself soon will — as a strict sequence of one-driver-at-a-time transfers over a single shared highway. No magic: cheaper wiring, one hard rule, and a new switch that knows how to shut up.

01The rat's nest, and the highway

Let's start by making the mess visible, because the fix only feels inevitable once the problem is unbearable. Every component needs to send numbers to every other one. So the naive plan is a dedicated set of wires from each part to each part — A to B, A to C, B to C, and so on. Add components below and watch the connections sprout. Two parts need one link; three need three; four need six. Every new part has to reach all the ones already there.

1 dedicated wires 2 parts × 1 ÷ 2 = 1 2 components
two parts, one wire — trivial
Every new part must get its own wire to every part already there. The wires don’t add up — they multiply.
Point-to-point wiring: give every component its own dedicated wire to every other one and you build the complete graph. Two parts need one wire; add a third and it sprouts two more; by a dozen parts you’re at 66 wires — the count climbs as parts×(parts−1)÷2, so it roughly squares as parts grow. That’s the rat’s nest we ended Chapter 9 on, and the reason the next idea — one shared bus everyone taps — had to exist.

That growth isn't just "a lot" — it has a precise, ruinous shape. Connecting N parts pairwise takes N·(N−1)/2 wires. That climbs as the square of the count: double the components and you nearly quadruple the wiring. It's the same combinatorial blow-up you'd get counting handshakes in a room — the eleventh person shakes ten new hands. Slide the part count below and watch the wire tally curve upward, while a single shared line, for comparison, just crawls along as a straight N.

point‑to‑point a private wire for every pair 1 wires shared bus one line, everyone taps in 1 taps on 1 line wires needed parts N → N(N−1)/2 N
N = 4 → point‑to‑point 6 wires  vs  bus 4
6 wires vs 4 — the mesh is pulling ahead
every part you add shakes hands with every other one. Point‑to‑point pays for the handshakes — N(N−1)/2, the square. The bus charges a flat N: bolt on and tap in.
Fig 2. The wiring bill for N parts. Point‑to‑point (left) gives every pair its own private wire — the handshake blow‑up: N(N−1)/2, which climbs as the square of N. Two parts is one wire; twelve is sixty‑six. A shared bus (right) is one line everybody taps into, so the cost is a flat N. Drag the count and watch the orange curve peel away from the blue while the mesh knots itself solid — that runaway square is exactly why every machine settled on a bus.

So here's the move, and it's the whole chapter in one picture. Stop giving each pair a private wire. Instead lay down one shared set of wires — call it the bus — running past every component, and let each part make exactly one tap onto it. A byte-wide bus is just eight such shared wires side by side. Now a part doesn't need a route to every other part. It needs a single stub to the common line, and anything it puts there is visible to everyone at once. Wire the same components onto a bus below and watch the tangle collapse: the cabling is now just N taps, no matter how many parts you add.

Before we lean on that shared line, ask the only honest question about it: what can one wire actually hold? A wire is one node. Touch it at the ALU’s tap, at the RAM’s tap, out at the far end past every component, and you measure the same voltage — because it is all one piece of metal. That is the whole law, and it is smaller than it sounds. The bus is not eight opinions sharing a line. At any instant it is one number, set by whatever is currently tying it to a rail. Hold onto that sentence. Everything else in this chapter is that one law read twice — once for the parts that only listen, once for the parts that push.

point‑to‑point 3 wires N(N−1)/2 grows like N² bus would need: 3
3 parts → 3 wires point‑to‑point, 3 taps on a bus
still tidy — but watch it as you add parts
Fig 3. The same parts, wired two ways. In point‑to‑point mode every pair needs its own dedicated wire, so the count climbs as N(N−1)/2 — add an eighth part and you're staring at 28 tangled wires. Flip to one shared bus: a single set of conductors runs past every component and each one taps in exactly once, so the count is just N. Drag components up and watch the tangle explode while the bus stays flat — that collapse from N² to N is the whole reason real machines share one highway instead of running private wires everywhere.

02One wire, many talkers

A shared wire changes the rules of the game, so let’s feel exactly how — first the good news. Reading a bus is free and unlimited. Look at what a listener is. Every gate’s input leg is a MOSFET gate — the plate from Chapter 1’s cross-section, behind a thin insulator, never touching the silicon it steers. Its field reaches through; its electrons never do. So the leg has no path to anywhere, and draws essentially no current. Now read that off the node’s one law: a thing that pulls no current cannot move the wire’s one voltage. Name that property here, where it is easy — the input is high impedance. It senses the wire without leaning on it. So any number of components can tap the same line, and none of them disturbs it or each other. A listener just measures what’s there. So “everyone can hear everyone” costs nothing. Put several listeners on one line below, drive a value onto it, and watch them all read the same bit in perfect agreement — no conflict, no limit.

DRIVER 1 one wire · one value on it readers draw ≈ 0 µA line sag 0.00 V · no conflict
3 listeners tapping the wire
3 listeners, every one reading 1 — in agreement
Reading is free. The driver sets the wire to a single voltage — a 1 or a 0. Every listener just taps that wire: its input is high-impedance, drawing almost no current, so it can't disturb the value or fight the others. Add one listener or eight and the driven bit never sags and never splits — they all sense the same thing, in perfect agreement. (Real chips have a fan-out limit, but within it, one more ear costs the line essentially nothing — the reason a bus can broadcast to the whole machine at once.)

Here's the mental model that makes a shared wire actually work, and it's about time, not space. The bus holds one value at any given instant — whatever the current talker is putting there — and the components take turns using it. One moment the wire carries register A's byte. The next moment, after A lets go, it carries the ALU's result. A moment later, a value on its way into RAM. The single highway is shared by scheduling, the way one lane of traffic serves many cars by having them go one at a time. Step the turns below and watch one wire carry a whole sequence of different values, one owner per beat.

CPU 0x2A · 42 enable RAM 0xFF · 255 enable I/O 0x07 · 7 enable GPU 0x91 · 145 enable one wire · one lane · every device shares it the bus, now 42 00101010 ↓ the SAME wire, sampled over time — a different owner, a different value, each beat
beat 1 · CPU owns the wire · carrying 42
Only one device is enabled at a time — its tri-state buffer connects, everyone else sits in high-Z (electrically unplugged). Two drivers at once would fight (bus contention), so the wire carries exactly one value per beat. Step the turns.
The bus is shared in time. A bus is one set of wires that many components tap — but a wire can hold only one value at any instant. So the parts take turns: each beat, exactly one device switches its tri-state buffer on and drives its value onto the lane while everyone else drops into high-Z (electrically disconnected). Step the turns and watch the single wire carry a whole sequence — 42, then 255, then 7, then 145 — one owner per beat. It's one lane serving many cars: cheap, shared, and strictly one-at-a-time. Let two drive at once and you get bus contention — the reason the enable line is sacred.

Now the bad news, and it's the reason the rest of the chapter exists. Reading is safe; writing is not. Suppose two components decide to drive the same wire at the same instant. One pushes it toward +5 V for a 1; the other yanks it toward 0 V for a 0. The wire can't be both. What you get isn't a compromise voltage or a scrambled bit. It's called bus contention, and it's a hardware emergency, not a logic error. Trigger it below: set two drivers to disagree and watch the wire's voltage collapse into a forbidden no-man's-land while the panel throws a SHORT warning.

Vcc 5 V GND 0 V pull-up pull-down Driver A the bus — one shared wire I ≈ 0 mA Driver B ⚡ SHORT — Vcc tied to GND valid 1 ≥ 3.5 V forbidden 1.5–3.5 V valid 0 ≤ 1.5 V 5.00 V
Driver A (left)
Driver B (right)
A drives 1, B released — clean 5 V on the bus.
Now make them disagree: set one driver to drive 1 and the other to drive 0. Watch the wire fall off the rails.
Fig 6. Every driver on a bus can pull the wire up to Vcc, pull it down to GND, or let go (Hi-Z). Leave one driving and the other released and the bus reads a clean 1 or 0. But set them to disagree — one shoving up, one yanking down — and you haven't made a garbled bit, you've wired Vcc straight to ground. Current floods the path, the voltage collapses into the forbidden zone that no gate can decode, and the SHORT alarm fires. This is why a bus needs one talker at a time — and it's the whole reason the next pages exist.

Let’s not hand-wave the danger — let’s look at the physics. It’s one honest line, and it’s the whole justification for the tri-state part coming next. A driver that outputs a 1 is a closed switch tying the wire up to the +5 V supply. A driver that outputs a 0 is a closed switch tying that same wire down to ground. Turn both on at once and you’ve wired the power supply directly to ground through two closed switches. So ask the honest question: what is left in that path? Only the transistors themselves. A closed MOSFET is not a perfect wire — it is a small resistance, its on-resistance — and here two of them sit end to end. That series pair is the entire R in I = V / R, with the whole supply standing across it. Nothing about it is imaginary. It is a fixed, small, real number, and a small R under 5 V means a large I — far more current than drivers built to feed a few insulated gate legs were ever sized to carry. That surge dumps its energy as heat in the tiny transistors doing the driving, and they burn out. Sweep the resistance down below and watch the current — and the heat — run away.

+5 V GND · 0 V DRIVER A drives 1 DRIVER B drives 0 total path resistance R SHORT the bus Ohm's law · I = V / R 0.10 A current through the drivers 0.5 W heat dumped in the silicon junction heat WARM wasting power, holding on
Driver A puts on the bus
Driver B puts on the bus
R = 50.0 Ω · both drivers fighting: +5V wired straight to GND
short circuit — one drives 1, the other 0
Fig 7. One bus wire, two drivers. Driving a 1 ties the wire to +5 V; driving a 0 ties it to ground. Set them to agree and the bus holds a clean bit — no path, no current. But make them fight — one to +5V, the other to ground — and you've wired the supply straight to ground through the drivers' own resistance R. Now drag R toward zero and watch Ohm's law bite: I = V/R spikes without limit, the heat P = V²/R runs away, and the drivers go from warm to BURNED. This is why only one thing may drive a shared bus at a time.

03Learning to stay silent — the tri-state buffer

So the rule is now clear — exactly one driver at a time — but our whole toolkit fights it, and it’s worth feeling why. Every gate we’ve built is a driver that never shuts up. Take the AND gate we used as a read-valve back in Chapter 3. When its enable leg is low, its output is 0 — but that’s not silence. It’s a driver actively holding the wire down at 0 V. Re-meet the AND-as-valve below and watch: even “shut,” the gate is still forcing a hard 0 onto its output. On a private OR-tree that was fine. On a shared bus, a component stuck forcing 0 is exactly the second talker that causes contention. Now go one level down and see why it cannot help itself. Every output we have ever built ends in the same two switches: a pull-up to the supply, a pull-down to ground, gates tied together. Ask for a 1 and the top one closes. Ask for a 0 and the bottom one closes. That is the law of our own hardware, and we proved it in Chapter 2 — exactly one of the two is closed, always. Which leaves a question we have never once put to it. Two switches means four ways to set them, and we have only ever used two. Top closed. Bottom closed. That leaves two we have never built. One of them is the short we just drew — both closed, supply straight to ground. What is the other?

pipe SHUT — output pinned to 0 ENABLE leg 0 0 DATA leg 0 OUTPUT
enable
data
enable 0 · data 0 → output 0 — pipe shut
Try this: leave enable at 0 and flip the data leg — the output won't budge. Now set enable to 1 and flip data again: the output copies it exactly. One leg of an AND is just an on/off valve for the other.
Fig. An AND gate is a valve. The enable leg works the wheel: turn it to 0 and the sluice drops across the pipe — the data signal knocks against the gate but the output stays pinned at 0, no matter how you flip the data leg. Turn enable to 1 and the gate lifts: now the pipe is open and the output simply copies whatever the data leg is doing. One leg gates; the other passes. That is the whole trick behind using AND to switch a signal on and off.

Neither. Open both switches at once. That is the one setting our own output stage has never been in, and it is the third option we needed — because a leg wired to neither rail isn’t driving 1 and isn’t driving 0. It is a dangling stub. It has let go of the wire entirely, and it is electrically as good as not connected at all. So this is not a new part fetched from a shop. It is the output stage we already own, plus one control leg: assert that leg and the two switches follow the data exactly as before; drop it and both lift away together. Box that up and you have the tri-state buffer — a data input, a data output, and that one extra control leg, the enable. When enable is 1, the buffer is a plain wire: whatever’s on its input drives its output, 0 for 0, 1 for 1. When enable is 0, the output does neither. It enters the third state, a floating disconnect we’ll name in a second. Toggle the enable below and watch the output flip between “driving a real value” and a grey, released nothing.

Now stop, because there is a wrong turn right here that a lot of people never come back from. Three states — so is that a third digit? A new value the wire can carry, alongside 0 and 1? Answer it yourself before you read on. No. Nothing we just did touched the wire. It is still one node holding exactly one voltage, precisely as it was three pages ago. What gained a third state is the driver: it now has three things it can be doing — pushing the line up, pulling it down, or nothing at all. That third one is a statement about where its switches are, not about what the line holds. Three states of the driver; two values on the wire. Keep those apart and everything after this is easy.

THE BUS 1 DATA IN ENABLE 1 1 driven
enable = 1 · the value flows straight through, like a plain wire
Flip enable to 0 and the output lets go of the bus — no 1, no 0, just a grey floating nothing (engineers call it high-impedance, Z). That release is exactly what lets many chips share one bus: all stay in Z but the one that's talking.
Toggle enable. At 1 the buffer is invisible — the input value walks straight onto the bus, driven and coloured, current flowing. At 0 the output lets go: not a 0, not a 1, but a third state — a grey, high-impedance Z where the wire simply floats. That release is the whole trick behind a shared bus: dozens of chips hang off the same wires, all sitting in Z, and only the one that's enabled gets to speak.

That third state has a proper name — high-impedance, written Hi-Z — and it's worth understanding at the metal instead of accepting as magic. "Impedance" is just resistance's more general cousin: how hard the part fights the flow of current. A driver outputting a 1 has low impedance up to the supply. Outputting a 0, it has low impedance down to ground. Hi-Z means enormous impedance in both directions at once. The internal pull-up switch and pull-down switch are both held open, so the output leg is connected to neither +5 V nor ground. It's a dangling stub. The wire is free to be whatever someone else makes it. Open up the buffer below and watch both internal switches lift away, cutting the output loose.

tri-state buffer +5 V GND · 0 V OUT ↯ floating OE = 1 5.00 volts out
Driving 1 — the top switch is closed, so OUT is tied hard to +5 V.
In Hi-Z, both internal switches lift open at once — OUT connects to neither +5 V nor ground. It's a dangling stub, free for another chip to drive the same wire.
Hi-Z at the metal. A tri-state buffer's output stage is just two switches: one to +5 V, one to ground. Drive a 1 and the top one closes; drive a 0 and the bottom one closes — always exactly one, so OUT is pulled firmly to a rail. Click Hi-Z and both lift away at once. Now OUT is wired to neither rail: a dangling stub at high impedance, contributing nothing to the line — which is precisely how many chips can share one bus wire and take turns driving it.

And now the payoff — the fix for the emergency we triggered two figures back. Put a tri-state buffer on each component's connection to the bus, and the "exactly one driver" rule becomes something you can actually enforce. Assert exactly one buffer's enable at a time, and force every other buffer to Hi-Z. The one enabled driver owns the wire. All the rest have electrically vanished, so there's no second talker and no short — ever. Wire the same two clashing drivers through tri-states below and hand each an enable. Keep both enabled and you'll still get the SHORT. Enable just one and the wire goes clean, the loser floating harmlessly away.

Driver A wants 1 · pulls to 5V OE=1 Driver B wants 0 · pulls to 0V OE=1 SHORT the shared bus one wire · many drivers · a tri-state on each
Both enabled — two drivers fighting for the wire. Dead SHORT.
The one-driver rule, now enforceable: assert exactly ONE enable. Every other driver goes Hi-Z and lets go of the wire — so no short can happen.
Fig 11. Two drivers, one wire. Driver A wants a 1 (pulls to 5V), Driver B wants a 0 (pulls to 0V). Enable both and they clamp the same node in opposite directions — that red animated current is a dead short, real heat, real damage. The fix is a tri-state on each output: a third state beyond 1 and 0 — Hi-Z, high-impedance, electrically let go of the wire. Assert exactly one enable and the loser floats out of the way; the bus reads a clean value with nobody fighting. The one-driver rule stops being a hope and becomes a wire you can actually enforce.

04Wiring the machine onto the bus

We have the discipline and the part that enforces it. Now let's actually hang the machine we've built onto one shared highway, component by component. Start with the piece from Chapter 8: the register, eight flip-flops on one clock holding a whole word. Recall it below. This is the first citizen of the bus, and in a moment we'll give it a tap.

D inputs — click a bit to set the wires on the wires · 0100 1000 = 72 CLK Q outputs — the byte held in the register held · 0
wires ≠ register — hit CLOCK to store
Eight flip-flops, eight separate D wires, one clock. Change the D bits all you like — Q won’t budge until the single rising edge, and then all eight snap over together. That instant is when a whole number first gets stored.
Eight flip-flops = a register. Each of the eight D flip-flops watches its own input wire, but they all share a single clock line. Set the byte on the wires by clicking the D bits — nothing reaches the Q outputs yet. Press CLOCK and one rising edge makes all eight flip-flops sample at the very same instant, latching the whole byte at once. That shared-edge capture is the first device that stores a complete number: the register.

A register needs to do two jobs on the bus, and each is one enable line. But first a word about the word, because “enable” is about to mean two different things, and it is cheaper to split them now than to untangle them later. To put its stored word onto the shared wires, the register drives them through a tri-state buffer gated by an out-enable. That one means talk. Assert it and the register owns the wire; drop it and the register floats, silent. To take a word off the bus, it uses its load-enable. That one means catch, and it isn’t new. It is the steered enable we built in Chapter 9 — the input that decides whether a register swallows the data on its D lines at the next edge or quietly reloads its own output instead. There it wore the name write-enable, because RAM was doing the writing. Hung on a bus, the same input is called load-enable. So a bus-connected register has three postures: drive (out-enable on), listen (load-enable armed), or float (neither). Work the two enables below and step it through all three.

That split is worth one more beat, because the two enables are not the same kind of thing at all, and blurring them is how people lose track of a bus. An out-enable is electrical, and it is continuous: while it is asserted, that buffer’s switches are physically clamping the line to a rail for the whole beat. It is also exclusive. Across the entire machine, at most one may ever be up, or you are back to the short. A load-enable is temporal, and it is cheap: it arms a register to sample the wire, and one clock edge spends it. Nothing is being pushed. So arm two catchers at once and both simply take the same value — nothing burns. That asymmetry is why only one question ever matters on a bus: who is driving right now? And why the answer must always have exactly one name in it.

SHARED BUS · what everyone sees 42 0010 1010 OE LE THE REGISTER · holds 170 1010 1010 EN ANOTHER DEVICE · offers 42 0010 1010
DRIVE
LISTEN
FLOAT
OUT-ENABLEdrive the bus?
LOAD-ENABLElatch from the bus?
float · the register sits off the bus, holding 170
THE OTHER DEVICEso LISTEN has something to hear
One wire, many devices — so a register needs two gates. The out-enable is a tri-state buffer: only when it’s on does the register push its value onto the bus; off, its output goes high-impedance and vanishes electrically. The load-enable latches whatever the bus is showing back into the register. Two drivers at once → contention. Nobody driving → the bus floats.
Fig 13. One register on a shared bus. A plain latch isn’t enough — because dozens of devices share the same wires, a bus-connected register needs two enables. The out-enable is a tri-state buffer: switch it on and the register drives its value onto the bus; switch it off and its output goes high-impedance — electrically absent, as if unplugged. The load-enable latches whatever the bus is showing back into the register. That gives three clean postures: drive (out-enable on), listen (load-enable on, someone else driving), and float (both off — holding its value, hands off the wire). Break the discipline and the bus tells you: two drivers at once is contention, and latching a bus nobody drives captures pure noise.

Next, the arithmetic. Recall the ALU from Chapter 6 — two operands in, one op-select line, one result out. On a bus machine, its two operand inputs come from registers and its result has to reach the shared wires like everyone else. Re-meet the ALU black box below before we plug it in.

ALU 13 − 5 SUBTRACT one adder · B inverted · Cin = 1 A = 13 B = 5 op-select: SUB one control line picks the operation RESULT 8 0b1000 no borrow
1101 − 0101 = 1000 · no borrow
Same box, same wires — the op-select alone decides what comes out.
Fig 14. Meet the ALU — arithmetic logic unit. It's a black box with the same three ports every time: two operands in the left, one op-select line in the bottom, one result out the right. Feed it A and B, then flip the op-select. SUB reuses the very adder that does ADD — it just inverts B and adds one (two's complement), and its carry-out tells you whether it had to borrow. Bolt a few logic ops (AND, OR, XOR) onto that same select line and the adder-that-subtracts has quietly become the calculating core of every CPU.

Here’s how the ALU joins the highway, and it is the one place the bus reaches out and dictates the shape of the machine. Try the obvious thing first: put both operands on the bus and let the ALU take them. You already know why that request is impossible. The ALU wants two numbers at the same instant, and the bus is one node — one node holds one number. There is no instant at which it is showing you both. So the operands cannot both come off the wire at the moment the ALU needs them. They have to be sitting still beside it already. That is what the two dedicated operand registers are for — A and B. Be exact about the wiring, because it blurs easily. A and B are loaded from the bus on an edge, like any register on the highway. But the ALU does not read them through the bus; their outputs run straight into its two operand inputs. The ALU chews on them continuously and presents a result. And that result reaches the bus through a tri-state buffer with its own out-enable, exactly like a register. So “do some math and put it on the bus” is just this: load A, load B, pick the op, enable the ALU’s output buffer. Set the operands and the op below and enable the result onto the wire.

a shared bus (4 bits, the Ch. 6 ALU recalled) A = 10 B = 6 + ALU OE=0 Hi-Z · floating
Click the bits inside registers A and B to set the operands — they wire straight into the ALU. Pick an op. The answer exists the instant you change anything, but it can't touch the bus until you flip the buffer's output-enable.
tri-stated — result held back, bus floats
buffer disabled — the ALU has an answer, but the bus is floating (Hi-Z)
Fig 15. An ALU doesn't fetch its inputs from the bus — it has two dedicated operand registers, A and B, wired straight into it. Click their bits and pick an op: the result appears immediately at the ALU's output. But that output isn't hard-wired to the bus — it passes through the ALU's own tri-state buffer. With output-enable OFF the buffer is high-impedance: the answer just waits, and the bus floats, free for some other unit to drive. Flip OE on and the buffer connects the result to the wire — only now does A op B reach the bus. Same discipline as every other talker on the bus: compute privately, speak only when enabled.

And the last citizen: the whole RAM from Chapter 9. It's no different in kind — it's one more component that reads and writes the bus through a tri-state tap. On a read it drives the addressed word onto the shared wires (out-enable, behind its own tri-state). On a write it latches whatever's on the bus into the addressed slot (its write-enable). Recall the RAM block below — the same control-line-plus-datapath shape — and picture its data port opening onto the bus instead of a private cable.

ADDR 00 which cell same address also steers the read mux → SEL 2 → 4 decoder word / select lines WE write-enable · 0 0 1 2 3 0000 0000 0000 0000 register file — the memory DATA-IN value to store · 1010 read mux 0000 DATA-OUT = 0
WE is low — the write pulse is gated off.
Read is live: the addressed cell flows through the mux to DATA-OUT.
You set ADDR, flip WE, and pulse write by hand. That hand — deciding what happens when — is the seed of a control unit.
The whole RAM, one block, its lines named. Two families of wire run through it. The control linesADDR, WE, and the decoder’s word-lines — carry no data at all; they only steer, deciding which cell is chosen and whether a write may happen. The datapath — the registers, the data-in bus, the register outputs, the read mux and data-out — is what actually carries the bits. Slide address and the same signal steers both the write-decoder and the read-mux; notice a write only lands when WE is high and you pulse write. Toggle control lines / datapath to see each family alone. And the thing setting ADDR, raising WE, choosing the moment to pulse — that’s you. Automate that hand and you’ve built a control unit.

05Running a program by hand

Every part is on the highway now, each with a tri-state out-enable to talk and a load-enable to listen. So let’s define the single move the whole machine is made of — the bus transaction. Count it carefully, because this is the atom every later chapter is built out of. A transaction is one beat, and three roles are filled inside it. Before the edge, you assert exactly one source’s out-enable, so it drives the wire: that is the talker. Every other driver in the machine is standing in Hi-Z — not a step you take, but the standing condition, true for the whole beat. Also before the edge, you arm exactly one destination’s load-enable. Armed, not fired: nothing has moved yet. Then the clock edge arrives and the value lands. Drive, Hi-Z, latch. One driver, many listeners, one catcher. Run a single transaction below — choose who drives, choose who latches, pulse the clock — and watch the “who’s driving?” indicator confirm the rule is never broken.

One more thing about that standing condition, because it has a second face and the chapter would be dishonest without it. Ask the mirror question. If Hi-Z means no switch anywhere is closed, what is the wire when every driver on it is in Hi-Z? Not 0. That is the instinct, and it is wrong: 0 is a voltage, and holding a wire at 0 V takes a closed switch to ground — which is exactly what nobody has. Nothing is tying the line to anything. So it is not 0 and it is not 1. It is floating — drifting on whatever stray charge and coupling happen to be nearby, and perfectly able to read back as either. Arm a load-enable over a bus like that and you do not latch a value, you latch noise. Same physical state, two faces: the cure when exactly one talker is enabled, the hazard when none is.

CLK ON THE BUS ← REG A 0x2A · 42 THE BUS · 8 shared wires · exactly one owner at a time
REG A owns the bus. B · C · D sit in Hi-Z (listening).
Three roles, every beat: one source drives, everyone else sits in Hi-Z listening, the destination copies the bus on the edge.
Fig 17. One bus, four registers, one rule. Pick a source and its tri-state buffer switches on (OE▲) — it pushes its byte onto the shared wires while the other three buffers go to Hi-Z (the dashed wires, marked Z): electrically disconnected, just listening. Pick a destination, then pulse the clock: on the rising edge it latches whatever the bus holds. Drive nobody and latch anyway and you capture a floating bus — pure garbage — which is exactly why the hardware guarantees exactly one driver per move. Drive, Hi-Z, latch: every transfer inside the machine is that same three-role handshake.

Now chain those transactions and something wonderful happens. We can run the exact computation that broke a single register back in Chapter 9: (a + b) − (c + d). Count every beat, including the dull ones — the count is the program. Beat 1: the source drives a, R0 latches it. Beat 2: the source drives b, R1 latches it. Beat 3: the ALU reads R0 and R1, and its add result drives the bus into R2. Watch beats 4 and 5 closely, because they look like a repeat and are not: the source drives c into R0 and d into R1, overwriting a and b. Those two are spent — they already live inside R2. Beat 6: the ALU adds again, and R3 catches c+d. Beat 7: the ALU reads R2 and R3, and its subtract result drives the bus into R0. Seven beats, and not one of them free. Every step is the same atomic move — one talker, one edge. Step through the whole ritual below.

beat 0 / 7 THE BUS SOURCE a 6 b 3 c 2 d 4 · R0 scratch · R1 scratch · R2 holds a+b · R3 holds c+d + ALU
a+b = · c+d = · = ·
next: load a → R0
seven clean beats — one talker, one edge, per beat.
The single register that raced tried to be talker and listener at once. Here every beat has a different one of each — so it just works.
Fig. 18 — Running (a+b)−(c+d) by hand. This is the exact sum that made a lone register thrash when it tried to feed itself. On the bus it comes apart into seven calm beats: load a, load b, add and store, load c, load d, add, subtract and store. Watch each beat — one talker drives the wire, the ALU reads two registers, and exactly one register latches on the clock edge. No box is ever talker and listener at once, so nothing races — the answer just falls out. Set your own a, b, c, d and run it again.

Step back and look at what you just did with your own hands, because the next few chapters live inside this observation. Running that program was nothing but a fixed sequence of control signals. On beat 1, enable this out and arm that load; on beat 2, the next pair; and so on. It’s the same choreography every time you compute the same thing. You were the conductor, punching out-enable and load-enable lines in a set order. But a fixed sequence of switch-flips is precisely the kind of thing a circuit can do without you — a little machine that, tick by tick, asserts the right control lines in the right order. The table below shows that discipline written down. Fair warning: those are not your seven beats. It is a smaller machine — two registers and an adder, counting up by three — with its choreography printed one row per beat, a mark under whichever out-enable drives and whichever load-enable catches. And it shows you something your own run could not. Beats 1 and 2 are the identical row, thrown twice. So the rows are not clever. They are bit patterns you could copy, repeat, and store. Hold onto that, because a table of “what to assert when” is the seed of the thing that will finally replace you at the panel.

THE BUS · one wire, one talker hi-Z on the bus REG A 0 Aₒ Aᵢ REG B 3 Bₒ Bᵢ ADDER A + B 3 adder taps A & B directly Σₒ REG OUT 0 Oᵢ
beat · do this Aₒ
A→bus
Aᵢ
bus→A
Bₒ
B→bus
Bᵢ
bus→B
Σₒ
sum→bus
Oᵢ
bus→OUT
panel idle · 0 / 3
Nothing is asserted yet — every switch is down, the bus floats (hi-Z). Step through the score below.
Read it as sheet music for a wire: each row says who drives the bus and who latches it this beat. You are the machine right now — throwing the switches by hand.
A little computer, laid bare: registers A and B, an adder, and an OUT register, all hanging off one shared bus — and only one thing may talk on it at a time. Below sits the whole program: a timing table, one row per clock beat, marking which out-enable line drives the bus (•) and which load-enable line latches it. Step through it and you are the machine, throwing those switches by hand. Notice beats 1 and 2 are the identical row, thrown twice — repeated addition, counting up by three. Now press let it run: the score plays itself, no hand on the panel. Freeze those rows onto a turning drum and wire it to the switches and you've built the thing that punches the panel for you — a program counter and a control ROM. That machine is where the next few chapters are heading — starting, next, with the frozen table that makes it possible.

And that's Chapter 10 — the chapter where a rat's nest became a single clean highway. We started buried in wires: connecting N components pairwise costs N·(N−1)/2 cables, a count that explodes as the square of the parts. The fix was one shared set of wires — the bus — that every component taps exactly once, dropping the wiring to a flat N. Sharing came with a gift and a threat. Any number of parts can read the wire for free. But let two of them drive it to opposite voltages and you don't get garbage — you get bus contention, a dead short from +5 V to ground where I = V/R with R → 0 spikes the current and burns the drivers. The cure was a genuinely new part, the tri-state buffer: an enable that either drives the value or releases the wire into high-impedanceHi-Z, both internal switches open, electrically vanished. Hang one on every component — each register, the ALU with its two operand registers, the whole RAM — and the machine runs as a strict sequence of bus transactions: one driver enabled, everyone else in Hi-Z listening, one destination latching on the edge. We proved it by running (a+b)−(c+d) entirely by hand. And that hand-work is the cliff-hanger. Every move was a fixed choreography of control lines, the kind of "assert these, on this beat" table a circuit could execute on its own. But before a machine can conduct itself, it needs two more things it can only get from a table baked into silicon — a way to show its answer, and a way to store its own instructions. Both turn out to be the same device: a decoder feeding an OR array, frozen. That's the lookup table, and the ROM — and it's next.

iolinked.com
Written by Ajai Raj