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

13The Fetch–Execute Loop

Last chapter we taught the machine to read a single byte as a command. It split the byte into an opcode and an operand, fed the halves to different parts of the datapath, and we watched a single byte load register A from memory. It worked. But look closely at who ran it: you did. You picked the instruction. You set the operand. You flipped the enables in order. The machine was a beautifully built puppet, and your hand was inside it. Now I want to take my hand out — and yours. Because a program isn't one instruction. It's a list of them sitting in RAM. Running a list means answering two questions the machine can't answer yet: which instruction am I on right now, and how do I get to the next one by myself? That whole leap — from "a pile of logic that does one thing when poked" to "a computer running your code" — is hidden in those two questions. The answer is one small register that holds an address and knows how to count. It's called the program counter. It drives one tight, tireless cycle: fetch the instruction it points at, advance to the next, execute what it fetched, then go around again. That loop, spinning on its own, is the difference between a machine and a computer.

01Where am I? The program counter

Here's the machine as we left it. Every block sits on one shared bus, along with the two new registers from last chapter: the MAR, which names a memory cell, and the IR, which catches the instruction. Take one more slow look, because we're about to spot the single thing it's missing.

THE 8-BIT CPU · EVERY BLOCK, EVERY CONTROL LINE 8-BIT DATA BUS ADDR A B Program Counter CO · CE · J +1 MAR MI → ADDR RAM RO · RI (WE) Instruction Reg II · IO A register AI · AO ALU SU · EO A + B B register BI OUT · display · OI 042
out-enable · drives the bus load-enable · reads the bus control · no bus traffic
out-enables — put a byte ON the bus
load-enables — take a byte OFF the bus
control — steer, don't carry data
Click any control line to light the wire it drives. Hover a block to read what it does — or run a real bus transfer below to watch a byte move.
watch a transfer · one out-enable + one load-enable
Hover any block for its job.
Fig 1. Here is the whole machine at once — every block that matters, wired around one shared 8-bit bus. The vocabulary of this chapter is the set of control lines: the orange out-enables (CO, RO, IO, AO, EO) that shove a byte onto the bus, the green load-enables (MI, RI/WE, II, AI, BI, OI, J) that latch one off it, and the gold control lines (CE, SU) that steer without carrying data. Click any line to light exactly the wire it drives; hover a block to hear its job. Then run a transfer: every move inside a CPU is just one out-enable feeding the bus while one load-enable drinks from it — and an instruction is nothing more than a timed list of which lines to raise.

Now the reframing that starts the whole chapter. A program is not one instruction. It's a column of them, sitting in consecutive cells of the same RAM that holds your data. Address 0 holds the first command, address 1 the next, and so on down. The cut is the one we agreed last chapter, and it never moves: the top four bits of a byte are the opcode, the bottom four are the operand. Try it on 01001000. Read it as a number and it's 72 — one 64, one 8. Cut it in half and it's a store into address 8. Nothing in the byte changed. Here is that RAM strip again. Picture the top few rows not as numbers but as an ordered to-do list the machine will work through, top to bottom.

addr the eight stored bits — identical either way byte you tag it the reader then sees
Click a row's CODE / DATA tag. Watch: the eight bits never move — only the reader's reading of them flips. The tag isn't in the silicon; it's a decision.
Fig 2. One strip of RAM. Every row is the same kind of thing — eight stored bits — and the bit colours here depend only on whether each bit is a 1 or a 0, never on what the row is "for." Tag a row CODE and the reader decodes those bits through the instruction format (the top four bits pick the opcode, the low four are its operand); tag it DATA and the very same bits are just a number. Addresses 0x00 and 0x01 literally hold the identical byte 01001000 — tag them differently and one becomes a STA 8 while the other is the number 72. That is the stored-program idea: a cell is a command only because the machine chose to fetch it as one. Nothing in the silicon marks the difference — the roles live in how the bytes are read, not in the bytes.

