The fetch decode execute cycle explained
What a processor does with one instruction: the program counter, the MAR, MDR, CIR and accumulator, the three buses, and what a clock speed really buys you. Three demos run a tiny processor written in Python that drives the robot and prints its registers at every step.
A processor does one small thing at a time. It reads an instruction out of memory, works out what it means, carries it out, and then goes back for the next one. That loop is the fetch decode execute cycle, and a phone processor runs it a few billion times a second. Nothing else in the machine is going on: every program you have ever used is this loop, over and over.
This page builds a tiny processor out of Python and lets it drive a robot. The program it runs is a list of made-up instructions in a list called memory, and every register is a variable you can watch. Each demo is real: change the numbers, press Run, and read the registers as they change.
A program is a list in memory
Main memory is a long row of numbered boxes. The number of a box is its address, and each box holds one value. A value might be an instruction or it might be data, and nothing about the box says which. That idea, instructions and data sharing the same memory, is the stored program or von Neumann design, and it is why a computer can run any program rather than one built into its wiring.
The processor on this page has nine instructions:
| Instruction | What it does |
|---|---|
SENSE |
put the distance ahead, in cm, into the accumulator |
DRIVE n |
motors forwards at n percent |
TURN n |
turn on the spot at n percent |
WAIT n |
wait n tenths of a second |
SUB n |
take n away from the accumulator |
JN a |
jump to address a if the accumulator is negative |
JMP a |
jump to address a |
STOP |
motors off |
HALT |
stop the cycle |
The word at the front is the opcode: which operation to do. The number after it is the operand: what to do it to. In this memory each instruction is text, so that you can read it. In real memory it is a number, with some bits for the opcode and the rest for the operand.
The registers
A register is a store inside the processor that holds one value. There are only a few, they are far faster than memory, and each has a job:
| Register | Holds |
|---|---|
| PC, the program counter | the address of the next instruction |
| MAR, the memory address register | the address being read from or written to |
| MDR, the memory data register | the value that came back, or is about to go out |
| CIR, the current instruction register | the instruction being carried out now |
| ACC, the accumulator | the result of the last calculation |
A real processor also has a set of general purpose registers for working values, and a status register of flags. The five above are the ones exam questions ask about.
The buses
The processor and memory are joined by three bundles of wires, called buses:
- the address bus carries an address from the processor to memory, and only goes that way;
- the data bus carries instructions and data, in both directions;
- the control bus carries the signals that say what is happening, such as read, write and the clock tick.
How wide each bus is matters. An address bus of 32 wires can name 232 different addresses, which is 4 GB of bytes, and that is why 32-bit machines could not use more memory than that. A wider data bus moves more bits per trip.
One instruction, step by step
Fetch is four moves, always in this order:
- The address in the PC is copied into the MAR.
- Memory sends back what is at that address, along the data bus, into the MDR.
- The PC goes up by one, ready for next time.
- The instruction is copied from the MDR into the CIR.
Decode: the control unit splits the instruction in the CIR into its opcode and its operand, and works out which signals to send.
Execute: the instruction happens. Arithmetic is done by the ALU, the arithmetic logic unit, and its answer goes to the accumulator. A jump writes a new address into the PC. On this robot, DRIVE sets the motors.
Then back to fetch. Here is the whole cycle, with every fetch and every execute printed as it happens.
The program
from bugbot import *
connect()
# the program, one instruction at each address
memory = ["SENSE", # 0: put the distance ahead into the accumulator
"DRIVE 60", # 1: motors forward at 60
"WAIT 8", # 2: wait 8 tenths of a second
"TURN 50", # 3: turn on the spot at 50
"WAIT 4", # 4: wait 4 tenths
"STOP", # 5: motors off
"SENSE", # 6: measure again
"HALT"] # 7: end of the program
pc = 0 # program counter: the address of the next instruction
mar = 0 # memory address register: the address being read
mdr = "" # memory data register: what came back
cir = "" # current instruction register: the instruction being run
acc = 0 # accumulator: the last result
running = True
while running:
# fetch
mar = pc # 1: the address goes to the MAR
mdr = memory[mar] # 2: memory sends it back to the MDR
pc = pc + 1 # 3: the PC moves on
cir = mdr # 4: the instruction goes to the CIR
print("fetch PC=" + str(pc), "MAR=" + str(mar), "MDR=" + mdr)
# decode
parts = cir.split()
opcode = parts[0]
operand = int(parts[1]) if len(parts) > 1 else 0
# execute
if opcode == "SENSE":
acc = round(distance())
elif opcode == "DRIVE":
drive(operand, 0)
elif opcode == "TURN":
drive(0, 0, operand)
elif opcode == "WAIT":
wait(operand / 10)
elif opcode == "STOP":
stop()
elif opcode == "HALT":
running = False
print("execute CIR=" + cir, "ACC=" + str(acc))
plot("PC", pc)
plot("ACC", acc)
Read the printout as the processor's diary. Two things are worth noticing.
The first is that the PC is always one ahead of the instruction being run. Look at the first line: PC=1 MAR=0. The instruction from address 0 has only just arrived, and the PC already points at 1. That is because step 3 of the fetch happens before the instruction is even decoded. Exam questions like this one.
The second is that the MAR and the MDR are the only way out of the processor. The MAR is what goes on the address bus and the MDR is what comes back on the data bus, every single time.
The program counter is what makes a loop
Nothing so far could repeat. A processor loops by writing a new address into the PC: that is all a jump is, and it is all a loop, an if, a function call and a while are underneath.
This program drives the robot at the wall and stops 25 cm short. Address 4 holds JMP 0, which sends the PC back to the start, and address 2 holds JN 5, which jumps to the STOP only when the accumulator has gone negative.
The program
from bugbot import *
connect()
# change this and press Run
STOP_AT = 25 # stop this far from the wall, in cm
memory = ["SENSE", # 0: ACC = the distance ahead
"SUB " + str(STOP_AT), # 1: take the stopping distance off it
"JN 5", # 2: if the ACC is negative, jump to 5
"DRIVE 40", # 3: motors forward
"JMP 0", # 4: back to the start
"STOP", # 5: motors off
"HALT"] # 6: end of the program
pc = mar = acc = 0
mdr = cir = ""
cycles = 0
running = True
while running:
mar = pc # fetch
mdr = memory[mar]
pc = pc + 1
cir = mdr
parts = cir.split() # decode
opcode = parts[0]
operand = int(parts[1]) if len(parts) > 1 else 0
if opcode == "SENSE": # execute
acc = round(distance())
elif opcode == "SUB":
acc = acc - operand
elif opcode == "JN":
if acc < 0:
pc = operand # the jump writes straight to the PC
elif opcode == "JMP":
pc = operand
elif opcode == "DRIVE":
drive(operand, 0)
elif opcode == "STOP":
stop()
elif opcode == "HALT":
running = False
cycles = cycles + 1
plot("PC", pc)
plot("ACC", acc)
print(cycles, "CIR=" + cir.ljust(8), "ACC=" + str(acc).rjust(3), "PC=" + str(pc))
wait(0.1)
print(cycles, "cycles, and the robot stopped", round(distance()), "cm from the wall")
The robot asked to stop at 25 cm and came to rest at 20, because it keeps sliding after the motors are told to stop. Change STOP_AT to 40 and the whole program changes, because the constant is written into the instruction at address 1 before the processor ever sees it. That is what an assembler does with the numbers in a real program.
The five instructions in the loop are worth counting: SENSE, SUB, JN, DRIVE, JMP. Every trip round costs five cycles, and only one of them moves the robot. Real programs are the same shape: most of the work is fetching, deciding and jumping.
What a clock speed means
A clock is a signal that flips between 0 and 1 at a steady rate, and every step of the cycle waits for a tick. The clock speed is how many ticks there are each second, measured in hertz. One gigahertz (GHz) is a thousand million ticks a second.
Clock speed is not the same as instructions a second. On a real processor a simple instruction takes a few ticks and a complicated one takes many, and modern processors overlap instructions (pipelining) so that several are part-done at once. On the processor on this page, one instruction takes exactly one tick, which makes the arithmetic easy to see.
A faster clock matters here for a reason you can watch: the robot only looks where it is going once per trip round the loop. At 2 instructions a second, a trip round the five-instruction loop takes 2.5 seconds, and the robot travels about 20 cm blind between looks.
The program
from bugbot import *
connect()
# change these and press Run
SLOW = 2 # the first clock, in instructions per second
FAST = 20 # the second clock
STOP_AT = 25 # stop this far from the wall, in cm
memory = ["SENSE", "SUB " + str(STOP_AT), "JN 5", "DRIVE 40", "JMP 0", "STOP", "HALT"]
done = 0 # instructions carried out so far
def run(hz):
global done
pc = acc = 0
running = True
while running:
mar = pc # fetch
mdr = memory[mar]
pc = pc + 1
cir = mdr
parts = cir.split() # decode
opcode = parts[0]
operand = int(parts[1]) if len(parts) > 1 else 0
if opcode == "SENSE": # execute
acc = round(distance())
elif opcode == "SUB":
acc = acc - operand
elif opcode == "JN":
if acc < 0:
pc = operand
elif opcode == "JMP":
pc = operand
elif opcode == "DRIVE":
drive(operand, 0)
elif opcode == "STOP":
stop()
elif opcode == "HALT":
running = False
done = done + 1
plot("instructions done", done)
plot("gap, cm", round(distance() - STOP_AT))
wait(1 / hz)
run(SLOW)
print("at", SLOW, "instructions a second it stopped", round(distance()),
"cm from the wall, after", done, "instructions")
first = done
drive(-60, 0) # back to where it started
wait(5)
stop()
run(FAST)
print("at", FAST, "instructions a second it stopped", round(distance()),
"cm from the wall, after", done - first, "instructions")
The "instructions done" line is the clock speed drawn as a picture. Its gradient is instructions a second: shallow in the first run, ten times steeper in the second. The "gap, cm" line is how far the robot still was from its stopping point, and at the slow clock it goes a long way past zero before anything happens.
That is the real answer to why clock speed matters. A faster clock means more trips round the loop each second, so the machine reacts sooner and gets more done. It is also why clock speed alone does not decide how fast a computer feels:
- more cores run more than one cycle at once, but only help a job that can be split up;
- cache, a small fast memory inside the processor, saves waiting for main memory;
- pipelining starts fetching the next instruction while the last one is still executing;
- a faster clock makes more heat, which is why processors slow themselves down when they get hot.
Instructions are numbers too
Memory holds only bits, so a real instruction is a number. Split a byte into a 4-bit opcode and a 4-bit operand and you get sixteen possible instructions and sixteen addresses. DRIVE 6 might be opcode 0010 and operand 0110, stored as 00100110. The control unit decodes those first four bits to decide what to do.
Numbers that can be negative are held in the same bits by a rule of their own, which the two's complement guide explains. That is how SUB can leave -2 in the accumulator and JN can test it.
Mistakes that lose marks
- Putting the PC increment last. The PC goes up during the fetch, before the instruction is decoded. Say so.
- Mixing up the MAR and the MDR. Addresses go out in the MAR, values come back in the MDR.
- Forgetting the CIR. The instruction moves from the MDR to the CIR, so that the MDR is free for the data the instruction needs.
- Saying the address bus is two way. It is one way, processor to memory. The data bus is the two-way one.
- Saying a 3 GHz processor runs 3 billion instructions a second. It has 3 billion clock ticks a second, and most instructions take more than one.
- Naming the wrong part for the job. The control unit decodes and sends signals, the ALU does arithmetic and logic, the registers hold single values.
- Forgetting that a jump writes to the PC. That is the whole mechanism of a loop.
Where this is taught
- Hardware, software and von Neumann is where the stored program idea comes from.
- The CPU and fetch-execute is the GCSE lesson for this page.
- CPU performance is clock speed, cores and cache together.
- Memory is what is on the other end of the buses.
- Hardware, software and the stored program starts the A level module.
- The processor and its registers covers every register and the status flags.
- The fetch-decode-execute cycle in detail writes the fetch out as register transfers.
- Instruction sets and addressing modes is what an operand can mean.
- Assembly language: the Little Man Computer is a processor like this one, with a standard instruction set.
- Performance, pipelining and parallel processors is why clock speed stopped rising.
Questions
What is the fetch decode execute cycle?
The loop a processor repeats for every instruction. It fetches the instruction at the address in the program counter, decodes it to work out what it means, and executes it. Then it starts again with the next address.
What happens in the fetch stage?
The address in the PC is copied to the MAR, memory sends the value at that address back along the data bus into the MDR, the PC is increased by one, and the instruction is copied from the MDR into the CIR.
What does the program counter do?
It holds the address of the next instruction to fetch. It goes up by one during every fetch, and a jump instruction writes a different address into it, which is how loops and decisions work.
What is the difference between the MAR and the MDR?
The MAR holds an address and its contents go out on the address bus. The MDR holds a value, the instruction or data that came back on the data bus, or one about to be written out.
What is the CIR for?
It holds the instruction that is being carried out, so that the MDR is free to fetch whatever data that instruction needs. Without it, loading a value would overwrite the instruction doing the loading.
What are the three buses?
The address bus, which carries addresses from the processor to memory and only goes that way. The data bus, which carries instructions and data both ways. The control bus, which carries signals such as read, write and the clock.
What does clock speed mean?
How many times a second the processor's clock ticks, measured in hertz. 3 GHz is 3 billion ticks a second. Each step of the cycle waits for a tick, so a faster clock gets through more instructions a second, but most instructions take more than one tick.
Does a higher clock speed always mean a faster computer?
No. A program that is waiting for memory, a disk or a network gains nothing, and a processor with a small cache can spend most of its ticks waiting. More cores help only a job that can be split up. Heat puts a ceiling on the clock, which is why processors gained cores instead of gigahertz.
What is the accumulator?
A register that holds the result of the last calculation the ALU did. Instructions such as SUB work on it, and a jump such as JN tests it.
What is the von Neumann architecture?
A design where instructions and data share the same memory and the same buses, and the processor works through them one instruction at a time with a program counter. Nearly every general purpose computer, including the one in a BugBot, is built this way.
Learn it step by step
These lessons build the same ideas one at a time, each with tasks the simulator marks.
- F9.3 Hardware, software and von Neumann Logic and computer systems, GCSE
- F9.4 The CPU and fetch-execute Logic and computer systems, GCSE
- F9.5 CPU performance Logic and computer systems, GCSE
- F9.6 Memory Logic and computer systems, GCSE
- A9.1 Hardware, software and the stored program Computer architecture, A level
- A9.2 The processor and its registers Computer architecture, A level
- A9.3 The fetch-decode-execute cycle in detail Computer architecture, A level
- A9.4 Instruction sets and addressing modes Computer architecture, A level
- A9.5 Assembly language: the Little Man Computer Computer architecture, A level
- A9.8 Performance, pipelining and parallel processors Computer architecture, A level