Some cells, memories above all, run internal sequences that take a fixed time per cycle. The library gives a minimum clock period for the pin, and STA checks the actual period at that pin. The check also catches clock definitions that were wrong in a way that no data path reveals.
# A memory clock pin with minimum period 1.25 ns (illustrative).
min_period = 1.25
clocks = {"clk_core": 1.10, "clk_core_div2": 2.20, "clk_mem": 1.25}
slack = {name: round(p - min_period, 2) for name, p in clocks.items()}
assert slack == {"clk_core": -0.15, "clk_core_div2": 0.95, "clk_mem": 0.0}
violators = [n for n, s in slack.items() if s < 0]
assert violators == ["clk_core"]
# fastest legal frequency at this pin
fmax = 1000.0 / min_period
assert abs(fmax - 800.0) < 1e-9
print("PASS: violators", violators, "; maximum frequency", fmax, "MHz")A memory fed directly by a 1.10 ns clock fails by 0.15 ns; the same clock divided by two has 0.95 ns of slack; a 1.25 ns clock is exactly at the limit, which is a zero-slack pass. The maximum frequency at the pin is 800 MHz. This is the usual reason a design is clocked through a divider or a separate memory clock.
Situation | Effect on the check |
|---|---|
Divided clock | Period at the pin is the divided period; larger slack |
Clock multiplexer | The pin sees the clock of each selected input; each period is checked |
Gated clock | Checked on the waveform defined at the pin; gating does not change the defined period |
Generated clock defined with the wrong divide ratio | Reported slack is wrong, in either direction |
Minimum period is clean for every macro clock pin, in every corner.
Clock definitions match the intended frequencies; a wrong generated clock can hide or invent period violations.
Whether clock uncertainty is subtracted from the period for this check is a methodology decision: state it in the signoff notes.
Divide-by-1 leaves 1.0 ns and fails. Divide-by-2 gives 2.0 ns and passes, so every ratio of 2 or more passes.