To work through a list in order, you need a finger on your place. Without one, the machine finishes line 4 and has no idea that line 5 is next. So we add exactly that: a small register whose only job is to hold the address of the instruction we're on. It's called the program counter, or PC for short. It's nothing more exotic than a register wired to point into RAM. Watch it aim at a row.

PROGRAM COUNTER 0 = address of line 0 points at → RAM — every line lives at an ADDRESS
tip: click any line to aim the PC straight at it
PC = 0 — the finger rests on line 0: LDI 5
Fig 3. The program counter is one small register holding a single number: the address of the line the machine is about to run — a finger keeping your place in the list. Each fetch bumps it by one, so the finger walks down the program; a JMP is nothing but writing a new address into it, and the finger leaps. Click a line to aim it, or hit Run and watch the loop.

A finger that only ever points at line 0 is useless, though. The PC has to move. After fetching the instruction at address 3, it must become 4, then 5, then 6, marching forward one step at a time. And "add one to a register, over and over" is a machine you already built. Back then, we fed a register's own value plus one back into its input on every clock edge. That's a binary counter. Let it run.

CLK HI LO latch every up-flick loads the next value — the level in between does nothing 8 4 2 1 0 0 0 0 Q3 Q2 Q1 Q0 the accumulator register Q + 1 D next count, wired back in it reads, in decimal 0 0000 clock edges ticked 0 no hand touched a switch
speed
press the clock — one edge, one step up
This is a register plus a wire that adds one, looped back on itself. Ticked, it climbs 0, 1, 2, 3… forever — the seed of the program counter that walks a CPU through its instructions.
Fig 4. The binary counter. Tie a register's own value, plus one, back into its input, and every rising clock edge latches the next number. Pulse it by hand or let it auto-run: it climbs 0, 1, 2, 3… with no switch touched — and notice that holding the line high counts only once. That up-flick, repeated, is exactly how a CPU's program counter steps from one instruction to the next.

The plan never lets us wave at a magic "+1 block," so let's open the increment up and see the arithmetic actually happen. Adding one to a binary number is the simplest possible add. Flip the lowest bit. If it was a 1, it rolls over to 0 and hands a carry up to the next bit — exactly the roll-over you saw an odometer do. Step a single increment and watch the carry ripple left through the wires.

Now the itch, before it turns into a nag. This machine already has an adder — the ALU you built chapters ago. So why does the PC get a second one? Look at what the ALU is actually wired to: register A and register B. A is where the program's running total lives. To borrow the ALU for a +1, you'd have to drop the PC's address into A, flattening the total the program is halfway through computing, then add one, then put the address back, then somehow restore the total you just wrecked. And you'd pay that on every single fetch, because every instruction fetches. A handful of gates dedicated to +1 is cheaper than all that traffic. Better than cheap: the PC steps forward on its own, without disturbing a single bit the program cares about. Real CPUs make exactly this trade.

0 0 1 1 = 3 the register, read as a binary number b3 b2 b1 b0 0 0 1 1 8 4 2 1 place value of each column +1 a carry into b0 ← the carry rides left, column by column 1 1 falls off each bit is a half-adder — there is no +1 block newbit = bit XOR carry · carry-out = bit AND carry
ready · value 3 (0011)
One click drops a carry into b0. Each bit does the same tiny job: flip if the carry reaches it, and pass the carry on only if it was already 1. The ripple dies at the first 0. Click a bit to set your own start number.
Fig 5. A +1 is not one indivisible move — it is a carry dropped into the lowest bit that ripples left. Each column runs the same two-gate rule: the new bit is bit XOR carry, and the carry passed on is bit AND carry — so a 1 flips to 0 and hands the carry along, while the first 0 it reaches flips to 1 and swallows the carry, ending the ripple. Step it by hand, or watch it run; set your own start with a click to see how far the carry has to travel.

