Paths and slack
After synthesis and placement, a design is flip-flops joined by gates and wires. On a clock tick, a new value leaves one flip-flop and races through the gates to the next. It must get there before the following tick.
Add up every delay on the path. Clock-to-Q is 0.5 ns, four gates take 1.0 ns each, and the long wire takes 1.0 ns. So the value arrives 5.5 ns (nanoseconds, billionths of a second) after the tick.
The clock runs at 200 MHz, so the next tick comes 5.0 ns later. Flip-flop 2 needs its input steady 0.4 ns before that tick: its setup time. So the value is required by 5.0 − 0.4 = 4.6 ns.
Slack = required time − arrival time = 4.6 − 5.5 = −0.9 ns. Positive slack means time to spare. Negative slack means the value is late, so flip-flop 2 may store a wrong value. This path fails.
Checking every path
Static timing analysis does this sum for every path in the design, using worst-case delays and no test inputs. It lists each path's slack. Timing is closed only when no slack is negative. Here the worst slack is −0.9 ns.
Fixing negative slack
The easiest fix is a slower clock. At 160 MHz the period is 6.25 ns, so the value is required by 5.85 ns and the slack becomes +0.35 ns. But now every part of the chip runs slower.
Keep 200 MHz and shrink the delays instead. The tool swaps in bigger, faster gates (0.7 ns each) and places parts closer, so the wire takes 0.3 ns. Arrival drops to 3.6 ns: slack +1.0 ns.
AND gives the same answer in any grouping. Regroup q & a & b & c & d as a balanced tree, ((q & a) & (b & c)) & d: every input passes at most 3 gates. Arrival 4.5 ns: slack +0.1 ns.
Or add a flip-flop in the middle. Now each half gets a whole clock period: 2.5 ns and 3.5 ns, with slack +2.1 and +1.1 ns. The cost: the result reaches flip-flop 2 one tick later.
Hold time
There is a second check. Flip-flop 3 needs its old input to stay steady 0.5 ns after the tick: its hold time. On this very short path the new value arrives after only 0.4 ns. Hold slack −0.1 ns: too early.
A slower clock cannot help: the hold check uses the same tick, so the period never enters it. The tool adds two 0.2 ns buffers: arrival 0.8 ns, hold slack +0.3 ns. With one setup fix as well, every slack is ≥ 0: timing closed.
The timing sums
;; step 1/11 · paths ;; about: Flip-flop 1, Gates, Long wire, Flip-flop 2 flip-flop 1 → 4 AND gates → long wire → flip-flop 2 synthesis turns your code into gates placement puts each gate on the chip routing draws the wires between them Every flip-flop-to-flip-flop link is a "path". A real design has millions.
The delays here (0.5 ns clock-to-Q, 1.0 ns per gate, 1.0 ns long wire, 0.4 ns setup, 0.5 ns hold) are round example numbers on the nanosecond scale of an FPGA design. Real tools read each cell's delays from the chip's timing library and also add clock skew and uncertainty, which this example leaves at zero. The example hold time (0.5 ns) is set above the fastest clock-to-Q (0.3 ns) so the short path fails; real flip-flops are usually built with clock-to-Q longer than the hold time, so two flip-flops joined by a bare wire normally pass hold, and real hold failures mostly come from clock skew (Harris and Harris, sections 3.5.2 and 3.5.3). In Python, 200e6 is 200 × 10⁶ (200 MHz), so 1 / 200e6 is the period in seconds and × 1e9 turns it into nanoseconds.