Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

How a processor runs each instruction (fetch-execute cycle)

After this lesson: I can follow fetch, decode and execute for one instruction.

50 min lesson9 commandsCompilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

Three billion times a second

The laptop on a help desk runs about three billion steps a second. Every one of them is the same small routine.

Read the next instruction, work out what it asks for, do it, and move on. Once you can follow that routine for one instruction, you can follow it for any program.

By the end of this lesson

Note

I can follow fetch, decode and execute for one instruction.

Key words

WordWhat it meansExample
Program counterthe register holding the address of the next instructionpc
Instruction registerwhere the instruction just fetched is held
Fetchreading the next instruction from memory
Decodesplitting the instruction into its fields
Executedoing the work the instruction asks for
Opcodethe field that says which kind of instruction it is

The cells students fill in are left blank in this preview.

One routine, over and over

The program counter, pc, holds the address of the next instruction. To fetch, the processor reads the word at that address into the instruction register and adds 4 to pc.

To decode, it splits the word into fields: what kind of instruction, which registers. To execute, it does the work and writes the result back. Then it fetches again.

Go to the architecture folder

Command
cd ~/arch

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Assemble the lab's add.s

Command
riscv64-linux-gnu-as add.s -o add.o

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Link it

Command
riscv64-linux-gnu-ld add.o -o add

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Watch the emulator fetch and decode

Command
qemu-riscv64 -d in_asm ./add

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

What the emulator fetched

qemu fetched five words from memory and decoded each one. Each line shows the address, the word in hex and what it decoded the word as.

The addresses go up by 4, from 0x000100b0 to 0x000100c0, because every instruction here is 4 bytes. Notice li has gone: the processor only ever sees addi a0,zero,2.

Decoding splits the word into fields

An add is 32 bits cut into six fields. The lowest seven bits are the opcode: 51, which means arithmetic on two registers.

Then come five bits for rd, the destination register, three bits for more detail, and five bits each for rs1 and rs2, the inputs. Register a0 is x10 and a1 is x11. So 00b50533 says: x10 = x10 + x11.

Worked example: the fields of 00b50533

BitsFieldValueMeaning
31 to 25funct70000000Plain add, not subtract
24 to 20rs201011 (11)Second input: x11, a1
19 to 15rs101010 (10)First input: x10, a0
14 to 12funct3000Add or subtract
11 to 7rd01010 (10)Answer goes to x10, a0
6 to 0opcode0110011 (51)Arithmetic on two registers

The cells students fill in are left blank in this preview.

The instruction as 32 bits

Command
python3 -c "print(format(0x00b50533, '032b'))"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Pull out opcode, rd, rs1 and rs2

Command
python3 -c "print(0x00b50533 & 127, (0x00b50533 >> 7) & 31, (0x00b50533 >> 15) & 31, (0x00b50533 >> 20) & 31)"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Execute, then the pc moves on

Execute does the work: an add, a load, a compare. Most instructions leave pc where fetch put it, 4 further on. A branch that is taken writes a new address into pc instead, and that is all a jump is.

With -d exec, qemu prints one line for every instruction it runs. The second number in the square brackets is the RISC-V pc.

One line for each instruction run

Command
qemu-riscv64 -one-insn-per-tb -d exec,nochain ./add

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A common mistake

Warning

Many people think the program counter counts how many instructions have run. It does not count anything. It holds an address: where the next instruction is. In a loop it goes back to the same addresses again and again.

Stepping this machine's own processor

gdb can stop a native program and run one instruction at a time. Typed by hand, it waits for you. With -batch and a list of commands it runs them and ends, so a Run can use it.

The Run below stops at main, prints pc, runs one instruction with stepi and prints pc again. On an Arm processor the address moves by 4. On an x86 processor instructions are 1 to 15 bytes long, so the step varies.

Build the lab's loop program

Command
gcc -O2 -o loop loop.c

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Stop at main and step once

Command
gdb -batch -iex 'set debuginfod enabled off' -ex 'break main' -ex run -ex 'info registers pc' -ex stepi -ex 'info registers pc' ./loop

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Going further: count a loop's instructions

Write and build sum.s from the instructions lesson, or ask a neighbour for the printf line. Before you run anything, work out how many instructions it runs: three before the loop, three each time round, ten times, and two after.

Then type qemu-riscv64 -one-insn-per-tb -d exec,nochain ./sum 2>&1 | wc -l and compare. Which addresses appear ten times?

About this lab and its source: Compilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.