So the PC is a real, honest circuit: a register plus an increment that ripples carries, latching the next address on each tick. Nothing borrowed, nothing assumed. Now we have the finger, and we have the "move to the next line." Time to use them.

02The fetch: pulling the next command

Here is the heartbeat of every computer ever made, drawn as a loop. The PC points at a cell, and fetch pulls that cell's byte into the IR. The PC advances to the next cell. The machine executes the instruction it just fetched. And then — this is the part that makes it a computer — it goes straight back to fetch and does it all again, forever, with no one watching. Trace the arrows.

PROGRAM · IN MEMORY LDI 40 ADD 31 SUB 12 OUT3 JMP 04 PC 0 ACC 0 OUTPUT IR instructions run: 0 FETCH load next instruction ADVANCE PC point at next address EXECUTE do what it says
ready — click step, or a box, to trace one arrow of the cycle
The processor never stops here. It fetches, bumps the PC to the next address, executes — then loops straight back to fetch, forever, with nobody watching. That single circle is the whole machine.
Fig 6. The fetch–execute loop. Three boxes, one circle: fetch the instruction the program counter points to, advance the PC to the next address, execute what was fetched — then the arrow curves straight back to fetch. Press step to walk a single arrow, or hit run and watch the token race the loop while the tiny program computes and jumps back on itself. Nobody presses a key between ticks; this cycle is the running computer.

Before we break the fetch into ticks, do it yourself. Take ADD. Write down the moves the machine has to make to get that byte out of RAM and into the IR — you have the PC, the MAR, the bus, and last chapter's habit of naming a cell before you read it. Now write the same list for SUB. Now for JMP, an instruction I haven't taught you yet. Write its fetch anyway. Your gut should be objecting right about now: these are wildly different verbs, so surely what you're fetching changes how you fetch it. Look at the three lists you just wrote before you read on.

They're the same list. Not similar. Identical, all three, and you wrote them that way yourself. Now here's why it had to come out like that. Sit at the first tick and ask what the machine actually knows. The instruction is still in RAM. The IR is empty. The opcode — the four bits that would say ADD or JMP or HALT — has not been read yet, because reading it is the job we're in the middle of. So the fetch cannot depend on the opcode. You cannot branch on a byte you haven't looked at. That isn't a design choice anyone made. It's the order of events, and it leaves no room for cleverness. It's why you could write JMP's fetch without knowing what JMP does. And it's the reason the whole thing can close into a loop: if every lap opens with the same two moves, nobody ever has to tell the machine how to start a lap. Let's break that fetch into its actual clock ticks.

CPU PC · program counter 2 +1 tick 0 MAR · address register · · IR · instruction register · · · ADDRESS BUS DATA BUS RAM · memory addr ▸ ◂ data 0 LDI 2 1 ADD 9 2 SUB 9 3 OUT 4 JMP 0
Every instruction begins the same way: two clock beats that pull it out of memory. Step through them and watch which wires light.
clock · armed
tick 0  PC → MAR
tick 1  RAM → IR  &  PC+1 SAME TICK
Armed · PC = 2. Press step to run tick 0.
The wiring never changes — only the values on it. That is why fetch is identical for every instruction in the machine.
Fig 7. The fetch is two clock beats, and it is exactly the same for every instruction the CPU ever runs. On tick 0 the program counter copies its value into the MAR — that is the address we’re about to read. On tick 1 two things happen on the one clock edge: the addressed RAM cell drives its bytes down the data bus into the IR, and the PC ticks up by one so it already points at the next instruction. Step it, then reset and step again — the values on the wires change, the wiring never does.

