How a Program Actually Runs
A CPU runs a program by repeating one simple loop, billions of times a second: the fetch–decode–execute cycle (the instruction cycle).
- Fetch. The CPU reads the next instruction from memory. A special register, the program counter (PC), holds the address of that instruction. The instruction is copied into the instruction register (IR), and the PC advances to point at the following instruction.
- Decode. The control unit interprets the bits in the IR to determine what operation is requested and which operands it needs.
- Execute. The CPU carries out the operation — the ALU computes, or a value is moved to or from memory or a register.
Then the loop repeats. Because the PC advances automatically, instructions normally run in sequence. A jump or branch instruction changes the game: it writes a new address into the PC, so the next fetch happens somewhere else. This is exactly how loops, conditionals, and function calls are built — by controlling what the PC holds.
| Step | What happens | Key register |
|---|---|---|
| Fetch | Read instruction at PC; advance PC | Program counter (PC) |
| Decode | Interpret the operation and operands | Instruction register (IR) |
| Execute | Perform the operation | ALU / registers / memory |
Common pitfall: thinking a branch or jump "skips" the cycle or works by magic. It does not — it simply writes a different address into the program counter. Every instruction, branches included, goes through fetch–decode–execute; a branch's whole effect is changing where the next fetch looks.
A three-box loop labelled Fetch, Decode, Execute with an accent token circulating through them, and a side program-counter that increments each pass — then a branch beat rewrites the PC and the token resumes from a.
Following a Real Instruction
RISC-V is a modern, openly published instruction set, and it is small enough to trace by hand. Take a single instruction, add x5, x6, x7: add the contents of registers x6 and x7 and put the result in x5. RISC-V has 32 integer registers named x0 to x31, and every instruction is exactly 32 bits — four bytes — wide.
Suppose the program counter holds address 200 and that instruction sits there. One turn of the cycle goes:
- Fetch — the address in the PC is sent to memory, and the four-byte word at 200 comes back into the instruction register. The PC is advanced to 204.
- Decode — the control unit splits the word into its fields, reads the operation as "add two registers", and identifies x6 and x7 as the sources and x5 as the destination. The register file is read, placing both operand values on the ALU's inputs.
- Execute — the ALU adds them.
- Write back — the sum is written into x5.
Notice when the PC was advanced: during fetch, before the instruction had even been decoded. That is deliberate. For the overwhelming majority of instructions the next one is simply the next in memory, so the hardware assumes it and gets on with the work. A branch or jump that turns out to be taken corrects the PC later in the same cycle, overwriting the assumption.
Common pitfall: picturing the PC as being incremented at the end of the cycle, once the instruction is understood. It is advanced during fetch, on the assumption of sequential flow. Control-flow instructions do not "set the PC instead" — they overwrite a value that has already been set.