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.

Guidefree, runs in your browser

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.

The processor, main memory and the three buses, with the registers as they are after the first fetch of the demo's programCPUcontrol unitdecodes, sends signalsALUadds, comparesregistersPC1next addressCIRSENSErunning nowACC0last resultMAR0address outMDRSENSEvalue inmain memory0SENSE1DRIVE 602WAIT 83TURN 504WAIT 45STOP6SENSE7HALTaddress busone way: 0data busboth ways: SENSEcontrol busread, write, clock
The four moves of a fetch, in order: the PC's address goes into the MAR and out on the address bus, memory sends SENSE back on the data bus into the MDR, the PC goes up to 1, and the instruction moves into the CIR. Only the MAR and the MDR ever touch the buses.

One instruction, step by step

Fetch is four moves, always in this order:

  1. The address in the PC is copied into the MAR.
  2. Memory sends back what is at that address, along the data bus, into the MDR.
  3. The PC goes up by one, ready for next time.
  4. 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.

Eight instructions, eight trips round the cycle. The PC line climbs by one each time, and the accumulator holds 81 cm from the first SENSE until the second one makes it 74.
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)
Put this demo on your own site

Paste it into a school website, Moodle, Google Sites or a blog. More options on the embed page.

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.

90 trips round the cycle, with 17 jumps back to the start. The PC line climbs 0 to 4 and drops back to 0 each time. The ACC line falls as the wall gets nearer, and the loop ends when it goes 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")
Put this demo on your own site

Paste it into a school website, Moodle, Google Sites or a blog. More options on the embed page.

The program counter over the demo's cycles: a staircase from 0 to 4 that drops back to 0 on every JMP, and at the end jumps to 5 and stops135791101234567cyclePC after the instructionJMP 0 writes 0 into the PC868890the last 5 cyclesJN 5 jumps to the STOPEvery trip round the loop is 5 instructions. 17 jumps back, 90 cycles in all.
A jump is nothing more than writing an address into the PC. Here JMP 0 does it 17 times, and on the last trip the accumulator has gone negative, so JN 5 writes 5 instead and the program reaches HALT after 90 cycles.

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.

At 2 instructions a second the robot ran 17 cm past its stopping point, ending 8 cm from the wall, after 25 instructions. Backed up and run again at 20 instructions a second, it stopped 23 cm away after 120 instructions.
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")
Put this demo on your own site

Paste it into a school website, Moodle, Google Sites or a blog. More options on the embed page.

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.

Instructions carried out against time: a shallow line at the slow clock and a line ten times steeper at the fast one0481216202404080120160simulated time, secondsinstructions done2 a secondbacks up, then runs again20 a secondstopped 8 cm awaystopped 23 cm away
The gradient of the line is the clock speed. In 12 seconds the slow clock got through 25 instructions; in 6 seconds the fast one got through 120. The robot looks where it is going once every five instructions, so the slow run ran 15 cm further past the same stopping point.

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

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.

  1. F9.3 Hardware, software and von Neumann Logic and computer systems, GCSE
  2. F9.4 The CPU and fetch-execute Logic and computer systems, GCSE
  3. F9.5 CPU performance Logic and computer systems, GCSE
  4. F9.6 Memory Logic and computer systems, GCSE
  5. A9.1 Hardware, software and the stored program Computer architecture, A level
  6. A9.2 The processor and its registers Computer architecture, A level
  7. A9.3 The fetch-decode-execute cycle in detail Computer architecture, A level
  8. A9.4 Instruction sets and addressing modes Computer architecture, A level
  9. A9.5 Assembly language: the Little Man Computer Computer architecture, A level
  10. A9.8 Performance, pipelining and parallel processors Computer architecture, A level
Open the lessons