Two beats, and they're worth naming precisely — in the control lines, because those are the only words the hardware understands. On the first tick, the PC drives its address onto the bus and the MAR latches it. That's two lines high: CO (counter out) and MI (MAR in). Now RAM knows which cell we want. On the second tick, RAM drives that cell's byte onto the bus, the IR latches it — and, in the very same tick, the PC increments. Three lines: RO (RAM out), II (IR in), and CE (counter enable, the increment itself). So the fetch costs exactly two clock cycles. When it's done, the instruction is sitting in the IR and the PC is already aimed at the next line, ready for the round after this one. But hold on. If the PC is changing on the very beat RAM is being read, doesn't the address shift under RAM's feet? That's the right question, and it deserves a real answer rather than a shrug.

So let's answer that, and the answer is already sitting in the machine. Where does RAM's address actually come from? The MAR. Not the PC. The MAR latched that address a full beat ago and has been holding it steady ever since — that is the whole reason the MAR exists, and it's why the fetch needs a first beat at all. The PC could catch fire on the second tick and RAM would never notice. Now the deeper half. Every register here is edge-triggered: it samples what's on its input before the edge arrives, and commits the new value after. So on that second tick the incrementer is looking at the PC's old value, and the new address only exists once the edge has passed. A value cannot reach backwards into the beat that made it. That's not a trick. It's the definition of edge-triggered, straight from the register chapter — the same discipline that lets a bus full of gates march in lockstep. The machine now knows what to do and where it'll go afterward. All that's left is to actually do it.

03The execute: a handful of verbs

With the fetch handled, "executing a program" comes down to a small vocabulary of things an instruction can do once it's in the IR. Our toy speaks just a handful of them. Every one is a short sequence of the same bus moves you already know — enable a source, latch a destination — stacked on top of the two-cycle fetch. Here's the machine's whole instruction set on one card — the five straight-line verbs, plus the two that bend and end the march: the opcode, the mnemonic we call it, and what it does.

OPCODE HEX NAME WHAT IT DOES LDI Load Immediate takes: a number A ← n
WHAT MOVES the number n = A (accumulator)
LDI · Load Immediate
Scan the card top to bottom — hover or arrow-key each row. Seven opcodes is the machine's entire vocabulary; everything a program does is these lines in a row.
Fig 8. The whole machine speaks seven words. Each row pairs an opcode — the 4-bit number the hardware actually sees — with a human mnemonic and its exact effect. LDI drops a number into the accumulator; ADD/SUB pull from memory and do the arithmetic; STA writes A back out; OUT shows it; JMP rewrites the program counter to bend the flow; HALT stops the clock. Hover any row to see what moves where. Flip to plain words if the arrows feel dense. There is no eighth instruction hiding — every program you will ever run is just these lines, stacked.

A note before we run one, because it explains half the table. The arithmetic instructions — ADD and SUB — don't name two operands. They name one. The other is implicit: a scratch register, call it B, that the ALU always uses as its second input. Register A is where the running total lives. B is the value being folded in. Recall the ALU with its two dedicated operand registers hanging off it.

the shared bus (8 bits) A = 170 B = 86 + 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 9. 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.

So ADD 9 means: fetch the number living at address 9 into B, then set A ← A + B. Count what that costs, in beats you've already watched. Two for the fetch: PC→MAR, then RAM→IR with the PC stepping. Then the operand has to name its cell before RAM can be read — beat three: operand→MAR. RAM hands the byte to B: beat four. The ALU folds B into A: beat five. Now go down the card and try to beat that. LDI drops its operand straight into A. One move, done. OUT copies A to the display. One move, done. Neither needs a third execute beat. ADD does — it's the instruction that needs the machine's full allotment of steps. So the budget is five clock cycles: two for the fetch, and up to three for the execute. Not because five is special, but because a lap has to be long enough for the hungriest verb on the card. That's precisely why the budget is five. Step through all five and watch the PC advance during the fetch, then the operand do its work.

