Base CS from zero
What flow means
You have seen how the CPU runs a fetch–decode–execute cycle forever. You have seen the program counter — the register that holds the address of the next instruction. But so far, every program traced has been perfectly straight: instruction 1, then instruction 2, then instruction 3, in order, no detours.
Real programs are not straight. A password check must do one thing when the password is correct and a different thing when it is wrong. A countdown must keep subtracting until it reaches zero. Something in the program must control which instruction the CPU picks up next.
That “something” is the topic of this entire unit. But before getting to branches and loops, you need a precise mental model of the default case — straight-line execution — and why it works the way it does. Once you understand the default, every deviation from it will make immediate sense.
After this lesson you can define execution flow as the ordered sequence of instructions the CPU actually runs, explain why the default is straight-line top-to-bottom execution, describe exactly how the program counter produces that straight-line order, and identify what kind of instruction must happen for the order to deviate from straight-line.
Execution flow: the sequence the CPU actually runs. A program stored in memory is just a list of instruction bytes sitting in cells. The bytes themselves do not move and do not have an inherent order — they are just data at known addresses.
Execution flow is the sequence in which those instructions are actually run by the CPU. It is not defined by the bytes themselves; it is defined by which instruction the program counter points to at each moment.
This distinction matters: you can have two identical programs in memory and run them with completely different execution flows if the CPU’s program counter is steered differently. The bytes are fixed; the flow is dynamic. What determines the flow is how the program counter moves.
The program counter drives the flow. Recall from Unit 03 that the program counter (PC) is a special-purpose register inside the CPU that holds the memory address of the next instruction to fetch. After the CPU fetches an instruction, the cycle moves to decode and then execute — and after execution, the PC must be updated before the next fetch.
The default update rule is simple: add the size of the current instruction to the PC. On an architecture where every instruction is 4 bytes, the PC advances by 4 after each instruction. If the current instruction was at address 100, the next fetch comes from address 104. Then 108. Then 112. The CPU sweeps forward through memory in equal steps.
Nothing about this default update involves any decision. The circuit that advances the PC by a fixed amount runs automatically after every non-jump instruction, regardless of what the instruction computed or what values are in the registers.
Straight-line execution: what it looks like in memory. When a program is loaded into memory, its instructions sit in consecutive cells in the exact order a programmer or compiler placed them. Because the PC advances forward by one instruction at a time, the CPU visits those cells in that exact order — top to bottom, first to last.
This is sequential execution, sometimes called straight-line code. It is the simplest possible execution flow: every instruction runs exactly once, in the order it appears in memory, with no repeats and no skips.
Most of the computation in most programs is sequential: arithmetic, variable assignments, function argument preparation. The deviations from sequential execution — branches and loops — are the parts that make programs interesting, but sequential execution is the baseline that everything else is measured against.
Why this works
Why is sequential the default and not something else? The sequential default follows directly from the physical design of the program counter circuit. Advancing a register by a fixed offset requires only an adder — the simplest arithmetic circuit. Any other behaviour (jumping, branching) requires additional circuits and conditions. Sequential execution is the “do nothing special” case that emerges from the simplest hardware. It is not a choice the programmer makes explicitly; it is what happens when no instruction overrides the default PC update.
What breaks the straight line: the jump instruction. The only way to deviate from sequential execution is for an instruction to write a different value into the program counter during the execute step.
Recall from Unit 03 (fetch–decode–execute): a JUMP instruction’s execute step sets the PC to the jump’s target address instead of letting the PC advance normally. The next fetch then comes from the target address, which may be anywhere in memory — before the current instruction, after it, or far away.
This one mechanism — overwriting the PC — is the basis for every non-sequential execution pattern. A branch is a conditional jump: the CPU sets the PC to the branch target only if a condition holds, and lets the PC advance normally otherwise. A loop is a backward jump: the CPU sets the PC back to an earlier address, causing instructions to run again.
Unit 07’s remaining lessons examine how each of these patterns works. But they all reduce to the same question: does this instruction overwrite the PC, and if so, with what address?
Tracing sequential flow through three instructions.
Suppose three instructions sit at addresses 200, 204, and 208 (each 4 bytes). The PC starts at 200.
Step 1 — Fetch from PC = 200. The CPU reads the instruction at address 200.
- Decode and execute: suppose this is
LOAD R0, 50(load the value at memory address 50 into register R0). After execution, R0 holds whatever was at address 50. - PC update: PC = 200 + 4 = 204. No jump was involved; the PC just advanced.
Step 2 — Fetch from PC = 204. The CPU reads the instruction at address 204.
- Decode and execute: suppose this is
ADD R0, R1(add R0 and R1, store result in R0). After execution, R0 holds the sum. - PC update: PC = 204 + 4 = 208.
Step 3 — Fetch from PC = 208. The CPU reads the instruction at address 208.
- Decode and execute: suppose this is
STORE R0, 60(write R0’s value to memory address 60). After execution, memory address 60 holds the sum. - PC update: PC = 208 + 4 = 212.
At no point did the CPU make a decision about order. It followed the default PC-advance rule three times. The flow was straight because no instruction wrote a different value into the PC.
Common mistake
A common misconception is that a program’s execution order is the same as the order it was written in the source file. That is mostly true for sequential code, but a compiler is free to reorder instructions that do not depend on each other — a process called instruction scheduling. What matters to the CPU is the order of instructions in the final binary, not in the source. The CPU only sees the bytes in memory; it never sees source code. The PC points into the binary, not into the source file.
Instructions are at addresses 40, 44, 48, and 52 (each 4 bytes). The PC starts at 40. After the instruction at 40 executes (not a jump), what does the PC hold?
Instructions are each 4 bytes. The PC is at 200 before a JUMP to address 100 executes. After the JUMP executes, the PC holds what value?
A sequence of 5 instructions at addresses 0, 4, 8, 12, and 16 (each 4 bytes) runs sequentially from the start. After all 5 have executed, the PC holds what value?
In sequential execution, how many times does each instruction run?
Which register does the CPU update after every instruction to keep track of where to fetch next?
What determines execution flow — the order in which instructions actually run?
Execution flow is the sequence of instructions the CPU actually runs, determined entirely by what value the program counter (PC) holds at each fetch step. The default behaviour after any non-jump instruction is sequential: the PC advances by the instruction size, so the CPU visits instructions in the order they appear in memory — top to bottom, one at a time. This is straight-line or sequential execution. The only way to deviate from this order is a jump instruction, which writes a different address into the PC during its execute step, causing the next fetch to come from a non-sequential location. Every branch and every loop in every program is built from this one mechanism.