The whole machine on one page
By now you have met every part separately. The datapath is the network of roads — the program counter that points at the next instruction, the instruction memory it reads from, the register file that holds the working values, the ALU that does the math, the data memory for loads and stores, the sign-extender that stretches a small immediate to full width, and the multiplexers that pick which road a value takes. The control unit is the traffic controller: it reads the opcode and sets every signal that steers data through those roads. This last guide does only one thing — it watches the whole machine work, by tracing two real instructions, one slow step at a time.
We will use a tiny RISC-V style program for the trace. The point of choosing a load and a branch is that they exercise opposite corners of the machine: the load is the longest path any instruction takes (it touches the register file, the ALU, and data memory before writing back), while the branch is the trickiest, because it changes which instruction comes next instead of writing a register. Between them they touch nearly every component, so following them is the closest thing to a full tour of the single-cycle processor.
# x10 holds a base address; x11 is a loop counter
lw x5, 8(x10) # LOAD: x5 = Memory[x10 + 8]
beq x5, x0, done # BRANCH: if x5 == 0, jump to 'done'
...
done:
...
We trace lw first, then beq. Watch the control signals
change between the two even though the datapath is the same.Tracing the load, signal by signal
Recall that lw x5, 8(x10) means: take the address in register x10, add the immediate 8, read the word at that memory address, and store it into x5. This is load execution, and it is the instruction that decides the clock period of the whole single-cycle machine, because its path is the longest. Watch how the data flows from left to right and how each control signal opens exactly the right gate at exactly the right moment within the single cycle.
- Fetch. The program counter feeds the instruction memory, which returns the 32 bits of lw. The same cycle, an adder computes PC + 4 — the default next instruction — and holds it ready.
- Decode and read registers. The control unit reads the opcode and recognizes a load: it sets RegWrite = 1 (we will write a register), MemRead = 1, ALUSrc = 1 (the ALU's second input comes from the immediate, not a register), and MemtoReg = 1 (the value written back comes from memory, not the ALU). Meanwhile the register file reads x10 onto its first read port.
- Sign-extend and compute the address. The sign-extender stretches the immediate 8 to full width. The ALUSrc mux picks that immediate, so the ALU adds x10 + 8 to form the memory address. The same adder hardware that does arithmetic instructions is reused here just to compute an address.
- Access data memory. The computed address goes to the data memory; with MemRead = 1, it returns the word stored there. This memory read is the slow part — it is why the load defines the cycle time.
- Write back. The MemtoReg mux selects the value from memory (not the ALU output), and because RegWrite = 1, that value is latched into x5 at the rising clock edge. At the very same edge, the PC updates to PC + 4. The instruction is done.
Tracing the branch, and the question it asks
Now beq x5, x0, done — branch if equal. It means: compare x5 with x0 (which is always zero), and if they are equal, make the next instruction be the one at label 'done' instead of the next line. This is branch execution, and its job is fundamentally different from the load's: a load produces a value to store, while a branch produces a decision about where to go next. The same datapath serves both, but the control unit flips a different set of switches.
- Fetch the same way: PC reads beq from instruction memory, and PC + 4 is computed in parallel as the fall-through (not-taken) target.
- Control decodes a branch: RegWrite = 0 (a branch writes no register), MemRead = MemWrite = 0 (it never touches data memory), ALUSrc = 0 (both ALU inputs are registers), and Branch = 1 (this instruction is allowed to redirect the PC).
- The register file reads x5 and x0. The ALU is told to subtract: x5 - x0. We do not want the difference; we only want its Zero flag. If x5 equals x0, the result is zero and the ALU raises Zero = 1.
- A separate adder computes the branch target: PC + (sign-extended offset to 'done'). Now a small piece of logic forms 'take the branch?' = Branch AND Zero. A mux uses that single bit to choose the next PC: the branch target if taken, or PC + 4 if not.
Look closely at step 3: the branch reuses the very same ALU, doing a subtraction only to learn whether two numbers are equal. We do not even keep the result — we throw away the difference and keep one flag bit. This is the kind of frugal reuse that makes a datapath elegant: one adder/subtractor serves arithmetic, address calculation, and equality tests alike, just by changing the ALU control lines. And the right-hand half of the machine — data memory, the write-back mux — sits completely idle this cycle, because a branch has nothing to store and nothing to write back.
Where the single cycle starts to hurt
Put the two traces side by side and a problem jumps out. The branch finished without ever touching data memory — its real work was over halfway through the cycle. But the clock period of a single-cycle machine must be long enough for the slowest instruction, which is the load, with its full register-read, ALU, memory-read, write-back chain. So every fast instruction is forced to wait out the long cycle the load demands. This is the single-cycle limitation: the clock is paced by the worst case, so a quick branch or a quick add wastes most of its cycle standing still.
There is a second, sharper version of the same waste. Because every instruction is one cycle, the CPI is a perfect 1 — which sounds wonderful — but that cycle is so long that the iron law (run time = instruction count x CPI x cycle time) still loses overall. A great CPI bought with a terrible cycle time is no bargain. Worse, you cannot reuse a hardware unit twice in one cycle, so a single-cycle design needs separate instruction and data memories and separate adders, paying in silicon for the privilege of doing everything at once.
The cure is the multi-cycle datapath. Instead of one stretched cycle, chop each instruction into several short cycles — fetch, decode, execute, memory, write-back — and let a short clock tick once per step. Now a branch that needs only three steps finishes in three short cycles, while the load takes five; nobody waits for the load any more. And because the steps happen at different times, a single ALU and a single memory can be reused across steps of the same instruction, saving hardware. CPI rises above 1, but the cycle time falls dramatically, and the iron law comes out ahead.
Microprogrammed vs hardwired — the seam to the pipeline
Once an instruction takes several cycles, the control unit has a harder job: it must now produce a different set of signals on each step, in the right order. There are two honest ways to build that sequencer. Hardwired control bakes the logic directly into gates and a small finite state machine — fast and compact, but rewiring it for a new instruction means redesigning circuits. Microprogramming instead stores the control signals as tiny 'micro-instructions' in a small on-chip memory, and the controller simply reads them out one per step, like a recipe card per cycle. It is slower but wonderfully flexible: change the recipe, not the wiring, to add or fix an instruction.
And this is exactly the seam onto the next rung. The multi-cycle machine already broke each instruction into fetch / decode / execute / memory / write-back stages. The very next, almost irresistible idea is: while one instruction is in its memory stage, why not have the next instruction already in its execute stage, and the one after that in decode — like a laundry assembly line washing, drying, and folding different loads at once? That is pipelining, and it turns the stages we just traced into an overlapping stream. The single-cycle trace you just walked is the foundation; the pipeline is where this machine finally learns to do many things at once. Hold on to the two clean instructions you traced here — every hazard and forwarding trick in the next rung is just those same stages, racing.