PC · program counter 5 MAR · address RAM [5]ADD 9 [6]STA [7]JMP 0 [8]· [9]4 IR · instruction A · accumulator 3 ALU + B · operand
◂ 2 FETCHthe 5-step budget3 EXECUTE ▸
1PC→MAR
2RAM→IR
3op→MAR
4RAM→B
5A+B→A
Ready — PC points at the ADD instruction. Press Step.
One ADD is the instruction that needs all five beats. Two beats just to fetch it, three to execute it. Step through and watch which registers change on each beat.
beat 0 / 5
Fig 10. One ADD, broken into its five smallest moves — and that count is no accident. Every instruction first has to be fetched: PC → MAR, then RAM → IR — two beats, and notice PC quietly advances on that second beat, riding the very same clock edge as RAM → IR, already aimed at the next instruction. It can, because MAR latched the address a beat earlier — RAM is reading MAR, not PC — so the increment costs no beat of its own. Then ADD is executed in three: pull the operand address into MAR, read that cell into B, and let the ALU do A + B → A. Step it beat by beat and watch what each edge writes — one register every time, except the second, where the increment rides along for free. ADD is the instruction that spends the whole budget — which is why the machine's clock is built to give every instruction five ticks.

Five beats: PC→MAR, then RAM→IR with PC++ (the fetch), then operand→MAR, RAM→B, and finally A+B→A (the execute). Now the mirror image. SUB is the same shape — load B, then feed the ALU — but with the ALU told to subtract. Here the earlier chapters pay a quiet dividend: the machine has no subtractor. It computes A − B as A + (−B). It builds −B with the two's-complement invert-and-add-one trick, so the very same adder that does ADD also does SUB. That's also why "0 − 1" lands cleanly on −1 (all ones) instead of breaking. Watch subtraction happen with no subtractor in sight.

the subtraction how −B is made the one adder — identical circuitry for + and − 8-bit adder · dumb column-by-column 1 2 4 8 16 32 64 −128 + A −B
A−B is A+(−B). Watch the negate-then-add flow through the one adder — it never learns it subtracted.
Fig 11. This is the same adder ADD uses — and here it is doing SUB, with no subtractor anywhere in it. Pick any A − B and step it through. The subtraction rewrites itself as A + (−B); −B is built by the two-step reflex — flip the bits, add one; then A and −B pour into the identical eight-bit adder, column by column, carries and all. On 7 − 5 the top carry drops off the end — a full lap around the wheel, worth 0 — and out falls 2. The adder did the same dumb column-add it always does. It never knew it subtracted, and that is why SUB costs this machine no new hardware at all — only a different control line.

Adding and subtracting are pointless if you can't keep the result. STA — store A — is two moves and no new parts. First the IR's operand goes onto the bus and the MAR latches it, naming the cell. Then A pushes its value onto the bus and RAM latches it into that cell. That's it. And if it feels familiar, it should: it's LDA from last chapter, the load we ran to pull a byte out of memory, with the traffic pointed the other way. Same three parts, same two beats, opposite direction. Follow A's value flowing into memory.

executing STA M[0011] ← A REG A 00000110 6 OE·A MAR · address 0011 RAM · a column of cells WE the shared bus — one wire, driven from one end at a time
1 · operand → MAR 2 · A drives the bus 3 · RAM latches it
Address 0011 is aimed. Hit run the store and watch A's value flow out onto the bus and into that cell.
STA and LDA use the exact same three parts — A, the bus, the addressed cell. All that changes is which end drives and which end latches. Store is load run backwards.
Fig 12. STA — store A — is LDA run backwards. Both instructions touch the same three things: register A, the shared bus, and one addressed cell of RAM. Dial A's value and pick an address, then run the store: the operand names the cell (MAR), A drives its value onto the bus, and RAM latches it in — A's number now lives in memory. Flip to LDA and the charge runs the other way down the identical wire: the cell drives, A latches. The only difference between saving a value and loading one is which end pushes and which end listens.

Two more and the set is complete. LDI — load immediate — is the quickest instruction of all. The operand nibble isn't an address to look up. It's the value itself, loaded straight into A with no trip to RAM. "Immediate" means the data is right there in the instruction. It's how you get a starting number into the machine.

