digiwleeaLearn
Open the lab →

Tracing a program

Four instructions, step by step

6 min read

A program trace hand-executes a program one step at a time, following the fetch-decode-execute cycle and watching the registers and bus change. Tracing a short LOAD, ADD, STORE, HALT program shows the accumulator CPU actually computing a sum.

You have the whole machine and its language. The last thing to do is run a program by hand, the way the hardware does: follow fetch-decode-execute, tracking each register as the control unit's steps fire. Do this once and the CPU stops being a diagram and becomes a thing you can predict. We will compute 5 + 10 and store the answer.

The program and the memory

Recall the instruction set: LOAD addr (0x1) copies memory[addr] into the accumulator ACC; ADD addr (0x2) adds memory[addr] to ACC; STORE addr (0x3) writes ACC back to memory[addr]; HALT (0xF) stops the clock. Here is memory, program at the bottom, data at the top, written in hex:
addressbytemeaning
00x1ELOAD 14
10x2FADD 15
20x3DSTORE 13
30xF0HALT
130x00result slot (starts 0)
140x05the value 5
150x0Athe value 10
Each program byte is opcode then operand: 0x2F is opcode 2 (ADD), operand 0xF (address 15). Addresses 14 and 15 hold the data 5 and 10; address 13 will receive the result.
Notice there is no line between code and data: both are just bytes in the same RAM. The program counter decides which bytes are read as instructions (it walks 0, 1, 2, 3) and which the instructions treat as data (addresses 13, 14, 15). This is the *stored-program* idea, the foundation of every general-purpose computer.
Predict, then trace
Before reading the trace below: after this whole program halts, what value is in the accumulator, and what value is in memory address 13? (The data is 5 at address 14 and 10 at address 15.)

The fetch that every instruction shares

Each instruction begins with the same fetch, driven by the control unit's step lines T0, T1 (from the ring counter):
  1. **T0:** the program counter drives its address onto the bus; RAM reads that byte; the instruction register loads it. Now the IR holds the instruction and exposes its opcode and operand.
  2. **T1:** the program counter increments, so it already points at the *next* instruction. Then the steps branch on the opcode to do the execute phase.

Running it, instruction by instruction

Start with PC = 0 and ACC undefined. Fetch reads address 0.
  1. **Fetch 0x1E (PC 0 -> IR), PC becomes 1.** Opcode 1 = LOAD, operand 14. Execute: put 14 on the address bus, RAM reads memory[14] = 5 onto the bus, the accumulator loads it. Now ACC = 5.
  2. **Fetch 0x2F (PC 1 -> IR), PC becomes 2.** Opcode 2 = ADD, operand 15. Execute: put 15 on the address bus, RAM reads memory[15] = 10 into the ALU's B input; the ALU adds (ACC + B = 5 + 10); the accumulator loads the sum. Now ACC = 15.
  3. **Fetch 0x3D (PC 2 -> IR), PC becomes 3.** Opcode 3 = STORE, operand 13. Execute: the accumulator drives ACC = 15 onto the bus, RAM writes it into memory[13]. Memory address 13 now holds 15.
  4. **Fetch 0xF0 (PC 3 -> IR), PC becomes 4.** Opcode F = HALT. Execute: the control unit stops the clock. The machine freezes with ACC = 15 and memory[13] = 15.
That is a complete program run. You wrote 5 + 10; the machine fetched four bytes, decoded each opcode, and performed the transfers, and the answer 15 (0x0F) is sitting in memory at address 13. Every step was one micro-operation: one value crossing the bus, gated by control lines, clocked into a register. Nothing magic, just the loop, repeated.

Watching the execute core do the arithmetic

The figure is the accumulator + ALU core, the part that does the LOAD and ADD execute steps. Driving its inputs over clocks reproduces the program's arithmetic directly: this is what the control unit makes happen once it has fetched an instruction. Step it to relive the trace.
  • Hold LD = 1 (load on every edge) and set the function F1 F0 = 00 (add).
  • Put 5 (0000 0101) on B, clear the accumulator first if needed, and clock: this is the LOAD/ADD that lands ACC = 5.
  • Put 10 (0000 1010) on B and clock again: the ALU adds, ACC becomes 15 (0000 1111), exactly the program's result.
  • Try one more ADD with B = 0 and ZERO stays low; subtract 15 (set F0 = 1, B = 0000 1111) and ACC returns to 0, lighting the ZERO flag.
The execute core (ACCALU): the accumulator wired into the ALU. B0-B7 is the operand the fetch step pulled from memory, F1 F0 is the operation the opcode chose, LD loads the result on a clock edge. Open it in the lab and replay the trace: add 5, then add 10, and read ACC = 15.
To hand-trace any program, keep a small table of the machine's state, one column each for PC, IR, ACC, and any memory you touch, and fill in a row per instruction. Fetch advances PC and reloads IR; execute changes ACC or memory per the opcode. That table is all a CPU really is: state, transformed one instruction at a time.
This is the end of the climb. From a single transistor you built gates, then arithmetic and memory, then a register, ALU, counter, RAM, and control unit, and now you have traced a program executing on a computer you understand top to bottom. Open the lab and write your own four-instruction program; you know exactly what every byte will do.

Frequently asked

What is a program trace?

A program trace is hand-executing a program one step at a time, following the fetch-decode-execute cycle and watching the registers (PC, IR, ACC) and memory change. Tracing a short LOAD / ADD / STORE / HALT program shows the accumulator CPU actually computing a sum: here, 5 + 10 = 15.

How does fetch-decode-execute work in this CPU?

Every instruction starts with the same fetch: on step T0 the program counter drives its address onto the bus, RAM reads that byte, and the instruction register loads it; on T1 the PC increments to point at the next instruction. The steps then branch on the opcode to run the execute phase (read the operand, run the ALU, load a register).

What is the stored-program idea?

There is no line between code and data: both are just bytes in the same RAM. The program counter decides which bytes are read as instructions (it walks 0, 1, 2, 3) and which the instructions treat as data (here addresses 13, 14, 15). This stored-program idea is the foundation of every general-purpose computer.

How do you hand-trace any program?

Keep a small state table with a column for PC, IR, ACC, and any memory you touch, then fill one row per instruction: fetch advances PC and reloads IR, and execute changes ACC or memory per the opcode. That table is all a CPU really is: state, transformed one instruction at a time.

Every lesson here builds toward one thing: a working CPU, from the transistor up.

Open the free lab →
Builds towardAssembly language
Found this useful? Share itShare on X