When a clock passes through a logic gate controlled by an enable, the enable must only change while the clock is at the gate's non-controlling level, the level where the gate's output ignores the enable. For an AND gate, the enable must change only while the clock is low. For an OR gate, it must change only while the clock is high. If the enable changes at any other time, the gated clock gets a clipped pulse or a glitch. That is a functional failure, not just lost slack. STA tools infer clock-gating setup and clock-gating hold checks on these gates, and set_clock_gating_check sets the margins for those checks.
{
"title": "AND-type gating: EN rises while CLK is low, so GCLK starts with a full pulse",
"ticks": false,
"signals": [
{ "name": "CLK", "wave": "p.....", "period": 2 },
{ "name": "EN", "wave": "0..1........" },
{ "name": "GCLK = CLK AND EN", "wave": "0...hlhlhlhl" }
]
}
# Default margins for every inferred gating check (ns, illustrative)
set_clock_gating_check -setup 0.10 -hold 0.05 [current_design]
# Tighter setup margin on one hand-instantiated gate
set_clock_gating_check -setup 0.20 [get_cells u_cg/u_and_gate]
# Tell the tool which clock level to check when it cannot infer it
# (e.g. a mux or complex cell used as a gate)
set_clock_gating_check -high [get_cells u_clk_mux] ;# AND-like behaviour
set_clock_gating_check -low [get_cells u_or_gate] ;# OR-like behaviour
Why synthesis inserts ICG cells
An
integrated clock-gating (ICG) cell latches the enable while the clock is low, then ANDs it with the clock, so the enable is held stable by design. Its setup and hold requirements are characterised in the
.lib (a cell marked with a
clock_gating_integrated_cell attribute). The tool times those library arcs directly instead of inferring a check on discrete logic. Bare AND/OR gating is mainly found in hand-written or legacy RTL, and that is where the margins above matter most. Option names and report commands vary between tools, so check your tool's manual.