the instruction byte opcode: LDI "load immediate" operand nibble = the data click a bit to flip it 0 0 0 1 1 1 0 1 8 4 2 1 RAM memory not read no memory fetch straight through — the operand IS the data register A 13 0000 1101
quick set
A ← 13 — loaded straight from the instruction
LDI carries its data inside itself. No address, no RAM read — the operand nibble drops directly into A. It's how the very first number gets into the machine.
Fig 13. An LDI instruction is one byte cut in two: a opcode nibble that says "load immediate," and an operand nibble that is the number. Flip the operand bits — or drag the dial — and watch the value drop straight into register A. Notice what never happens: no address is formed, RAM is never touched. The data rode in inside the instruction. That's how the very first number gets into a machine that starts with empty registers — you hand it one, immediate.

And OUT — the machine finally showing its work. It copies A into an output register wired to a display. A number the CPU has been shuffling in silence becomes something a human can read. Here's the display itself — the lookup table that turns a number into lit bars.

a b c d e f g the 7-bit code stored for this digit a 1 b 1 c 1 d 1 e 1 f 1 g 0 address 8 → lights up stored word (a…g) 1111110 seven of seven bars lit
digit 8 lights every bar — the whole figure-eight
Nothing here draws a numeral. Each digit is just an entry in a table: a 7-bit word that flips seven bars on or off. Pick another and watch a different subset light.
Fig 14. A seven-segment display never draws a numeral — it selects one. Seven bars (ag) sit there permanently; a stored 7-bit code decides which light and which stay dark. Pick any digit 0–9 and watch its own subset switch on: a 1 in the code lights that bar, a 0 leaves it off. That table — digit in, pattern out — is a lookup table, and burning it into hardware so it never forgets is exactly what a ROM is.

That's the entire straight-line vocabulary: load a constant, add, subtract, store, show. Feed the machine a column of these and it will march down them — fetch, execute, fetch, execute — computing as it goes. But "march down them" is exactly the problem. A straight run only goes one way: down. Off the bottom of memory and into gibberish. To write a real program, the machine has to be able to break the march.

04Bending the march: JMP and HALT

Everything so far assumes the PC only ever does one thing: count up by one. But the PC is a register, and a register can be written to. Before you read on, answer this. Every register in this machine loads from the bus the instant its load-enable goes high. Nobody ever said the PC was different. So what happens if a byte lands in the PC by the same route a byte lands in A? What if an instruction, instead of touching A or RAM, reached over and wrote a brand-new address straight into the PC? Then the next fetch wouldn't grab the following line. It would grab whatever line that address names. That's a jump. Now lay it beside its twin, in the lines. STA: A talks (AO), RAM listens (RI). JMP: the IR's operand talks (IO), the PC listens (J). One out-enable, one load-enable, both times. The only difference is which load-enable went high. Control flow isn't a new power. It's a store with a different destination. Watch the operand overwrite the PC.

MEMORY operand → PC PROGRAM COUNTER 0 PC + 1 every fetch bumps by one … unless a JMP overwrites it 0
PC = 0 · press Step to fetch & execute one instruction
A JMP is just a store whose destination is the PC. An ordinary op lets the +1 incrementer nudge the counter along; JMP N writes N straight in — so the next fetch reads from N. Addresses 4–5 never run: the jumps leap right over them.
Fig 15. The program counter is just a register — and the fetch–execute loop keeps it moving. For an ordinary instruction the +1 incrementer nudges it to the next address, so execution walks straight down memory. A JMP does something almost boring in hardware: it is a store whose destination happens to be the PC. The operand is written straight in, overwriting the count — so the very next fetch reads from there, and control teleports. Step it and watch 3→6 and 7→1 leap over addresses 4 and 5, which never run at all. Loops, branches, function calls — every one of them is nothing but a carefully aimed store into the program counter.

