Loading header...

The Fetch-Decode-Execute Cycle, One Clock Edge at a Time

We've spent four lessons taking the CPU apart piece by piece: reset forces a known starting address, a decoder turns opcode bits into control wires, the ALU computes everything in parallel and a mux picks the winner, and a control unit — micro­coded or hardwired — sequences all of this across however many cycles an instruction needs. Now it's time to put the pieces back together and watch them work as one machine, on one real instruction, one clock edge at a time. By the end of this lesson, "the CPU executed an instruction" should stop sounding abstract and start sounding like exactly what it is: a tightly choreographed sequence of wires flipping in a specific order, driven by nothing more than a clock and some combinational logic.


Our Subject: AVR ADD R1, R2

We'll trace the AVR instruction ADD R1, R2 — add register R2 into register R1, store the result back in R1. Its 16-bit encoding, straight out of lesson 2:

Break the encoding into fields:

  • Fixed opcode prefix: 0000 11.
  • Destination bits: 0 00001, selecting R1.
  • Source bits: 0010, combined with the extra source bit, selecting R2.
  • Decoder result: read R1 and R2, add them, and write the result back to R1.

On AVR, this single instruction executes in exactly one clock cycle — a direct payoff of the hardwired control philosophy from lesson 4. (We'll also glance at the 8085 equivalent, which needs multiple T-states, to highlight the contrast.)


Learning Objectives

By the end of this lesson, you should be able to:

  • Trace a simple instruction from fetch through writeback.
  • Identify which CPU events are clocked and which are combinational settling.
  • Explain why setup time, propagation delay, and clock period constrain instruction timing.
  • Compare a single-cycle AVR register operation with a multi-T-state 8085 memory operation.
  • Use timing diagrams to debug incorrect register writes, stale opcodes, or missed flag updates.

The Datapath We're About to Watch

flowchart LR classDef cpu fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a classDef mem fill:#dcfce7,stroke:#16a34a,color:#14532d classDef bus fill:#f3e8ff,stroke:#9333ea,color:#581c87 classDef clk fill:#fef9c3,stroke:#ca8a04,color:#713f12 PC["Program Counter"]:::cpu IMEM["Program Memory\n(Flash)"]:::mem IR["Instruction Register"]:::cpu DEC["Decoder\n(lesson 2)"]:::bus RF["Register File\n(R0-R31)"]:::cpu ALU["ALU\n(lesson 3)"]:::cpu SREG["Status Register\n(flags)"]:::bus PC -->|address| IMEM IMEM -->|opcode| IR IR --> DEC DEC -->|reg addresses| RF DEC -->|ALU op-select| ALU RF -->|R1, R2 values| ALU ALU -->|result| RF ALU -->|flags| SREG DEC -->|PC_inc| PC

Every box here is something you've already met. This lesson is purely about timing — which wires assert on which edge.


Step-by-Step Across the Clock Cycle

sequenceDiagram participant CLK as Clock participant PC as Program Counter participant MEM as Flash Memory participant IR as Instruction Reg participant DEC as Decoder participant RF as Register File participant ALU as ALU CLK->>PC: Rising edge T0 PC->>MEM: Drive address (current PC) MEM->>IR: Opcode bits available, latched into IR IR->>DEC: 0000 11 0 00001 0010 decoded DEC->>RF: Assert read addresses R1, R2 RF->>ALU: R1 value, R2 value driven onto operand buses DEC->>ALU: ALU_OP = ADD (function-select) ALU->>ALU: Adder computes R1+R2 (lesson 3: all units compute, mux selects ADD) ALU->>RF: Result + flags ready before next clock edge CLK->>RF: Rising edge T1 - latch result into R1, latch flags into SREG CLK->>PC: Same edge - PC increments to next instruction

Notice everything between T0 and T1 — fetch, decode, register read, ALU compute — happens as combinational logic settling, not as separate clocked steps. The clock only marks two moments: "start this instruction" (T0) and "commit the results" (T1). Inside that window, signal propagation through the decoder and ALU just needs to finish before T1 arrives, which is exactly why lesson 3's "constant ALU delay regardless of operation" property matters: the clock period has to be long enough for the slowest possible combinational path, every single cycle.


Worked Example: Minimum Clock Period

A simplified single-cycle CPU has these worst-case delays for an ADD path:

Path segment Delay
PC clock-to-output 0.5 ns
Instruction memory access 4.0 ns
Instruction decode 1.5 ns
Register file read 1.0 ns
ALU add and flag logic 3.0 ns
Register setup time 0.5 ns

The clock period must cover the whole path from one clocked state element to the next:

  • Tclk_min = 0.5 + 4.0 + 1.5 + 1.0 + 3.0 + 0.5 ns.
  • Tclk_min = 10.5 ns.
  • fmax = 1 / Tclk_min.
  • fmax is approximately 95.2 MHz.

Real CPUs include clock skew, routing delay, memory wait states, and margin, so the production maximum frequency would be lower. The calculation still shows the core rule: one instruction per cycle is only safe when every required signal arrives before the next capture edge.


Waveform View: Which Wire Fires When

The timing sketch below is explanatory, not a gate-level simulation. It shows valid windows and latch pulses within one AVR-style ADD R1, R2 cycle.

title "AVR ADD R1, R2 timing"
time start=0 end=10 unit=ns divisions=10

CLK: square label="clock" low=0 high=1 duty=50 cycles=1 unit=logic color=#ca8a04
ADDR: step label="PC address valid" low=0 high=1 at=1 unit=logic color=#2563eb
OP: step label="opcode valid" low=0 high=1 at=2 unit=logic color=#16a34a
DEC: step label="decode settled" low=0 high=1 at=4 unit=logic color=#9333ea
ALU: step label="ALU result valid" low=0 high=1 at=7 unit=logic color=#dc2626
WE: pulse label="write enable" low=0 high=1 at=9 width=0.5 unit=logic color=#0f766e

marker T0 at=0 label="T0 edge"
marker T1 at=10 label="T1 edge"

Read this left to right: the opcode bus has valid data almost immediately, the decoder output settles a little later (it has to wait for the IR latch), the register file read happens once addresses are known, and the ALU result is the last thing to settle — because it's waiting on everything upstream. RF_WE (register file write-enable), SREG_latch, and PC_inc all fire together, right at the end of the cycle, because writing back early — before the ALU result is guaranteed stable — would corrupt the register file with a half-settled value.


Contrast: The 8085's Multi-T-State Version

The 8085 (microcoded, lesson 4) needs multiple T-states even for a simple accumulator operation, because its bus and ALU aren't built for everything to happen in one combinational sweep. A representative ADD M (add memory operand pointed to by HL into the accumulator) takes several T-states:

T-state What happens
T1 Opcode fetch begins; PC drives address bus
T2 Opcode latched into instruction register; decode starts
T3 HL register pair drives address bus to fetch memory operand
T4 Memory operand read onto data bus, latched into temp register
T5 ALU adds accumulator + temp register; result stored in accumulator, flags updated
flowchart LR classDef clk fill:#fef9c3,stroke:#ca8a04,color:#713f12 classDef cpu fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a classDef mem fill:#dcfce7,stroke:#16a34a,color:#14532d T1["T1: Fetch opcode"]:::clk T2["T2: Latch + begin decode"]:::cpu T3["T3: Drive HL onto address bus"]:::cpu T4["T4: Read memory operand"]:::mem T5["T5: ALU add, writeback, flags"]:::cpu T1 --> T2 --> T3 --> T4 --> T5

This is the microcode sequencer from lesson 4 in action: each T-state corresponds to one row read out of the 8085's internal microcode-driven control logic, asserting a different subset of control wires each time, because the operand has to travel from memory to the ALU across a shared, narrower internal bus rather than AVR's direct register-file-to-ALU wiring.


ARM Cortex-M Thumb Encoding, For Comparison

A roughly equivalent ARM Thumb instruction, ADDS R1, R1, R2 (add R2 into R1, set flags), also uses a compact 16-bit Thumb encoding. In the Thumb T1 form, the fixed 0001100 pattern identifies register add, while the remaining rrr, rrr, and ddd fields select the source and destination registers.

Cortex-M's pipeline overlaps fetch/decode/execute across instructions rather than completing everything in a single isolated cycle — but the combinational decode-to-control-signal mapping inside each stage is the same principle as AVR's: opcode bits matched by hardwired logic (lesson 2), function-select bits routed straight into the ALU mux (lesson 3), all driven by a clock that — because control is hardwired, not microcoded (lesson 4) — has predictable per-stage timing, which is precisely what makes the pipeline overlap safe to build in the first place.


Everything At Once: The Full Picture

flowchart TD classDef cpu fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a classDef mem fill:#dcfce7,stroke:#16a34a,color:#14532d classDef bus fill:#f3e8ff,stroke:#9333ea,color:#581c87 classDef clk fill:#fef9c3,stroke:#ca8a04,color:#713f12 R["Lesson 1: Reset forces\nPC to known address"]:::clk F["Fetch: PC addresses Flash,\nopcode latched into IR"]:::mem D["Lesson 2: Decoder matches\nopcode bits → control wires"]:::bus A["Lesson 3: ALU computes all ops\nin parallel, mux selects ADD"]:::cpu C["Lesson 4: Hardwired control\nkeeps this 1 cycle, not many"]:::bus W["Writeback: result + flags\nlatched on next clock edge"]:::cpu N["PC increments,\ncycle repeats"]:::clk R --> F --> D --> A --> C --> W --> N --> F

This loop — fetch, decode, execute, writeback, increment, repeat — is the entire reason a CPU appears to "run a program." There is no higher-level interpreter, no hidden intelligence. It's reset's fixed starting point, the decoder's mechanical bit-matching, the ALU's parallel-compute-then-select trick, and the control unit's cycle-sequencing strategy, looping at clock speed, forever, until power is removed.


Common Mistakes

  • Treating fetch, decode, and execute as always separate clock cycles. In a single-cycle datapath they are phases of settling inside one cycle.
  • Writing the register file before the ALU result and flags are stable.
  • Ignoring memory wait states; flash or external memory can stretch the fetch path.
  • Assuming pipeline overlap changes the architectural result. It changes timing, not instruction semantics.
  • Forgetting that flags are part of writeback and must correspond to the same selected result as the destination register.

Summary

Everything from lesson 1 onward converges right here: reset gave the CPU a starting address, the decoder turned that address's opcode into wires, the ALU computed every possible result and let the mux pick one, and the control philosophy (hardwired or microcoded) determined whether that all happened in one clock cycle or five. "The fetch-decode-execute cycle" isn't a separate new concept to memorize — it's simply the name for watching all four previous mechanisms run together, on schedule, clock edge after clock edge, for as long as the chip has power.

This is the last lesson in the Internals series — you now have the complete chain from "power applied" to "instruction executed," wire by wire.

Further Reading

  • Patterson and Hennessy, Computer Organization and Design, single-cycle and pipelined datapath chapters.
  • Microchip, AVR Instruction Set Manual, instruction cycle counts and status flag behavior.
  • Intel, 8085 Microprocessor User Manual, machine cycles and T-state timing.
  • Arm, Cortex-M Technical Reference Manuals, fetch/decode/execute pipeline descriptions.

Mind Map

mindmap root((Fetch Decode Execute)) Core loop PC addresses instruction Opcode enters IR Decoder asserts controls Register file drives operands ALU result writes back Timing Clock edges capture state Logic settles between edges Tclk covers worst path fmax equals 1 over Tclk Wait states stretch fetch Worked formulas Tclk min equals clk to Q plus logic plus setup fmax equals 1 divided by Tclk min Example 10.5 ns gives about 95 MHz Applications AVR ADD one cycle 8085 ADD M multiple T states Cortex M pipeline overlap Firmware timing estimates Practical checks Verify opcode encoding Check register addresses Confirm write enable timing Confirm flags latch once Inspect memory wait states Common mistakes Separating phases incorrectly Early writeback Stale opcode fetch Flags from wrong result