Clock Gating in Verilog: Glitch-Free Integrated Clock Gate (ICG)
Clock gating is the single most common dynamic-power-saving technique in digital design: stop the clock to idle logic and you kill its switching power. But you cannot simply AND the clock with an enable — that creates glitches and runt pulses that corrupt flip-flops. This page shows production-style clock gating verilog code for a latch-based integrated clock gate (ICG) that is glitch-free by construction.
We build gclk = clk & en_lat, where en_lat is captured by a level-sensitive latch while clk is low, then contrast it with the broken gclk = clk & en form. A second example drives a counter from the gated clock so you can see the enable actually start and stop counting.
Latch-based integrated clock gate vs naive AND
The latch samples en only during the low phase of the clock. Because the enable can only change en_lat while clk is low, the product clk & en_lat can never be cut mid-pulse — no glitch. The testbench counts rising edges of the gated clock with en=0 (expect 0) and en=1 (expect 3), then flips the enable in the middle of a high phase to prove the ICG output stays clean.
// icg.v : latch-based integrated clock gate (glitch-free) vs naive AND gate
module icg(input clk, input en, output gclk);
reg en_lat;
// level-sensitive latch: sample en only while clk is LOW
always @(*) if(!clk) en_lat = en;
assign gclk = clk & en_lat; // enable change during HIGH phase cannot create a glitch
endmodule
module tb;
reg clk, en;
wire gclk_icg;
wire gclk_naive = clk & en; // WRONG: en change during HIGH phase glitches
integer icg_edges, naive_edges;
reg prev_icg, prev_naive;
icg dut(.clk(clk), .en(en), .gclk(gclk_icg));
// count rising edges of each gated clock
always @(posedge gclk_icg) icg_edges = icg_edges + 1;
always @(posedge gclk_naive) naive_edges = naive_edges + 1;
initial begin
clk = 0; en = 0;
icg_edges = 0; naive_edges = 0;
// ---- Phase A: en=0 across 3 full clock periods -> expect 0 gated edges ----
repeat (3) begin
#5 clk = 1; #5 clk = 0;
end
$display("en=0 : icg rising edges = %0d (expect 0)", icg_edges);
if (icg_edges !== 0) begin $display("FAIL: gated clock ticked while disabled"); $finish; end
// ---- Phase B: enable while clk LOW, run 3 periods -> expect 3 gated edges ----
en = 1; // changed during LOW phase (the safe way)
repeat (3) begin
#5 clk = 1; #5 clk = 0;
end
$display("en=1 : icg rising edges = %0d (expect 3)", icg_edges);
if (icg_edges !== 3) begin $display("FAIL: wrong enabled edge count"); $finish; end
// ---- Phase C: flip en HIGH->LOW in the MIDDLE of a HIGH phase ----
// Naive AND would chop the clock and create a spurious falling/rising glitch.
// The ICG latch holds en_lat until clk returns LOW, so gclk stays clean.
en = 1; #5 clk = 1; // rising edge #4 of icg
#2 en = 0; // mid-high toggle: naive gclk drops now (glitch), icg holds
#3 clk = 0; // period ends; latch now samples en=0
$display("after mid-high toggle: icg edges = %0d (expect 4)", icg_edges);
if (icg_edges !== 4) begin $display("FAIL: mid-high toggle disturbed icg clock"); $finish; end
// One more full period with en held 0 -> icg must NOT tick again
#5 clk = 1; #5 clk = 0;
$display("next period (en latched 0): icg edges = %0d (expect 4)", icg_edges);
if (icg_edges !== 4) begin $display("FAIL: icg ticked after being gated off"); $finish; end
$display("ALL PASS");
$finish;
end
endmoduleen=0 : icg rising edges = 0 (expect 0) en=1 : icg rising edges = 3 (expect 3) after mid-high toggle: icg edges = 4 (expect 4) next period (en latched 0): icg edges = 4 (expect 4) ALL PASSSimulation prints the edge count at each phase and ends with
ALL PASS. The naive gated clock is left in the testbench so you can probegclk_naivein a waveform viewer and watch it glitch on the mid-high toggle.Driving a counter with the gated clock
Here the ICG output feeds a 4-bit counter. When
en=0the gated clock never rises, so the counter freezes; whenen=1it advances once per cycle. The testbench checks the counter holds at 0 while disabled, counts up to 5 when enabled, holds through three more gated cycles, then resumes.// gated_counter.v : use a glitch-free gated clock to drive a counter module icg(input clk, input en, output gclk); reg en_lat; always @(*) if(!clk) en_lat = en; assign gclk = clk & en_lat; endmodule module counter(input gclk, input rst, output reg [3:0] q); always @(posedge gclk or posedge rst) if (rst) q <= 4'd0; else q <= q + 4'd1; endmodule module tb; reg clk, en, rst; wire gclk; wire [3:0] q; icg cg (.clk(clk), .en(en), .gclk(gclk)); counter c (.gclk(gclk), .rst(rst), .q(q)); task one_cycle; // one full clock period begin #5 clk = 1; #5 clk = 0; end endtask initial begin clk = 0; en = 0; rst = 1; #3 rst = 0; // release reset while clk low $display("after reset: q = %0d (expect 0)", q); if (q !== 4'd0) begin $display("FAIL: reset"); $finish; end // 4 cycles while gated OFF -> counter frozen en = 0; repeat (4) one_cycle; $display("en=0 x4 cycles: q = %0d (expect 0)", q); if (q !== 4'd0) begin $display("FAIL: counted while disabled"); $finish; end // 5 cycles enabled -> counter advances to 5 en = 1; repeat (5) one_cycle; $display("en=1 x5 cycles: q = %0d (expect 5)", q); if (q !== 4'd5) begin $display("FAIL: wrong enabled count"); $finish; end // gate off again for 3 cycles -> holds at 5 en = 0; repeat (3) one_cycle; $display("en=0 x3 cycles: q = %0d (expect 5)", q); if (q !== 4'd5) begin $display("FAIL: did not hold"); $finish; end // enable 2 more -> 7 en = 1; repeat (2) one_cycle; $display("en=1 x2 cycles: q = %0d (expect 7)", q); if (q !== 4'd7) begin $display("FAIL: resume count"); $finish; end $display("ALL PASS"); $finish; end endmoduleafter reset: q = 0 (expect 0)
en=0 x4 cycles: q = 0 (expect 0)
en=1 x5 cycles: q = 5 (expect 5)
en=0 x3 cycles: q = 5 (expect 5)
en=1 x2 cycles: q = 7 (expect 7)
ALL PASSThe counter value is checked after each phase and the run ends with
ALL PASS, confirming the gated clock cleanly starts and stops the register updates.How the latch-based ICG works
A clock gate must obey one rule: the gating signal presented to the
ANDgate may only change while the clock is in its inactive (low) phase. If the enable changes while the clock is high, the productclk & encan drop in the middle of a pulse (a runt or glitch) or create an extra edge — either of which can illegally clock a flip-flop. The integrated clock gate enforces the rule with a negative level-sensitive latch. In the code,always @(*) if(!clk) en_lat = en;makesen_lattransparent only whileclkis low and opaque (held) whileclkis high. So any late-arriving enable change is parked until the next low phase, andgclk = clk & en_latis glitch-free by construction.Why the naive AND gate is wrong
The tempting one-liner
assign gclk = clk & en;fails becauseenis a free-running signal from upstream logic and has no relationship to the clock phase. Ifenfalls whileclkis high,gclkimmediately falls too, chopping the current high pulse short and producing a falling edge the downstream logic never expected. Ifenrises mid-high, you get a spurious rising edge — an illegal extra clock. In the first example,gclk_naiveis wired up precisely so you can observe this on a waveform: at the mid-high toggle the ICG output is undisturbed while the naive output glitches.Synthesis and timing notes
Do not actually write RTL latches in production code. Real flows instantiate the library's clock-gating cell (often called
CKLNQD,ICG, or similar) through the synthesis tool's automatic clock-gate insertion (e.g.set_clock_gating_stylein industry-standard synthesis tools/industry-standard synthesis tools). The behavioral latch shown here is the model of that cell — it is ideal for teaching and simulation but an inferred latch in a datapath is a classic lint error. Timing-wise the enable must satisfy setup to the rising edge of the clock at the latch, which is why tools enforce a tight timing arc on the gating enable. Clock gating also helps place-and-route: fewer toggling endpoints means less clock-tree dynamic power.Common pitfalls
Three traps catch beginners. First, sampling the enable on the wrong phase — if you make the latch transparent while
clkis high you have simply moved the glitch window, not removed it. Second, forgetting that the gated clock is now a derived clock: it must be declared as a generated clock in your SDC or static timing analysis will mis-analyze it. Third, gating a reset or a clock that feeds asynchronous logic — keep clock gating on well-behaved synchronous domains only. Also note the counter here uses an asynchronous reset outside the gated path so it can be cleared even when the clock is gated off.Interview angle
A near-universal interview question is: “Why can't you gate a clock with a simple AND gate, and how do you fix it?” The answer is exactly this page: an asynchronous enable ANDed with the clock produces glitches and runt pulses, so you insert a negative-level-sensitive latch to hold the enable stable through the entire active phase, giving a glitch-free integrated clock gate. Follow-ups probe whether you'd ever write this as RTL (no — use the standard cell via automatic gating), what SDC constraint the gated clock needs (a generated clock), and how clock gating saves dynamic power (it stops unnecessary clock-tree and register toggling). Being able to sketch the latch-plus-AND and explain the phase argument cleanly is what separates a confident answer from a vague one.
Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.▶ Try it in the ChipXpert LabRun it in the LabOpen this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.
Learn Verilog with mentors, labs and placement support
This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.
Explore VLSI Courses Hi! Ask me about courses, fees, batches or discounts. ×ChipXpert AssistantAsk about courses, fees, batches and centres