Hardware, software and the stored program

Internal components, the three buses and their widths, I/O controllers, the stored program concept, and von Neumann against Harvard.

A9.1Computer architectureA level20 min

Do this lesson in the simulator

At GCSE (F9.3) you met the von Neumann architecture: a processor, a memory that holds both the program and its data, and buses joining them. At A level you need the same picture drawn precisely: which components sit inside the computer, what each bus carries and in which direction, what exactly the stored program concept says, and when a designer would choose the Harvard architecture instead. This module then opens the processor itself, and it uses BugBot's microcontroller as the running example of a real embedded processor.

Hardware and software

Hardware is the physical components of a computer system. Software is the programs: sequences of instructions, together with the data they work on. Neither is any use alone. Hardware only does something when a program tells it what to do, and a program can only run on hardware.

The link between them is the instruction set. A processor can carry out a fixed set of simple operations, each with a binary code. Every piece of software, whatever language it was written in, is turned into (or interpreted by a program already made of) those binary instructions. Your Python program on BugBot runs inside the Python interpreter, which is itself machine code for the robot's processor. The robot's firmware, written in C, was compiled into the same machine code. So there are layers: your program, then the interpreter and operating system, then firmware and drivers, then the hardware that finally does the work.

The internal components

Component What it does
Processor fetches instructions from main memory, decodes them and executes them
Main memory holds the instructions and data of the programs that are running, each byte at a numbered address; the processor can read any address directly
Address bus carries a memory address from the processor to memory or an I/O controller: one way only
Data bus carries data or instructions between the processor, memory and I/O controllers: both ways
Control bus carries control and timing signals, such as memory read, memory write, the clock, interrupt request, bus request, bus grant and reset: both ways, since some lines go into the processor and some out
I/O controller an electronic circuit that connects a device (a keyboard, a disk, a motor) to the buses, translating between the processor's signals and the device's
The processor, main memory and an I/O controller joined by the address, data and control busesProcessorMain memoryI/O controllerAddress busData busControl bus
Every component connects to all three buses; a dot marks each connection

A bus is a set of parallel wires, and each wire carries one bit. So a bus's width is a number of bits, and it sets a limit:

  • an address bus of n wires can make 2n different addresses, so it limits how much memory the processor can address directly;
  • a data bus of w wires carries one w-bit value at a time, usually the processor's word length.
for n in [8, 16, 20, 32]:
    addresses = 2 ** n
    print(f"{n:2}-bit address bus: {addresses:,} addresses")

print("32 bits of address, one byte at each:", 2 ** 32 // 1024 ** 3, "GiB")

Run this in the simulator

That last line is why a processor with a 32-bit address bus is limited to 4 GiB of directly addressable memory.

Why I/O controllers?

The processor cannot drive a motor or read a camera directly. The devices work at different voltages and speeds, and each speaks its own protocol. An I/O controller sits between: the processor reads and writes it through the buses like memory, and the controller deals with the device. On BugBot, the processor does not switch motor current itself. It sends a byte to a motor driver chip on the Motion board, and that chip switches the motor.

The stored program concept

The stored program concept: machine code instructions are stored in main memory, alongside data, and are fetched and executed serially (one after another) by a processor that performs arithmetic and logical operations.

Three consequences follow, and exam questions often want them:

  1. To change the job, load a different program. Before stored programs, machines such as ENIAC were rewired for each problem.
  2. Instructions and data look the same. Memory holds binary patterns. A pattern is an instruction only because the program counter points at it. This lets one program handle another as data, which is how compilers, loaders and operating systems work.
  3. Instructions are executed one at a time, in order, unless an instruction changes the program counter (a branch).
memory = [0b00010101, 0b00100110, 0b11111111, 0b00000011, 0b00000100]

for address, value in enumerate(memory):
    print(address, format(value, "08b"), "as a number:", value)

Run this in the simulator

Nothing in that list says which bytes are instructions. The processor decides by where the program counter points, which is why a bug that jumps into data makes a program do nonsense.

Von Neumann and Harvard

Von Neumann Harvard
Memory one memory for instructions and data separate memories for instructions and for data
Buses one set of buses shared by both a separate set of buses for each
Fetching an instruction and a data item cannot use the bus at the same time an instruction and data can be fetched at the same time
Word lengths and memory types the same for both can differ: instructions in flash or ROM, data in RAM
Typical use general-purpose computers: PCs, laptops, servers embedded systems and digital signal processors

The weakness of von Neumann is that one shared bus limits how fast instructions and data move between memory and processor: the von Neumann bottleneck. Its strength is simplicity and flexibility: memory is not split, so any free space can hold program or data.

Harvard suits embedded systems because their program is fixed and lives in non-volatile memory, the data lives in a small RAM, and the separate paths give fast, predictable timing.

Contemporary processors mix the two. Main memory is shared, von Neumann style, but inside the processor the cache is split into an instruction cache and a data cache with separate paths, Harvard style. This is often called a modified Harvard architecture.

The robot's processor

BugBot's main processor is an ESP32-P4 microcontroller: processor cores, some RAM and many I/O interfaces on one chip, made for embedded systems. Its program (the firmware and the Python interpreter) is kept in flash memory that survives power off, and it works on data in RAM. When you run a program, your Python source is sent to the robot as data, and the interpreter, itself a stored program, reads it and acts on it: the stored program concept in action.

Task: bus widths

Work out what a bus of a given width can carry.

  • For each address bus width in [12, 16, 24, 32] bits, print how many different addresses it can make, as a whole number with no commas, in the form address bus 16 bits: 65536 addresses.
  • For each data bus width in [8, 16, 32] bits, print the smallest and largest unsigned whole number it can carry, in the form data bus 8 bits: 0 to 255.

Print the seven lines in that order. The robot does not move.

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

address_widths = [12, 16, 24, 32]
data_widths = [8, 16, 32]

Challenges

  1. A processor has a 20-bit address bus and each address holds one byte. How many MiB can it address?
  2. Give two reasons a washing machine controller would use Harvard architecture.
  3. Explain why the data bus must be bidirectional but the address bus need not be.