12Instructions
At the end of the last chapter I made you a promise. The bytes sitting in RAM were about to stop being numbers and start being commands. This is where that happens, and it's stranger than it sounds. Take the pattern 00010010. Read it as a number and it's plainly 18 — one 16, one 2, done. But hand that exact pattern to the right circuit and it means something completely different: load register A from memory address 2. Nothing in the bits changed. Not one voltage moved. All that changed is which part of the machine is looking at them, and how. That is the whole idea of an instruction. Once you see it, the gap between "a pile of logic" and "a computer running your code" closes in a single step. In this chapter we'll lay the machine out as labelled blocks. We'll add the two registers that turn it from a calculator into a code-runner. We'll split one byte into an opcode and an operand, and walk a real instruction through its moves — timed, at last, by a clock we'll finally stop taking on faith and actually build.
01The machine, every wire named
Let's start from the thing you already built by hand. Last chapter you ran a little arithmetic program by pushing buttons. There was a couple of registers, an ALU, and an output, all hanging off one shared bus. You enforced one rule yourself: only one device may talk on the wire at a time. Here it is again, with the hand-written timing program tacked to the wall.
| beat · do this | Aₒ A→bus |
Aᵢ bus→A |
Bₒ B→bus |
Bᵢ bus→B |
Σₒ sum→bus |
Oᵢ bus→OUT |
|---|
It works, but notice who's doing the thinking. You are. You read each line of the program, and you pulse the control lines that make it happen. The machine has no idea what it's doing. It's a datapath, and you're the driver. To hand it a whole program and step back, we have to add the parts that let it read commands out of memory and act on them itself. So let's draw the full machine. This time we include RAM, and we name every control line on it. Two honest warnings about that map. First, don't try to memorise the wall of two-letter tags. Each one only ever means "this block, talk" or "this block, listen", and we'll work a handful of them — the enables on the RAM, on the two new registers, and on register A. Second, a few of them are for blocks that don't exist yet. CO, CE and J belong to a program counter and a jump unit we haven't built. They're on the map because the finished machine has them, not because this chapter uses them. You meet those next chapter.
Two blocks in there are new. Both are just registers you already know, given a specific job. But before we meet them, look hard at the block they both talk to — the RAM. It's the same addressable memory from Chapter 9. Feed it an address and it hands back the byte living there. Everything a program does begins with naming a cell.
There's one thing to notice about that address input: it's not free-floating. An address is just a binary number on a handful of wires. The count of wires is what sets how many cells you can name at all. Four address wires reach exactly sixteen cells — 0000 through 1111. Slide the width and watch the reach.
So let's stop treating that as an example and make it a decision. This machine gets 16 cells of RAM — and that choice settles the wiring for us. Sixteen cells need sixteen names, and sixteen names need four bits, so we run four address wires. Hold onto that number — four address wires, sixteen cells — and bank it as a fact about our machine, not as an illustration. It comes back the moment we split an instruction. When it does, it will decide the shape of every instruction we write. Now for the first new block. To feed RAM an address, we need somewhere to put that address and hold it steady while RAM reads. That's a register. But a register wired onto a shared bus needs two separate controls. This is worth re-seeing, because both new blocks are built exactly this way.
There it is. A bus register has a load-enable (latch what's on the bus, on the clock edge) and an out-enable (a tri-state buffer that drives the bus, or lets go). Notice the words on the clock edge doing quiet work in there. That's the IOU I asked you to sign back in Chapter 8, when I told you a tick exists and asked you to take it on faith. Hold the discomfort; we settle that debt in section 04. Wire one of these so its output goes to RAM's address input instead of back to the bus, and you have the MAR — the memory address register. Its whole life is simple: catch an address off the bus, and hold it against RAM's address pins so RAM knows which cell we mean. Nothing exotic. A register with a destination.
02When a number becomes a command
Now for the reinterpretation the whole chapter turns on. We keep saying a byte "is" a number, but that was always a choice about how to read it. You've already seen one byte wear two faces. The same eight switches that sum to a number can, through one agreed lookup, spell a letter. Watch it again, and this time hold the question in your head: what decides which face you get? Answer it before you read on, and be honest about your first instinct. Mine was that the number is the real value and the letter is a costume painted over it. Hold that answer somewhere you can see it. We're about to check it.
The bits don't decide. The reader decides. Route those eight wires into the ALU and they're a number to be added. Route them into an ASCII font and they're a glyph. Route them into the machine's control logic and they become an instruction. Same voltages, three meanings, chosen entirely by where the wires go. So there is no true reading hiding underneath. 18 was a costume too. Now let's build the reading that makes the byte a command — and let the machine size it for us. You have exactly eight bits, and two jobs to pay for: what to do, and what to do it to. Start with the second one, because it has a price you already know. It has to name any of our sixteen cells, and you already proved that naming sixteen cells costs four bits. So the bottom four are spent, and that half has a name: the operand. Now subtract, and you're holding the answer. Four bits left, one job left to buy with them — the top four are the opcode.
Notice what just happened there. Nobody agreed to four and four. You subtracted. And that means the boundary is not fixed — it moves when the machine moves. Build a RAM with eight cells instead of sixteen and what to do it to costs only three bits, which leaves five for what to do: a 32-operation instruction set on a machine with eight cells to point at. Widen the memory instead and the opcode starves. The two halves are eating off one plate, and the plate is eight bits wide. So an instruction format isn't tradition and it isn't taste. It's subtraction, done against the memory you built. Ours has sixteen cells, so ours is four and four. Split it and colour it.
00010010 stops being 18 and becomes op 1 on cell 2 — a verb and its target, packed in one byte. Flip any bit and watch the halves recolour and the instruction re-decode. That single cut is the whole idea of a machine instruction.Read 00010010 that way and it's no longer 18. The opcode 0001 names an operation. The operand 0010 is the number 2. Put them together and the byte says "do operation 1 to the thing at 2." A quick word on terms, because they get muddled. The opcode is the operation code. The operand is the value it acts on. And argument is just a looser everyday word for that same operand. Now, how many different operations can a 4-bit opcode name? This is a counting question you've answered before: every bit you add doubles the possibilities.
Four opcode bits give 2⁴ = 16 distinct instructions — a small but real instruction set. Now watch the two sixteens carefully, because they are not the same fact and it is easy to let them blur into one. Sixteen cells is the machine's shape, and it is a cause: it forced the operand to four bits. The operand is four bits, which reaches exactly sixteen values, so a 4-bit operand is precisely wide enough to name any cell in our RAM — the same sixteen cells, reached by the same four wires. Sixteen operations is not a cause at all. It's the change from the purchase: what four leftover bits happen to buy, once the memory has taken its share. One number sized the instruction. The other is what was left over afterwards. Now for the second new block. Something has to catch the fetched byte and hold it split — opcode one way, operand the other — while the machine acts on it. That's the IR, the instruction register.
The IR is one more register, but wired with a twist. Its opcode nibble runs off to the control logic to steer what happens next. And its out-enable drives only the operand — the low four bits — onto the bus. That's the detail that lets an instruction carry an address with it. When the machine wants the operand, the IR pushes just those four bits onto the wire, straight toward the MAR. Opcode to the brain, operand to the bus. One register, two exits.
One thing before we run anything, because it's the question you're already asking. The IR is empty. Something has to put a byte into it, and nothing we have built does. Think about what that would take. The machine would need to hold an address of its own — not one an instruction handed it, but one it keeps for itself — pass that address to the MAR, and then drink RAM's answer into the IR instead of into register A. That move has a name: the fetch. Now the honest admission. In this chapter I am putting the byte into the IR by hand, the same way you've been pulsing every other control line. The part that would do it for us has to remember where it is in the program, and that is a program counter — the next chapter's whole job. So you didn't miss a paragraph. I'm the one holding the byte.
03Running one instruction: LDA
So we have enough to run the execute half of a real instruction — the half that happens once the byte is already in hand. Let's take the one hiding inside 00010010: opcode 0001, which we'll call LDA — load A. Its meaning is exactly this: A ← RAM[operand]. Go to the memory cell the operand names, pull the byte living there, and drop it into register A. Here's the path that value has to travel, lit up across the datapath.
Nothing in there is a new part. It's the MAR, the RAM, the bus, and register A, all built in earlier chapters. They're wired so a value can flow operand → MAR → RAM → bus → A. The only question left is timing: which control lines go high, in what order, so exactly one thing drives the bus at each moment. Set an opcode and operand and route it yourself. Flip enables and watch the value move (or get stuck, if you let two drivers fight).
Play with it and you feel the constraint that shapes everything. The bus is a single shared wire, so the moves must happen in sequence. You cannot put the operand on the bus and read RAM onto the bus in the same instant. So LDA breaks into micro-steps, each one a single clean bus transaction, and each one landing on a tick. That tick is still the thing I asked you to take on faith in Chapter 8. Keep noticing that you're owed it. Step through them.
Two beats. On the first, the IR drives the operand onto the bus and the MAR latches it — now RAM knows which cell. On the second, RAM drives that cell's byte onto the bus and register A latches it — the load is done. Each micro-step is one source talking and one destination listening, marched forward by one tick of a clock. That raises the question we've dodged for four chapters: what is that tick, really?
04What keeps the beat
Back in Chapter 8 I asked you to take the clock on faith — a steady square wave, high for half a beat, low for the other half, forever, at a perfectly even tempo. I promised we'd build the real thing later. Later is now. First, remind yourself what the wave looks like. This even, tireless drumbeat is the thing every register on the machine listens to.
So where does a wave like that come from? Nothing we've built oscillates. Every circuit so far settles to an answer and sits there. The trick is to build something that can't settle. Take an odd number of inverters and wire them in a ring, output back to input. Now the loop is a liar. Feed a 1 in and it must come back a 0, which comes back a 1, forever chasing its own tail. It never finds a stable state. That failure to settle, happening as fast as the gates can flip, is the oscillation.
flips: 0
A 1 must give a 0, which must give a 1 — go round an odd loop and you arrive at your own opposite. Nothing can hold still. That refusal to settle, at gate speed, is the clock.
That's a ring oscillator — the honest, from-the-metal answer to "where does the clock come from." A real computer usually swaps the raw ring for a quartz crystal. That's a sliver of quartz that mechanically vibrates at one exquisitely precise frequency when you nudge it electrically (the piezoelectric effect). Same idea — a physical thing that will not hold still — just far more stable in its tempo. Either way, out comes the square wave. And that wave does its work at its edges, the near-vertical instant it snaps from low to high, or high to low. One full low-high-low is one clock cycle.
Now the subtle bit that makes the micro-steps actually safe. A source can be told to drive the bus whenever. The instant its out-enable goes high, its value starts crawling onto the wire. But a destination must not latch the moment its load-enable goes high, because the bus value isn't valid yet. Gates take real time to settle (that propagation delay we kept flagging), so for a few nanoseconds the wire holds garbage while the new value works its way through. So answer this one before I do. When exactly is it safe for the listener to grab? "When the bus is valid" is not an answer — the listener has no way to know that. It's a register, not a referee. What you need is an instant the whole machine agrees on in advance, the same instant for every block on the wire. There is exactly one, and it has been in front of you since the wave came on screen: drive anytime, but latch only on the clock edge. You AND every register's load-enable with the clock, so the catch happens at one sharp instant, after the bus has had the whole half-cycle to settle.
Don't take that on my word — go and get it wrong on purpose. The widget lets you drag the latch line anywhere across the beat. Drag it back into the smear, into the moment while the lines are still arriving at their own separate speeds, and watch what the listener bites down on: a value that was never on the bus at all, half old and half new, stitched together from a wire caught mid-thought. Then slide the latch onto the rising edge and watch the nonsense vanish. Being wrong on purpose is the cheapest anaesthetic there is. Once you've watched garbage get latched, the edge stops being a rule you were handed and becomes the only place the latch could possibly go.
That's the discipline under every transaction. The driver puts its value up early and holds it. The listener ignores the wobble and grabs the value exactly on the rising edge, when it's guaranteed clean. Reads wait for the edge. That single rule is why a machine full of gates that all take slightly different times to settle can still march in perfect, reliable lockstep.
05The same bytes, two lives
Step back and notice what we quietly assumed. The instruction 00010010 was sitting in the same RAM that holds the numbers the program works on. There is no separate "code memory." A cell holding a command and a cell holding a value are physically identical — the same eight flip-flops, the same address. A byte is an instruction only because, at that moment, the machine chose to fetch it into the IR and read it as one. That is the stored-program idea, and it is the reason a computer is universal rather than a fixed calculator.
Both lives, one memory. Some rows we'll feed to the IR as opcode-plus-operand commands. Some rows we'll pull through the ALU as plain numbers. The RAM cannot tell them apart, because there's nothing to tell. Meaning lives in how a byte is read, not in the byte. We'll lean on that hard in a few chapters, when a program computes over its own instructions. For now, one honest admission about where we are. We ran a single instruction, but look back at what running it took.
A hand-timed ritual: enable this, pulse that, latch here, around again. It's the exact seven-beat dance you did by hand back in Chapter 10, now dressed up as LDA. It's a machine, but it's a machine with a human as its clock-and-controller. Every one of those choices, though, was a fixed function of the situation. For this opcode, on this step, assert these lines. And you already know what a fixed function with an answer for every case is: a lookup table. A ROM. The hand punching the control lines is about to be replaced by the same decode-and-OR furniture you built last chapter, pointed at the machine's own controls.
That's Chapter 12. A byte became a command the instant we split it into an opcode and an operand and fed the halves to different parts of the machine — opcode to the control logic, operand out to the bus. We added the two registers that make it possible. The MAR names a cell for RAM, and the IR holds the instruction and drives just its operand. We ran LDA as a fixed sequence of bus moves. And we finally built the clock — a ring oscillator that can't hold still — and saw why a read waits for its edge. But one instruction is not a program. A program is many instructions. To run them, the machine has to remember where it is and march forward on its own, advancing through RAM without a human reading the lines. That self-driven march is the fetch–execute loop, and it's next.