The assignment gclk = clk & en looks correct. The enable comes from logic that changes shortly after the rising edge, while clk is still high.
Enable changes while clk is high | Result on gclk |
|---|---|
1 → 0 | The pulse is cut short: a runt pulse that violates minimum pulse width |
0 → 1 | gclk rises in the middle of the high phase: a late, partial pulse that clocks flops at the wrong time and counts as a spurious edge |
The fix is a latch that is transparent while the clock is low and opaque while it is high. The enable can then only influence gclk by being present at the start of a pulse, and it cannot change anything while the pulse is running.
Nothing unusual: the latch is opaque while clk is high, so the pulse completes at full width. The enable change takes effect at the next low phase, and the next rising edge is suppressed.
The waveform shows the ideal gate_naive and icg models under a directed stimulus. The same en drives both gates. The clock period is 10 ns and the picture has four slots per period: two while clk is high, two while it is low. Each slot shows the values 0.62 ns after it starts, so a change is drawn at the start of the first slot that sees it: an en change 1 ns into a high phase appears one slot into that phase.
How to read it: there are six clock pulses. en changes four times: 1 ns into the second high phase (falls), in the low phase before the third pulse (rises), 3 ns into the third high phase (falls), and 1 ns into the fourth high phase (rises). Three of the four land while the clock is high.
Second pulse: en falls while clk is high. g_naive is high for only one of the two high slots: a runt pulse. en_lat still holds 1, so g_icg stays high for the full pulse.
Third pulse: en rises while clk is low, so the latch is transparent and en_lat follows it to 1 before the rising edge; both gates start a pulse. en then falls part-way through that high phase. g_naive is cut short again (one high slot), but en_lat stays at 1 through the whole high phase and g_icg completes a full pulse. en_lat only drops to 0 after clk falls, once the latch is transparent again.
Fourth pulse: en rises 1 ns after the rising edge. g_naive follows it at once with a late, short pulse in the second high slot, but en_lat still holds 0 and g_icg stays low for the whole cycle.
In the first, fifth and sixth pulses both gates agree and every g_icg pulse is full width. Never gate a clock with a bare AND gate; use an integrated clock-gating cell.
The naive gate, the latch-based gate, and the testbench that counts good and bad pulses.
`timescale 1ns/1ps
// Naive gating: AND the clock with the enable. Glitches whenever 'en' changes while clk is high.
module gate_naive (input logic clk, en, output logic gclk);
assign gclk = clk & en;
endmodule
// Latch-based integrated clock gate: the enable is captured while the clock is LOW,
// and held while it is high, so gclk can only start or stop cleanly at a clock edge.
module icg (input logic clk, en, te, output logic gclk);
logic en_l;
always_latch if (!clk) en_l = en | te; // te: test enable forces the clock on during scan
assign gclk = clk & en_l;
endmodule
Directed high-phase changes exercise the bad gate, followed by 200 random cycles. With the seed used, the expected count is 106 pulses: the AND gate delivers 135 pulses with 51 bad widths, and the ICG delivers 106 with 0 bad widths.
Gate | Pulses delivered | Width checks | Required outcome |
|---|---|---|---|
Expected | Count en at source rising edges | 5 ns high pulses | Pattern-dependent count |
AND gate | May differ from expected | At least one malformed pulse from directed stimulus | Negative control must fail ideal pulse contract |
Latch-based ICG | Equal to expected | Zero malformed high pulses | Finite ideal-model check |
These per-pulse high-width and edge-count checks apply only to this zero-delay model with enables driven away from latch-closing edges. They do not establish physical glitch immunity or minimum low width. Library enable/test-enable setup/hold arcs, pulse-width checks and CTS remain pending; see timing and signoff.
The waveform is generated from an Icarus Verilog simulation of the ideal gate_naive and icg models, with directed stimulus.
Testbench, run with Icarus Verilog 13.0 (2026-10-16): iverilog -g2012 -s tb_gate, then vvp with +SEED=162, prints PASS. Expected 106 pulses; the AND gate gives 135 pulses and 51 bad widths; the ICG gives 106 pulses and 0 bad widths. Counts are not portable across simulators even with an explicit seed.
The per-pulse width and edge-count checks apply only to this zero-delay model with enables driven away from the latch-closing edge. They do not establish physical glitch immunity or minimum low width. Library enable and test-enable arcs, pulse-width checks and CTS are separate.