The fetch–decode–execute cycle

A processor does one thing, billions of times a second: the instruction cycle.

  1. Fetch: read the instruction at the address in the PC (program counter) into the IR (instruction register), and add one to the PC.
  2. Decode: the control unit works out what the instruction means: which operation, and which registers or memory addresses.
  3. Execute: the ALU computes, or memory is read or written. A jump instruction puts a new address into the PC.

Then back to fetch. A HALT instruction stops the cycle (a real processor never stops: it runs the operating system's idle loop instead).

Two more registers sit between the CPU and memory: the MAR (memory address register) holds the address to read or write, and the MDR (memory data register) holds the value.

A tiny accumulator machine

Early computers, and many teaching machines, have one main register, the accumulator (ACC), which every arithmetic instruction uses. Here is one, with seven instructions:

InstructionMeaning
LOADI vACC = v
LOAD aACC = memory[a]
ADD a / SUB aACC = ACC ± memory[a]
STORE amemory[a] = ACC
JZ aif ACC is 0, jump: PC = a
JMP aPC = a
HALTstop

This program adds 10 + 20 + 30:

memory = {10: 10, 11: 20, 12: 30, 13: 0}
program = [("LOAD", 10), ("ADD", 11), ("ADD", 12), ("STORE", 13), ("HALT", 0)]

pc, acc = 0, 0
while True:
    op, arg = program[pc]          # fetch
    pc += 1
    if op == "LOAD":               # decode and execute
        acc = memory[arg]
    elif op == "ADD":
        acc += memory[arg]
    elif op == "STORE":
        memory[arg] = acc
    elif op == "HALT":
        break
    print(op, arg, "-> ACC =", acc)
print("memory[13] =", memory[13])
Open in compiler

And this one counts down from 3 with a loop, using JZ to leave it:

memory = {20: 3, 21: 1}
program = [("LOAD", 20), ("JZ", 5), ("SUB", 21), ("STORE", 20), ("JMP", 0), ("HALT", 0)]

pc, acc, steps = 0, 0, 0
while True:
    op, arg = program[pc]
    pc += 1
    steps += 1
    if op == "LOAD":
        acc = memory[arg]
        print("counter is", acc)
    elif op == "SUB":
        acc -= memory[arg]
    elif op == "STORE":
        memory[arg] = acc
    elif op == "JZ" and acc == 0:
        pc = arg
    elif op == "JMP":
        pc = arg
    elif op == "HALT":
        break
print("instructions run:", steps)
Open in compiler

Every program you write, in any language, ends up as instructions like these: a compiler turns total = a + b into a load, an add and a store.

Common mistakes

  • Forgetting that the PC is incremented during the fetch: a jump then overwrites the already-incremented value.
  • Mixing up the IR (holds the instruction) and the PC (holds its address).
  • Thinking "execute" always uses the ALU: loads, stores and jumps use memory or just the PC.

Quick check

1. What happens to the PC during the fetch step?
2. Which register holds the instruction being decoded?
3. ACC is 0 and the instruction is JZ 7. What is the next instruction fetched?
4. What does the MAR hold?

Practice problems for this lesson

My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.