So JMP 3 means "put 3 into the PC," and the very next fetch pulls the instruction at address 3. The machine has teleported. Put a JMP at the bottom of a block, pointing back to the top, and you get something the straight run could never do: a loop that runs the same instructions over and over. Here's the PC counting along on its own, wrapping 1111 back to 0000 when it runs off the end — and a JMP button that slams it to any address you choose, mid-stride.

PROGRAM COUNTER · 4-bit CLK 0 0 0 0 8 4 2 1 0 address (decimal) each tick: PC ← PC + 1, and 1111 rolls over to 0000 wrap: 15 → 0 PC
jump to10
parked at 0  ·  0000
Run the counter and watch it march 0→15 then wrap. Then slam JMP mid-stride — the count carries on from wherever you land. That overwrite is the seed of every loop.
Fig 16. A 4-bit Program Counter — the register that holds which instruction is next. Four bits is not an accident: 0000 through 1111 names exactly 16 addresses, and 16 cells is all the RAM this machine has. The counter can point at every cell, and at nothing that isn't there. Press Run and it marches: on every clock tick PC ← PC + 1, the marker stepping 0→1→2 up the address track. Reach 1111 (15) and the next tick doesn't hit 16 — there is no fifth bit to carry into, so the count wraps to 0000. That wrap is not a feature and it is not how programs repeat; it is simply what any fixed-width counter does when it runs out of bits, and a program that ever reaches it has run off the end of its own code. Now the twist: hit JMP and you overwrite the counter live — slam it to any address mid-stride, and the march carries on from there. That write into the PC is the one thing the straight march lacks, and it is the whole trick behind repetition: point the PC back at an address it has already run, and the machine runs those instructions again. That is a loop.

That single power — write the PC — is what turns a to-do list into a program with structure. But a loop that JMPs back forever now has the opposite problem: it never stops. We need a way to say "we're done." Recall the clock — the tireless square wave that drives every tick of every fetch. We're not taking it on faith any more. We built the real thing last chapter: a ring of inverters wired output back to input, a loop that can't settle, chasing its own tail forever. Out comes the square wave. That's what we're about to go after.

1 0 now one beat = one full high-then-low cycle · scrolling left, oldest at the edge 1 beats counted 1 clock now
ticking — half high, half low, forever
This is the square wave last chapter's ring oscillator produces — a steady, evenly-timed drumbeat for the whole machine.
Fig 17. The whole machine marches to one drumbeat: a clock — a steady square wave that sits high for half the beat and low for the other half, over and over, at a perfectly even tempo. Hit running and watch it scroll past the now line; each rising edge is a tick, and the counter climbs one per full cycle. Drag speed to change the tempo — the shape never does. The oscillator that actually makes this beat — the ring of inverters — is the one we built last chapter.

If the loop only runs while the clock is ticking, then stopping the machine is as blunt as it sounds: stop the clock. HALT does exactly that. It drops a "run" line that's ANDed with the clock. The ticks stop reaching the registers, and the whole machine freezes right where it is, mid-address, holding its last state. No dramatic shutdown. The beat just stops. Flip the run line and watch the ticks die.

CLOCK free-running CLK RUN LINE 1 RUN AND REGISTERS 0 program counter advance clock (never stops) to regs clk AND run — ticks starved — now
ticks delivered to the registers: 0
RUNNING — every tick reaches the registers
The clock never stops — flip HALT and it keeps oscillating on the left, but the AND gate holds its output low, so nothing crosses to the counter and the machine freezes in place.
Fig 18. A processor's clock never rests — it oscillates on the left whether the machine runs or not. The trick of HALT is to drop the RUN line and feed it, alongside the clock, into an AND gate: the gate only passes a tick when both inputs are high. Leave RUN at 1 and the clock sails through to the program counter, which advances on every rising edge. Flip it to 0 and watch the ticks die at the gate — the clock keeps beating, but its output pins low, no edges reach the registers, and the machine freezes exactly where it stood. Nothing is destroyed; the state is simply held, waiting for the run line to lift again.

