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 N² 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.
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.
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.
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.
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.
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.
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.
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?
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
| beat · do this | Aₒ A→bus |
Aᵢ bus→A |
Bₒ B→bus |
Bᵢ bus→B |
Σₒ sum→bus |
Oᵢ bus→OUT |
|---|
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-impedance — Hi-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.