The processor and its registers

The ALU, control unit and clock, general-purpose and dedicated registers, and the status flags an 8-bit ALU sets.

A9.2Computer architectureA level20 min

Do this lesson in the simulator

At GCSE (F9.4) you met the control unit, the ALU, the clock and four registers. At A level the list of registers grows, you need to say exactly what each part of the processor does, and you need to know the status register: the bits that record what the last operation did, which is how a processor makes decisions.

The components of the processor

Component What it does
Arithmetic logic unit (ALU) performs arithmetic (addition, subtraction, and operations built from them) and logic operations (AND, OR, NOT, XOR, shifts, comparisons) on binary values, and sets the flags in the status register to describe the result
Control unit (CU) decodes the instruction in the current instruction register and sends control signals, along the control bus and inside the processor, that make each step happen in the right order: which register loads, whether memory is read or written, which operation the ALU performs
Clock generates a regular stream of pulses; every step of the processor happens on a pulse, so all the components stay in step
Registers small, very fast storage locations inside the processor, each holding one word

The clock's rate is the clock speed, in hertz: a 400 MHz clock ticks 400 million times a second. One fetch-decode-execute cycle may take several ticks, so clock speed is not the same as instructions per second.

General-purpose and dedicated registers

General-purpose registers hold whatever the program is working on: intermediate results, counters, values about to be compared. A program chooses how to use them. AQA's assembly language has thirteen, called R0 to R12.

Dedicated registers each have one fixed job:

Register Holds
Program counter (PC) the address of the next instruction to be fetched
Current instruction register (CIR) the instruction being decoded and executed, split by the control unit into opcode and operand
Memory address register (MAR) the address in memory that is about to be read from or written to
Memory data register (MDR), called the memory buffer register (MBR) by AQA the data or instruction that has just been read from memory, or is about to be written to it
Accumulator (ACC) the result of calculations done by the ALU
Status register (SR) individual bits, called flags, that describe the result of the last operation, and bits that control the processor, such as whether interrupts are enabled

The MAR and MDR are the processor's two ends of the buses: the MAR drives the address bus, and the MDR sends and receives on the data bus.

The status register's flags

Most processors keep at least these four flags:

Flag Set to 1 when
N (negative) the result's most significant bit is 1, so as a two's complement number it is negative
Z (zero) the result is zero
C (carry) an unsigned addition carried out of the most significant bit: the true answer did not fit
V (overflow) a signed result is wrong: two numbers of the same sign gave a result of the other sign

Carry and overflow are easy to confuse. Carry is about the bits read as unsigned numbers; overflow is about the same bits read as two's complement. The ALU does not know which the programmer meant, so it sets both and lets the program choose.

Here is an 8-bit ALU adding two bytes and setting the flags:

def signed(byte):
    """0 to 255 read as 8-bit two's complement: -128 to 127."""
    return byte - 256 if byte >= 128 else byte

def alu_add(a, b):
    total = a + b
    result = total & 0xFF                 # only 8 bits fit in the register
    n = result >> 7
    z = 1 if result == 0 else 0
    c = 1 if total > 255 else 0
    same_sign_in = (signed(a) < 0) == (signed(b) < 0)
    v = 1 if same_sign_in and (signed(result) < 0) != (signed(a) < 0) else 0
    return result, n, z, c, v

for a, b in [(20, 30), (90, 90), (250, 10)]:
    print(a, "+", b, "->", alu_add(a, b))

Run this in the simulator

Check the middle one by hand. 90 + 90 = 180, which fits in 8 unsigned bits, so C = 0. But 180 is 10110100, and as two's complement that is -76: two positive numbers gave a negative answer, so V = 1 and N = 1.

How flags make decisions

A comparison is a subtraction whose answer is thrown away, keeping only the flags. To compare R0 with 10, the ALU works out R0 - 10:

  • if Z is 1, they were equal;
  • if Z is 0, they were not equal;
  • with signed values, if N and V differ, R0 was less than 10.

A conditional branch then looks only at the flags. In AQA's assembly language:

CMP R0, #10      // ALU works out R0 - 10 and sets the flags
BEQ done         // branch if Z = 1

This is the whole of how a processor makes an if or a while: an ALU operation sets flags, and the control unit loads a new address into the PC or not depending on them.

Not every processor works this way. The RISC-V cores in BugBot's ESP32-P4 have no flags at all: a RISC-V branch instruction such as beq compares two registers itself and branches on the result. RISC-V gives each core 32 general-purpose registers, x0 to x31, where x0 always reads as zero, plus a separate program counter.

Registers, cache and memory

Registers are the fastest storage in the computer because they are inside the processor and are part of the circuit that does the work. There are only a few of them, which is why the processor must keep copying values in from main memory and back out again. The next lesson follows those copies, one register transfer at a time.

Task: the flags

Write alu_add(a, b) yourself for an 8-bit ALU. Its inputs a and b are whole numbers from 0 to 255 (bytes). It works out the 8-bit result (0 to 255, anything that does not fit is lost) and the four flags N, Z, C and V, each 0 or 1, exactly as the table above defines them.

For each pair in pairs, print one line in the form 200 + 100 = 44 N=0 Z=0 C=1 V=0: the two inputs, the 8-bit result, then the flags in the order N, Z, C, V. The robot does not move.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

pairs = [(20, 30), (100, 50), (200, 100), (128, 128), (255, 1)]

def alu_add(a, b):
    return a + b

Challenges

  1. Write alu_sub(a, b) that works out a - b as an 8-bit subtraction and sets N, Z and V.
  2. Find a pair of bytes that sets C but not V, and a pair that sets V but not C, without running the program. Then check.
  3. Why does a processor need a CIR as well as an MDR, when both can hold the same instruction?