Timing and the Critical Path
The
synchronous discipline
promised us discrete time: logic settles between edges, flip-flops capture on the edge. Now we cash in the
promise and answer the question every architect ultimately gets paid to answer — how fast can the
clock tick? The answer is set by a single, unforgiving path through the chip: the longest chain of
logic that must finish between two edges. That is the critical path, and it alone
determines the maximum clock frequency. Every trick for going faster is, at bottom, a trick for shortening
it.
What must fit inside one clock period
Picture two flip-flops with a cloud of combinational logic between them. On the rising edge, the first
(launching) flip-flop releases its stored value; that value must travel through the logic and arrive,
stable, at the second (capturing) flip-flop before the next edge. Three delays stack up
in that journey, and their sum must fit inside one clock period T_{\text{clk}}:
- t_{cq} — the clock-to-Q delay: how long after the edge
the launching flip-flop actually puts its value on the wire;
- t_{\text{logic}} — the propagation delay of the
combinational logic in between (the critical path's length);
- t_{\text{setup}} — the setup time: the data must be stable
this long before the capturing edge, or the flip-flop may store garbage.
T_{\text{clk}} \;\ge\; t_{cq} + t_{\text{logic}} + t_{\text{setup}} \; (+\, t_{\text{skew}}).
Rearranged, the fastest you can clock is f_{\max} = 1/T_{\text{clk}}. The
t_{\text{logic}} term is the only big, designable one — and it is the length of
the longest path, because the clock must accommodate the worst case, not the average.
The clock-period budget, drawn
Think of one clock period as a fixed budget you must spend without going over. Here is that budget laid
out between a launching edge and a capturing edge:
The green slack at the end is your safety margin. Speeding up the clock shrinks the period from
the right, eating the slack; when slack reaches zero you are at f_{\max}. Push
further and the data arrives after the setup window closes — a setup violation, and the
chip computes wrong answers. The whole point of timing analysis is to find the path with the least slack
(the critical path) and make sure it stays non-negative.
Setup and hold: two windows around the edge
A flip-flop needs its data input to sit still in a little window bracketing the clock edge — not
just before it:
- Setup time t_{\text{setup}}: data must be stable this long
before the edge. Violating it is a too-fast-clock problem — the long path didn't
finish in time. You fix a setup violation by slowing the clock down (or shortening the
path).
- Hold time t_{\text{hold}}: data must stay stable this long
after the edge, so a new value racing through a short path doesn't overtake
the one being captured. A hold violation does not depend on clock speed — slowing the
clock will not help. You fix it by adding delay to the too-short path.
- Setup (max-delay):
T_{\text{clk}} \ge t_{cq} + t_{\text{logic,max}} + t_{\text{setup}} + t_{\text{skew}}
— bounds the longest path and sets f_{\max};
- Hold (min-delay):
t_{cq} + t_{\text{logic,min}} \ge t_{\text{hold}} + t_{\text{skew}}
— bounds the shortest path, independent of clock frequency;
- the critical path is the path with the smallest setup slack; it fixes the maximum
clock frequency f_{\max} = 1/T_{\text{clk}}.
Clock skew: when the tick arrives at different times
We pretended the clock edge reaches every flip-flop simultaneously. It does not — the clock is a signal on
a wire, and it arrives at different flip-flops at slightly different times. That difference is
clock skew t_{\text{skew}}. If the capturing flip-flop's edge
arrives late, it steals from your setup budget and lowers f_{\max}; but
that same late edge relaxes the hold constraint. Skew is double-edged, which is why clock
distribution — the H-tree networks and armies of buffers that spread the clock across a die — is one of the
most carefully engineered structures on the chip.
Pipelining: cut the path in half
If the critical path sets the clock, shorten it. Pipelining inserts registers
into a long stretch of combinational logic, splitting it into shorter stages. A path that took
t_{\text{logic}} becomes k stages of roughly
t_{\text{logic}}/k each — so the clock period drops toward
t_{\text{logic}}/k + t_{cq} + t_{\text{setup}} and the frequency climbs. You pay
for it: extra latency (a result now takes k cycles to emerge) and a fixed
t_{cq} + t_{\text{setup}} overhead per stage that eventually dominates
and caps the benefit. Deep pipelines are Amdahl's law in silicon — diminishing returns as the register
overhead swallows the ever-thinner slices of real logic.
// Compute max clock frequency from stage delays, and see what pipelining buys.
const t_cq = 0.05; // ns, clock-to-Q
const t_setup = 0.04; // ns, setup time
const t_skew = 0.02; // ns, clock skew
function fMaxGHz(logicNs: number): number {
const Tclk = t_cq + logicNs + t_setup + t_skew; // ns
return 1 / Tclk; // GHz (1/ns)
}
const totalLogic = 1.20; // ns of combinational logic on the critical path
console.log(`1 stage : Tclk = ${(t_cq + totalLogic + t_setup + t_skew).toFixed(2)} ns -> ${fMaxGHz(totalLogic).toFixed(2)} GHz`);
// Split the SAME logic across k balanced stages: each stage sees totalLogic/k.
for (const k of [2, 4, 8, 16]) {
const stage = totalLogic / k;
console.log(`${k} stages: stage logic = ${stage.toFixed(3)} ns -> ${fMaxGHz(stage).toFixed(2)} GHz`);
}
console.log("Note: gains flatten as the fixed t_cq + t_setup + t_skew overhead dominates.");
Intel's NetBurst (Pentium 4) chased clock frequency with a very deep pipeline — up to 31 stages — betting
that megahertz would sell. Two walls stopped it. First, the per-stage t_{cq}+t_{\text{setup}}
overhead became a large fraction of each ever-shorter stage, so frequency stopped scaling. Second, a deep
pipeline makes every branch misprediction and cache miss far more expensive — you flush and refill
many more stages — so real-world CPI ballooned. The
iron law
had the last word: a higher clock ($1/T_{\text{cycle}}$) bought at the cost of a much worse CPI is often a
net loss. Shorter, wider pipelines (the Core line) won.
The most common timing confusion: "my design fails timing, I'll just clock it slower." That cures a
setup violation, which is about the longest path finishing in time. But a
hold violation is about the shortest path — a new value racing through too little
logic and corrupting the value being captured at the same edge. The clock period never enters the
hold equation
(t_{cq} + t_{\text{logic,min}} \ge t_{\text{hold}} + t_{\text{skew}}), so
slowing down does nothing. Hold violations are fixed by adding delay (buffers) to the fast path.
Mixing these up has sunk many a first tape-out.
The knob behind every "GHz"
When a chip is advertised at 5 GHz, that number is 1/T_{\text{clk}} for a
T_{\text{clk}} squeezed down to the critical path plus flip-flop overhead. Every
technique in the rest of a computer-architecture course — faster
adders,
deeper pipelines, logic restructuring — is ultimately about that one path. And the reason we cannot simply
keep shrinking it forever is what the next lesson is about: as transistors got tiny and fast, the
wires between them refused to cooperate.