With JMP to bend the march and HALT to end it, the instruction set is finally expressive enough to run a real, finite program from start to a deliberate stop.

05The loop, running on its own

Let's watch the whole thing turn with no hand on the controls. Here is a tiny program in Python's clothing — an interpreter for our straight-line instruction set. It runs a short routine: load a number, add another, show the result, and halt. It fetches, advances the PC, executes, and repeats, exactly as the silicon would, and the trace beside it shows every beat as it lands.

MEMORY · 16 CELLS 0 LDI 2 1 ADD 9 2 OUT 3 HALT 4–8 · empty 9 3 ← data, not an order 4-bit address → 16 cells 8-bit words ↺ repeat FETCH ir = mem[mar] · pc++ 5 BEATS · 2 FETCH + 3 EXEC 1 2 3 4 5 EXECUTE run(op, n) MACHINE STATE PC 4 bit 0 MAR 4 bit IR 8 bit A 8 bit 0 B 8 bit OUT ·
ready — press Step phase to move one half of the cycle, or Run to let it go.
THE INTERPRETER · PYTHON
pc = 0
while True:
    mar = pc                 # beat 1: PC→MAR
    ir = mem[mar]            # beat 2: RAM→IR …
    pc = (pc + 1) & 0xF      # … and PC++, same edge
    op, n = ir >> 4, ir & 15  # 4-bit op, 4-bit operand
    run(op, n)               # beats 3-5 (A stays 8-bit: & 255)
    if op == HALT:
        break
STEP TRACE
no steps yet — run the loop
idle · PC at 0 · nothing has run yet
Nobody is pushing this along by hand. Once it starts, the same two moves — fetch (two beats, the PC increment riding the second) and execute (up to three) — repeat until the program hands it a HALT. That's a computer, in about nine lines.
Fig 19. No hand on the crank. Here is the fetch–execute loop written as nine lines of Python — and beside it, the machine those nine lines describe, turning the same wheel forever: FETCH the instruction PC points at — two beats, with the PC increment riding the second one — then EXECUTE it in up to three. Hit Run and watch it turn, beat for beat: LDI 2 drops the operand nibble straight into the accumulator A; ADD 9 names one operand and that operand is an address — so cell 9 is read into B and the ALU folds them into 5; OUT copies A to the tape; HALT stops the machine itself. Watch the budget strip: ADD is the only one here that spends all three execute beats — the rest idle through the same five ticks. Read the step trace line by line — that column of fetch → execute is the whole of what a processor does, and it's the same loop whether it runs four instructions or five billion a second.

Read the trace and you're reading the machine's inner monologue: I'm at line 0, the instruction there is LDI 2, do it, now I'm at line 1… That's the fetch–execute loop, spinning by itself. That is a computer. Not a metaphor for one, not "like" one — the real thing, in miniature: a program counter walking through RAM, a fetch that never varies, a handful of verbs, and a jump that lets it double back.

That's Chapter 13. The machine runs a program with one tireless cycle. The program counter points at a cell, and fetch pulls it into the IR. The PC advances (a real binary counter, carries and all). And the instruction executes in up to three more bus moves — a fixed five-tick lap, sized for the hungriest verb on the card. We built the straight-line verbs — LDI, ADD, SUB, STA, OUT. We saw JMP reveal itself as nothing but a store aimed at the PC. And we stopped the whole thing dead with HALT by starving the clock. But sit with what this loop still can't do. It marches, and with JMP it can loop forever — but it cannot choose. Every JMP is unconditional: it always jumps, no matter what. A real program needs to loop while a counter is nonzero, to stop when a total is reached, to branch on what it just computed. For that, the machine has to look at its own last answer and decide. It needs flags — and that's next.

iolinked.com
Written by Ajai Raj