Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Digital Design & Verification (Verilog, SystemVerilog, VLSI)  Module 6 – Clocks, resets and clock-domain crossing

Clocks for RTL designers: enables, gating, muxes

Why designs keep few clocks, how a latch-based gate stops a clock without the glitch of an AND gate, a glitch-free clock switch and generated clocks.

  • Advanced
  • 20 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free lesson, Pro answers: 20 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Explain why designs keep few clocks and slow their logic down with clock enables
  • Show why an AND gate on a clock glitches and how a latch-based gating cell prevents it
  • Build a glitch-free switch between two clocks and check its pulse widths in simulation
  • Recognise generated clocks and the constraints that tell timing analysis about them

Before you start

What you’ll learn · Before you start

What you will learn

  • Explain why designs keep few clocks and slow their logic down with clock enables
  • Show why an AND gate on a clock glitches and how a latch-based gating cell prevents it
  • Build a glitch-free switch between two clocks and check its pulse widths in simulation
  • Recognise generated clocks and the constraints that tell timing analysis about them

Before you start

On this page

Gate a 100 MHz clock with a plain AND gate and an enable from a flip-flop, and a counter on the gated clock counted 41 edges in 64 cycles where the enable allowed 28. A clock is not like other signals: each of its edges is an event for every flip-flop it reaches, so a pulse cut short is a wrong clock edge, not a wrong value for a moment.

RTL designers change clocks in four ways, and this lesson builds each one: slowing logic down with an enable, stopping a clock with a gating cell, switching between two clocks without a glitch, and making a slower clock from a faster one. Icarus Verilog 13.0 and Yosys 0.69 ran every circuit here, and every number comes from those runs.

Each extra clock is a domain to cross, so slow logic uses an enable

A clock reaches its flip-flops through a network of its own. On a chip, clock tree: The network of buffers and wires that carries a clock to every flip-flop of a chip so that its edges arrive at nearly the same time. FPGAs have dedicated global clock networks for the same job. synthesis builds a tree of buffers so that an edge arrives at every flip-flop at nearly the same time; in the open-source flow that is OpenROAD’s cts step. An FPGA has dedicated global clock networks for the same job, and AMD’s constraints guide recommends keeping look-up tables out of clock trees as much as possible (UG903). The flip-flops of one such network form one clock domain: The flip-flops clocked by one clock, or by clocks that have a fixed timing relationship to it. A signal that goes from one domain to another crosses domains and needs a synchronizer or a protocol., and timing analysis checks every path between two of them against that one clock.

A second clock is a second network and a second domain. Every signal between the two domains must then be synchronized, every path between them needs a timing constraint, and every crossing needs its own verification: the rest of this module is about exactly that work. The counters lesson measured the alternative on one slow counter:

One counter that steps every 16 cycles Clock nets in the netlist Signals to synchronize Clocks to declare
Clocked by bit 3 of a divider 2: clk_i clocks 4 flip-flops, div_q[3] clocks 4 every signal between the two groups the divider bit, as a second clock
Advanced by a clock enable: An input that decides whether a register loads a new value at a clock edge or keeps its value. Synthesis builds it as a multiplexer in front of the flip-flop, or a flip-flop with an enable pin. More in “Sequential logic, always_ff and nonblocking” 1: clk_i clocks all 8 none none

The enable keeps one domain because it is ordinary logic in front of each flip-flop’s D input; the clock is never touched. So the rule of RTL design is to keep one clock wherever logic only needs to act less often, and to change a clock itself for one of three reasons only: to save the power its edges cost, to choose between two sources, or to give a pin or a block a slower clock it really needs. Each of these has one safe circuit, and the rest of the lesson builds them.

Checkpoint

Check: Keeping one clock with enables

  1. Question 1 of 2 A status block must update its registers once every 1,000 cycles of a 100 MHz clock. What do you write?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: A counter on the 100 MHz clock whose terminal count enables the status registers

    Acting every Nth cycle is the job of a clock enable: the counter's terminal count enables the registers, and the netlist keeps one clock, as the counters lesson measured (clk_i clocks all 8 flip-flops).

  2. Question 2 of 2 Which of these does a second clock domain bring with it? Choose every one that applies.

    Choose every answer that is right.

    Show the answer: Question 2 of 2

    Answer:

    • Synchronizers on the signals that cross between the domains
    • Verification of each crossing
    • Timing constraints for the paths between the domains
    • A second clock network to build and balance

    A second clock costs a network, synchronizers, constraints and checks. None of them is needed when slow logic uses an enable on the clock it already has.

An AND gate on the clock cuts pulses whenever the enable changes

Stopping a clock is clock gating: Stopping the clock of a group of flip-flops while their enable is off, so that they spend no power on clock edges. It is done with a clock-gating cell, never with a plain AND gate on the clock.: the flip-flops behind the gate get no edges while their enable is off, so they spend no power on the clock. The obvious circuit is clk & en. clock_gate.sv has it as gate_and, beside the circuit of the next section, and tb_clock_gate.sv drives both with the same enable, which a flip-flop changes 1 ns after each rising edge, as any enable made on the same clock does:

Two clock gates, one enable, 64 cycles of a 100 MHz clock

hdl/clock_gate.sv

`timescale 1ns / 100ps
// Two clock gates for the same job: let clk through only in cycles where en is 1.
// en comes from a flip-flop clocked by clk, so it changes just after a rising edge.

// An AND gate: en reaches the gate whenever it changes, even in the middle of a pulse.
module gate_and (
    input  logic clk,
    input  logic en,
    output logic gclk
);
  assign gclk = clk & en;
endmodule

// A latch and an AND gate, the structure of an integrated clock-gating cell: the latch is
// open while clk is low and closed while it is high, so en can only change the gate's
// second input between pulses. (One assignment and no feedback: = and <= behave alike.)
module gate_latch (
    input  logic clk,
    input  logic en,
    output logic gclk
);
  logic en_held;
  always_latch
    if (!clk) en_held = en;
  assign gclk = clk & en_held;
endmodule

hdl/tb_clock_gate.sv

`timescale 1ns / 100ps
// Gates a 100 MHz clock with an enable from a flip-flop (1 ns clock-to-output delay), with
// both gates of clock_gate.sv. Prints a window of the waveforms (# is 1, _ is 0, one
// character per nanosecond), then counts the pulses of each gated clock, the edges a
// counter on it saw, and the pulses shorter than half a clock period.
module tb_clock_gate;
  logic clk = 0, en = 0;
  logic gclk_and, gclk_latch;
  always #5 clk = ~clk;

  gate_and   u_and   (.clk, .en, .gclk(gclk_and));
  gate_latch u_latch (.clk, .en, .gclk(gclk_latch));

  // The enable pattern: 64 cycles from a seeded xorshift generator, in runs of 1 to 4.
  int unsigned state = 32'd2463534242;
  function automatic int unsigned next_random();
    state ^= state << 13;
    state ^= state >> 17;
    state ^= state << 5;
    return state;
  endfunction

  logic pattern[64];
  initial begin
    int i, run;
    logic value;
    i = 0;
    value = 0;
    while (i < 64) begin
      run = next_random() % 4 + 1;
      for (int k = 0; k < run && i < 64; k++) pattern[i++] = value;
      value = !value;
    end
  end

  int cycle = 0;
  always @(posedge clk) begin
    en <= #1 pattern[cycle];
    cycle <= cycle + 1;
  end

  // What a counter on each gated clock sees, and the edges the enable allows: an edge k is
  // allowed when en was 1 during the cycle before it.
  int edges_and = 0, edges_latch = 0, allowed = 0;
  always @(posedge gclk_and) edges_and++;
  always @(posedge gclk_latch) edges_latch++;
  always @(posedge clk) if (en) allowed++;

  // Pulse widths of each gated clock.
  realtime rise_and, rise_latch;
  int pulses_and = 0, pulses_latch = 0, short_and = 0, short_latch = 0;
  realtime min_and = 1e9, min_latch = 1e9;
  always @(posedge gclk_and) rise_and = $realtime;
  always @(negedge gclk_and) begin
    pulses_and++;
    if ($realtime - rise_and < 5.0) short_and++;
    if ($realtime - rise_and < min_and) min_and = $realtime - rise_and;
  end
  always @(posedge gclk_latch) rise_latch = $realtime;
  always @(negedge gclk_latch) begin
    pulses_latch++;
    if ($realtime - rise_latch < 5.0) short_latch++;
    if ($realtime - rise_latch < min_latch) min_latch = $realtime - rise_latch;
  end

  // One character per nanosecond, from 0 to 80 ns.
  string row_clk = "", row_en = "", row_and = "", row_latch = "";
  initial begin
    #0.5;
    repeat (80) begin
      row_clk   = {row_clk,   clk        ? "#" : "_"};
      row_en    = {row_en,    en         ? "#" : "_"};
      row_and   = {row_and,   gclk_and   ? "#" : "_"};
      row_latch = {row_latch, gclk_latch ? "#" : "_"};
      #1;
    end
  end

  initial begin
    #642;
    $display("first 80 ns, one character per ns:");
    $display("clk         %s", row_clk);
    $display("en          %s", row_en);
    $display("clk & en    %s", row_and);
    $display("latch gate  %s", row_latch);
    $display("over 64 cycles, en allowed %0d edges", allowed);
    $display("AND gate:   %0d edges counted, %0d pulses shorter than 5 ns, shortest %.1f ns",
             edges_and, short_and, min_and);
    $display("latch gate: %0d edges counted, %0d pulses shorter than 5 ns, shortest %.1f ns",
             edges_latch, short_latch, min_latch);
    $finish;
  end
endmodule

Commands · hdl/gate_session.py

from session import run

# Icarus Verilog runs both clock gates of clock_gate.sv on the same enable for 64 cycles.
run("""
iverilog -g2012 -Wall -o gate.vvp tb_clock_gate.sv clock_gate.sv
vvp -n gate.vvp
""")

Output

# Icarus Verilog 13.0 (stable)
$ iverilog -g2012 -Wall -o gate.vvp tb_clock_gate.sv clock_gate.sv
$ vvp -n gate.vvp
first 80 ns, one character per ns:
clk         _____#####_____#####_____#####_____#####_____#####_____#####_____#####_____#####
en          ______________________________________________##############################____
clk & en    ______________________________________________####_____#####_____#####_____#____
latch gate  _______________________________________________________#####_____#####_____#####
over 64 cycles, en allowed 28 edges
AND gate:   41 edges counted, 25 pulses shorter than 5 ns, shortest 1.0 ns
latch gate: 28 edges counted, 0 pulses shorter than 5 ns, shortest 5.0 ns
tb_clock_gate.sv:91: $finish called at 6420 (100ps)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 gate_session.py

In the drawn window the enable rises at 46 ns and falls at 76 ns, both times while the clock is high. The AND gate passed each change straight into the clock: a 4 ns pulse at 46 ns, one cycle before the first edge the enable allowed, and a 1 ns pulse at 75 ns where the last pulse should have lasted 5 ns. Over 64 cycles that made 41 edges where the enable allowed 28, and 25 pulses shorter than half a period. In this zero-delay simulation every short pulse still counted as an edge; in silicon a pulse shorter than a flip-flop’s minimum pulse width may clock some flip-flops and not others, which is a glitch: A short, unwanted pulse on the output of combinational logic while its inputs change at slightly different times. It is over before the next clock edge, so it harms only logic that uses the signal without that clock. More in “Counters, LFSRs, PWM and clock enables” on a clock.

An AND gate as a clock gate

Wrong: assign gclk = clk & en; with en from a flip-flop on clk. Every rise of en added an early edge and every fall cut a pulse to 1 ns, as the run shows. Right: a clock-gating cell, or a clock enable on the flip-flops themselves, if (en) q <= d;, when only the logic has to stop.

A latch in front of the gate holds the enable while the clock is high

The cure is to let the gate’s enable change only while the clock is low, when the AND gate’s output is 0 whatever the enable does. A latch: A storage element that passes its input while its enable is on and holds its last value while the enable is off. A combinational block with a path that assigns nothing describes one. More in “Combinational logic with assign and always_comb” that is open while the clock is low and closed while it is high does exactly that. A latch and an AND gate together are a clock-gating cell: A standard cell that gates a clock without glitches: a latch, open while the clock is low, holds the enable, and an AND gate passes the clock only while the held enable is 1.: the behavioural model of sky130_fd_sc_hd__dlclkp, the clock gate of the SKY130 standard-cell library, is such a latch, enabled by the inverted clock, and such an AND gate. Step through gate_latch in the same run:

Interactive · step by step The latch holds the enable while the clock is high Each step is half a clock period. Watch the latch's held enable, and the gated clock below it.
The latch holds the enable while the clock is high, step 6 of 6. Showing en (0), clk (high), Latch (closed, holds 0), AND gate, Gated clock (low).closes it at 1en0clkhighLatchclosed, holds 0AND gateclk and held enableGated clocklow

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Edge 4. The clock rises and the latch closes, holding the enable it saw while the clock was low, 0. The gated clock stays low.
  2. 1 ns later. The enable's flip-flop changes en to 1 in the middle of the pulse. The latch is closed, so the AND gate still sees 0, where a plain AND gate would pass a 4 ns pulse.
  3. The clock falls. The clock goes low and the latch opens. The held enable becomes 1 while the AND gate's other input, the clock, is 0, so nothing reaches the gated clock.
  4. Edge 5. The clock rises with the held enable at 1, and the latch closes again. The gated clock carries a full 5 ns pulse.
  5. Edge 7, 1 ns later. Edges 6 and 7 passed full pulses too. 1 ns after edge 7 en falls, in the middle of the pulse. The latch is closed and still holds 1, so this pulse stays a full 5 ns, where the AND gate cut it to 1 ns.
  6. Edge 8. The latch took the 0 while the clock was low, so edge 8 is gated off. The enable was 1 for three cycles and the gated clock carried three full pulses, at edges 5, 6 and 7.

The latch gate passed exactly the 28 edges the enable allowed, and none of its pulses was shorter than 5 ns. Its first pulse came at edge 5, one cycle after the enable rose: an enable set in one cycle lets the next edge through, the same timing as an enable on a flip-flop.

You rarely draw this cell yourself. You write the enable, and an ASIC flow moves it into gating cells: the clockgate pass of Yosys “transforms each set of FFs sharing the same clock and enable signal into a clock-gating cell and a set of enable-less FFs”, which the next run shows on a bank of 8 registers:

Yosys moves the enable of 8 flip-flops into one SKY130 clock gate

hdl/bank.sv

// A bank of 8 registers that load together when en is 1, written with an enable.
module bank (
    input  logic       clk,
    input  logic       en,
    input  logic [7:0] d,
    output logic [7:0] q
);
  always_ff @(posedge clk)
    if (en) q <= d;
endmodule

hdl/cells.py

"""Counts the cells of each type in a Yosys JSON netlist.

Usage: python3 cells.py netlist.json"""
import json
import sys
from collections import Counter

for name, module in json.load(open(sys.argv[1]))["modules"].items():
    if module.get("attributes", {}).get("blackbox"):
        continue
    kinds = Counter(cell["type"] for cell in module["cells"].values())
    listed = ", ".join(f"{n} {kind}" for kind, n in sorted(kinds.items()))
    print(f"{sys.argv[1]}: {sum(kinds.values())} cells: {listed}")

Commands · hdl/gating_session.py

from session import run

# Yosys builds bank.sv, then its clockgate pass moves the enable of the 8 flip-flops into one clock-gating cell of
# the SKY130 library, sky130_fd_sc_hd__dlclkp_1, whose ports are GATE, CLK and GCLK.
run("""
yosys -q -p "read_verilog -sv bank.sv; synth -top bank; write_json before.json; clockgate -pos sky130_fd_sc_hd__dlclkp_1 GATE:CLK:GCLK; write_json after.json"
python3 cells.py before.json
python3 cells.py after.json
""")

Output

# Yosys 0.69
$ yosys -q -p "read_verilog -sv bank.sv; synth -top bank; write_json before.json; clockgate -pos sky130_fd_sc_hd__dlclkp_1 GATE:CLK:GCLK; write_json after.json"
$ python3 cells.py before.json
before.json: 8 cells: 8 $_DFFE_PP_
$ python3 cells.py after.json
after.json: 9 cells: 8 $_DFF_P_, 1 sky130_fd_sc_hd__dlclkp_1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 gating_session.py

Eight flip-flops with an enable became eight plain flip-flops and one sky130_fd_sc_hd__dlclkp_1. The cell has one timing rule of its own: the enable must reach the latch before the clock rises, which timing analysis checks with a clock-gating setup and hold check (set_clock_gating_check in OpenSTA).

Key idea

A clock may only be gated while it is low: a latch that is open while the clock is low holds the enable through each pulse, so the gated clock carries whole pulses or none, where the AND gate alone cut 25 of them short.

Checkpoint

Check: Why an AND gate on a clock glitches · The latch-based clock-gating cell

  1. Question 1 of 2 In tb_clock_gate.sv the enable rises 1 ns after a rising edge, while the clock is high. What does clk & en do in that cycle?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It rises 1 ns after the clock edge and gives a 4 ns pulse, an edge one cycle early

    An AND gate passes its inputs as they are. The enable becomes 1 in the middle of a high phase, so the gated clock rises then, 1 ns late, and falls with the clock 4 ns later: an extra, short edge.

  2. Question 2 of 2 When is the latch of a clock-gating cell open, and why then?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: While the clock is low, because then the AND gate's output is 0 whatever the enable does

    The cell's latch is transparent during the low half of the clock and opaque during the high half, which is the behaviour of SKY130's dlclkp: a latch on the inverted clock, then the AND gate.

A glitch-free switch lets go of one clock before it takes the other

Some blocks must run on one of two clocks: a slow crystal clock while a PLL starts, a test clock in place of the functional one. A plain multiplexer, sel ? clk_b : clk_a, switches the instant sel changes, wherever the two clocks are in their periods. clock_mux.sv has it as mux_plain, and a glitch-free clock switch: A circuit that moves its output from one clock to another without short pulses: it turns the old clock off while that clock is low, and only then turns the new one on while the new one is low. as mux_safe. The safe one gives each clock an enable of two flip-flops on that clock’s falling edge, so an enable changes only while its clock is low, and lets an enable rise only after the other one has fallen. These enables cross from one clock to the other, so they are synchronized, as Ginosar’s tutorial on synchronizers notes of every clock-switching signal. tb_clock_mux.sv switches between a 10 ns and a 26 ns clock 200 times at random moments and measures every high and low phase of both outputs:

Two clock switches, 200 switches between a 10 ns and a 26 ns clock

hdl/clock_mux.sv

`timescale 1ns / 100ps
// Two ways to switch between clk_a (sel = 0) and clk_b (sel = 1).

// A plain multiplexer: the output follows sel at once, wherever the two clocks are.
module mux_plain (
    input  logic clk_a,
    input  logic clk_b,
    input  logic sel,
    output logic clk_out
);
  assign clk_out = sel ? clk_b : clk_a;
endmodule

// A glitch-free switch. Each clock has an enable that changes only on that clock's falling
// edge, through two flip-flops, so it never changes while that clock is high; and an enable
// rises only after the other clock's enable has fallen, so the two clocks never overlap.
module mux_safe (
    input  logic rst_n,
    input  logic clk_a,
    input  logic clk_b,
    input  logic sel,
    output logic clk_out
);
  logic a1, a2, b1, b2;
  always_ff @(negedge clk_a or negedge rst_n)
    if (!rst_n) begin
      a1 <= 1'b0;
      a2 <= 1'b0;
    end else begin
      a1 <= !sel && !b2;
      a2 <= a1;
    end
  always_ff @(negedge clk_b or negedge rst_n)
    if (!rst_n) begin
      b1 <= 1'b0;
      b2 <= 1'b0;
    end else begin
      b1 <= sel && !a2;
      b2 <= b1;
    end
  assign clk_out = (clk_a && a2) || (clk_b && b2);
endmodule

hdl/tb_clock_mux.sv

`timescale 1ns / 100ps
// Measures every high and low phase of a clock while `measuring` is 1. A phase shorter than
// `shortest` is a pulse no flip-flop on that clock was designed for.
module phase_meter #(
    parameter realtime shortest = 5.0
) (
    input logic clk,
    input logic measuring
);
  realtime last = 0, min_high = 1e9, min_low = 1e9, max_low = 0;
  int short_high = 0, short_low = 0;
  always @(clk) begin
    if (measuring && last > 0) begin
      if (clk) begin  // a low phase just ended
        if ($realtime - last < shortest) short_low++;
        if ($realtime - last < min_low) min_low = $realtime - last;
        if ($realtime - last > max_low) max_low = $realtime - last;
      end else begin  // a high phase just ended
        if ($realtime - last < shortest) short_high++;
        if ($realtime - last < min_high) min_high = $realtime - last;
      end
    end
    last = $realtime;
  end
endmodule

// Switches between a 100 MHz clock (clk_a, 10 ns) and a 38.5 MHz clock (clk_b, 26 ns) at
// 200 seeded random moments, through both switches of clock_mux.sv, and measures every
// phase of each output. At the end clk_b stops while the output runs on it, and sel asks
// for clk_a.
module tb_clock_mux;
  logic clk_a = 0, clk_b = 0, sel = 0, rst_n = 0, measuring = 0;
  logic out_plain, out_safe;
  bit run_b = 1;
  always #5 clk_a = ~clk_a;
  initial begin
    #3.3;
    forever #13 if (run_b) clk_b = ~clk_b;
  end

  mux_plain u_plain (.clk_a, .clk_b, .sel, .clk_out(out_plain));
  mux_safe  u_safe  (.rst_n, .clk_a, .clk_b, .sel, .clk_out(out_safe));
  phase_meter m_plain (.clk(out_plain), .measuring);
  phase_meter m_safe  (.clk(out_safe),  .measuring);

  int unsigned state = 32'd88172645;
  function automatic int unsigned next_random();
    state ^= state << 13;
    state ^= state >> 17;
    state ^= state << 5;
    return state;
  endfunction

  realtime last_safe_edge = 0;
  always @(posedge out_safe) last_safe_edge = $realtime;

  // One switch drawn from 210 ns to 290 ns, one character per nanosecond.
  string r_sel = "", r_a = "", r_b = "", r_plain = "", r_safe = "";
  initial begin
    #210.5;
    repeat (80) begin
      r_sel   = {r_sel,   sel       ? "#" : "_"};
      r_a     = {r_a,     clk_a     ? "#" : "_"};
      r_b     = {r_b,     clk_b     ? "#" : "_"};
      r_plain = {r_plain, out_plain ? "#" : "_"};
      r_safe  = {r_safe,  out_safe  ? "#" : "_"};
      #1;
    end
  end

  initial begin
    #20 rst_n = 1;
    #197 sel = 1;
    #83;
    $display("sel rises at 217 ns; 210 to 290 ns, one character per ns:");
    $display("sel         %s", r_sel);
    $display("clk_a       %s", r_a);
    $display("clk_b       %s", r_b);
    $display("plain mux   %s", r_plain);
    $display("safe switch %s", r_safe);
    sel = 0;
    #100 measuring = 1;
    repeat (200) begin
      #(50 + next_random() % 400);
      sel = !sel;
    end
    #600 measuring = 0;
    $display("200 switches between a 10 ns and a 26 ns clock:");
    $display("plain mux:   %0d high and %0d low phases under 5 ns; shortest high %.1f ns, low %.1f ns",
             m_plain.short_high, m_plain.short_low, m_plain.min_high, m_plain.min_low);
    $display("safe switch: %0d high and %0d low phases under 5 ns; shortest high %.1f ns, low %.1f ns",
             m_safe.short_high, m_safe.short_low, m_safe.min_high, m_safe.min_low);
    $display("safe switch: longest low phase %.1f ns, while one clock hands over to the other",
             m_safe.max_low);
    // The handover needs both clocks: stop clk_b while the output runs on it, then ask for clk_a.
    if (!sel) begin
      sel = 1;
      #400;
    end
    wait (!clk_b);
    run_b = 0;
    #100 sel = 0;
    #2000;
    $display("clk_b stopped and sel = 0 at %.1f ns; the safe switch's last edge: %.1f ns; now: %.1f ns",
             $realtime - 2000, last_safe_edge, $realtime);
    $finish;
  end
endmodule

Commands · hdl/mux_session.py

from session import run

# Icarus Verilog switches between two clocks 200 times through both switches of clock_mux.sv.
run("""
iverilog -g2012 -Wall -o mux.vvp tb_clock_mux.sv clock_mux.sv
vvp -n mux.vvp
""")

Output

# Icarus Verilog 13.0 (stable)
$ iverilog -g2012 -Wall -o mux.vvp tb_clock_mux.sv clock_mux.sv
$ vvp -n mux.vvp
sel rises at 217 ns; 210 to 290 ns, one character per ns:
sel         _______#########################################################################
clk_a       _____#####_____#####_____#####_____#####_____#####_____#####_____#####_____#####
clk_b       #_____________#############_____________#############_____________#############_
plain mux   _____##_______#############_____________#############_____________#############_
safe switch _____#####_____#####______________________________________________#############_
200 switches between a 10 ns and a 26 ns clock:
plain mux:   71 high and 74 low phases under 5 ns; shortest high 0.3 ns, low 0.3 ns
safe switch: 0 high and 0 low phases under 5 ns; shortest high 5.0 ns, low 5.0 ns
safe switch: longest low phase 64.3 ns, while one clock hands over to the other
clk_b stopped and sel = 0 at 52003.0 ns; the safe switch's last edge: 51886.3 ns; now: 54003.0 ns
tb_clock_mux.sv:106: $finish called at 540030 (100ps)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 mux_session.py

The plain multiplexer made 71 high and 74 low phases shorter than 5 ns, the shortest 0.3 ns; in the drawn switch at 217 ns it cut a pulse of clk_a to 2 ns. The safe switch made none: its shortest phase was 5.0 ns, a half period of clk_a. Step through the drawn switch to see where its time goes:

Interactive · step by step The safe switch lets go of clk_a before it takes clk_b Each step is a clock edge of the run. Watch the two enables and the output under them.
The safe switch lets go of clk_a before it takes clk_b, step 6 of 6. Showing sel (1 picks clk_b), clk_a's enable (0: off), clk_b's enable (1: on), clk_out (follows clk_b).sel1 picks clk_bclk_a's enable0: offclk_b's enable1: onclk_outfollows clk_bclk_b

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Running on clk_a. clk_a's enable is 1 and clk_b's is 0, so clk_out is clk_a. Each enable is two flip-flops on the falling edge of its own clock, and each holds the other off.
  2. 217 ns, sel rises. sel asks for clk_b 2 ns into a high phase of clk_a. Nothing changes at once; a plain multiplexer would have switched here and cut that pulse to 2 ns.
  3. 220 ns and 230 ns. At two falling edges of clk_a, its enable's flip-flops take the 0. The enable falls at 230 ns, while clk_a is low, so the pulse from 225 ns to 230 ns was the last one and it was whole.
  4. 237.3 ns. At a falling edge of clk_b, its first flip-flop sees sel at 1 and clk_a's enable at 0, and takes the 1. Until clk_a's enable had fallen, it could not.
  5. 263.3 ns. At the next falling edge of clk_b, the enable rises, while clk_b is low. clk_out is still low.
  6. 276.3 ns, running on clk_b. clk_b rises and clk_out carries its first full pulse. The output was low for 46.3 ns, from 230 ns, and no pulse was cut.

The price is a gap: the output stays low while one enable falls and the other rises, 46.3 ns in the drawn switch and 64.3 ns at most in the 200. The design also needs both clocks running. At the end of the run clk_b stops while the output runs on it, and sel asks for clk_a: clk_b’s enable can only fall on a falling edge of clk_b, which never comes, so the safe switch gives no edge at all in the 2,000 ns that follow.

Switching to, or away from, a clock that is not running

Wrong: switching the select while one of the clocks is stopped, for example before a PLL has locked. The switch waits for edges of both clocks and hangs with its output low. Right: switch only while both clocks run, or give the switch a way to drop a dead clock that the rest of the design controls.

Checkpoint

Check: Switching clocks without glitches

  1. Question 1 of 2 sel changes from clk_a to clk_b 2 ns into a high phase of clk_a, while clk_b is low. What does sel ? clk_b : clk_a put on its output?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: A 2 ns pulse, then low until clk_b next rises

    A plain multiplexer switches at once, so the output takes whatever level the new clock has at that moment. In the run that made 71 high and 74 low phases under 5 ns in 200 switches.

  2. Question 2 of 2 A colleague shortens mux_safe's gap by letting clk_b's enable rise at the same falling edge of clk_b at which sel is first seen, without waiting for clk_a's enable to fall. What can go wrong?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Both enables can be 1 at once, so the output is clk_a OR clk_b and carries pulses of neither clock

    The safe switch makes the old clock's enable fall, while that clock is low, before the new clock's enable may rise, while it is low. Remove the wait and both enables can be 1 together.

Divided and switched clocks are generated clocks, and timing must be told

Sometimes a slower clock is the point: an output pin that must toggle at a third of the system clock, or a block that must run at a lower rate. A counter’s terminal count gives one-third of the frequency, high for one cycle in three. clock_div3.sv also gets a 50 % duty cycle: The share of each period that a clock or a pulse train is high: 50 % for a symmetric clock, 33.3 % for a divide-by-3 counter output that is high for one cycle in three., which needs both clock edges: q_pos is 1 for one cycle in three, q_neg copies it on the falling edge, half a cycle later, and their OR is 1 for one and a half cycles in three. Both outputs come from flip-flops and their OR, never from logic that can glitch on the way:

Divide by 3: a 33 % output and a 50 % output

hdl/clock_div3.sv

`timescale 1ns / 100ps
// Divides clk by 3. q_pos is a flip-flop on the rising edge that is 1 for one cycle in
// three; q_neg copies it on the falling edge, half a cycle later. Their OR is 1 for one and
// a half cycles in three: a 50 % duty cycle. q_pos alone is the 33 % divider.
module clock_div3 (
    input  logic clk,
    input  logic rst_n,
    output logic clk_div3,
    output logic clk_div3_33
);
  logic [1:0] count;
  logic q_pos, q_neg;
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) begin
      count <= 2'd0;
      q_pos <= 1'b0;
    end else begin
      count <= (count == 2'd2) ? 2'd0 : count + 2'd1;
      q_pos <= (count == 2'd2);
    end
  always_ff @(negedge clk or negedge rst_n)
    if (!rst_n) q_neg <= 1'b0;
    else q_neg <= q_pos;
  assign clk_div3    = q_pos | q_neg;
  assign clk_div3_33 = q_pos;
endmodule

hdl/tb_clock_div3.sv

`timescale 1ns / 100ps
// Runs clock_div3 on a 100 MHz clock and measures the period and the high time of both
// outputs over 10 periods, after reset.
module tb_clock_div3;
  logic clk = 0, rst_n = 0, div, div33;
  always #5 clk = ~clk;
  clock_div3 dut (.clk, .rst_n, .clk_div3(div), .clk_div3_33(div33));

  realtime rise50 = 0, high50 = 0, period50 = 0, rise33 = 0, high33 = 0, period33 = 0;
  int n50 = 0, n33 = 0, h50 = 0, h33 = 0;
  always @(posedge div) begin
    if (rise50 > 0) begin
      period50 += $realtime - rise50;
      n50++;
    end
    rise50 = $realtime;
  end
  always @(negedge div)
    if (rise50 > 0) begin
      high50 += $realtime - rise50;
      h50++;
    end
  always @(posedge div33) begin
    if (rise33 > 0) begin
      period33 += $realtime - rise33;
      n33++;
    end
    rise33 = $realtime;
  end
  always @(negedge div33)
    if (rise33 > 0) begin
      high33 += $realtime - rise33;
      h33++;
    end

  string r_clk = "", r_50 = "", r_33 = "";
  initial begin
    #40.5;
    repeat (60) begin
      r_clk = {r_clk, clk ? "#" : "_"};
      r_50  = {r_50,  div ? "#" : "_"};
      r_33  = {r_33,  div33 ? "#" : "_"};
      #1;
    end
  end

  initial begin
    #12 rst_n = 1;
    @(posedge div);
    repeat (10) @(posedge div);
    $display("40 to 100 ns, one character per ns:");
    $display("clk        %s", r_clk);
    $display("clk_div3   %s", r_50);
    $display("33 %% out   %s", r_33);
    $display("clk_div3:    period %.1f ns, high %.1f ns, duty %.1f %%", period50 / n50, high50 / h50,
             100.0 * (high50 / h50) / (period50 / n50));
    $display("33 %% output: period %.1f ns, high %.1f ns, duty %.1f %%", period33 / n33, high33 / h33,
             100.0 * (high33 / h33) / (period33 / n33));
    $finish;
  end
endmodule

Commands · hdl/div_session.py

from session import run

# Icarus Verilog runs the divide-by-3 of clock_div3.sv and measures both of its outputs.
run("""
iverilog -g2012 -Wall -o div.vvp tb_clock_div3.sv clock_div3.sv
vvp -n div.vvp
""")

Output

# Icarus Verilog 13.0 (stable)
$ iverilog -g2012 -Wall -o div.vvp tb_clock_div3.sv clock_div3.sv
$ vvp -n div.vvp
40 to 100 ns, one character per ns:
clk        _____#####_____#####_____#####_____#####_____#####_____#####
clk_div3   ##########_______________###############_______________#####
33 % out   #####____________________##########____________________#####
clk_div3:    period 30.0 ns, high 15.0 ns, duty 50.0 %
33 % output: period 30.0 ns, high 10.0 ns, duty 33.3 %
tb_clock_div3.sv:59: $finish called at 3350 (100ps)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 div_session.py

Both outputs have a 30 ns period, three cycles of clk. clk_div3 is high for 15.0 ns, a 50.0 % duty cycle, and the counter’s own output for 10.0 ns, 33.3 %. Each is a generated clock: A clock that logic makes from another clock, such as a divider's output or a clock switch's output. Timing analysis is told about it with create_generated_clock, so that paths between it and its source are timed.: timing analysis must know it is clk divided by three, or it cannot time the paths between the two. OpenSTA’s create_generated_clock describes it from the source clock’s edges, numbered from 1: the 50 % output rises at edge 1 and falls at edge 4 of clk, -edges {1 4 7}, and the 33 % one falls at edge 3, -edges {1 3 7}.

The switch of the last section puts two clocks on one net, and timing analysis traces both through it: AMD’s guide notes that Vivado propagates every incoming clock through such a multiplexer. They can never be there at the same time, so they are declared exclusive, with set_clock_groups -physically_exclusive or -logically_exclusive. When the two clocks also have timing paths between them elsewhere in the design, AMD’s timing wizard declares generated copies of them on the switch’s output and makes only the copies exclusive. A clock that passes a gating cell stays the same clock, delayed by the cell, and needs no new declaration.

Checkpoint

Check: Generated clocks and their constraints

  1. Question 1 of 2 clock_div3.sv's 50 % output rises at a rising edge of clk and falls one and a half periods later. Which -edges list describes it to create_generated_clock?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: {1 4 7}

    Edges are numbered from 1 along the source clock, rising and falling in turn. Rising at 1, falling at 4 and rising at 7 is a 3-period clock that is high for 1.5 periods, as the run measured: 30 ns and 15.0 ns.

  2. Question 2 of 2 clk_a and clk_b both reach the flip-flops behind mux_safe. How should timing analysis treat paths between them?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Declare them exclusive with set_clock_groups, because they are never on the net at the same time

    Timing tools carry every clock through a multiplexer, so both are on the net in the analysis. They cannot both be there in hardware, which -physically_exclusive or -logically_exclusive says.

Choosing the gentlest change to a clock

The five circuits of this lesson trade a new clock, short pulses, power and timing work against each other. Answer two questions about a block of your own and the table marks what fits:

Interactive · answer and compare Which change to the clock does your logic need? Answer two questions about your logic. The table marks the ways that fit and says why the others do not.
What does the logic need from its clock?
Where do the enable or the select come from?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Five ways to slow, stop, switch or divide a clock, against what each one costs
Way New clock Short pulses Clock power Timing work
Clock enable Built from: a multiplexer at each D input Good none: every flip-flop stays on one clock Good none: the clock is not touched Poor the clock still reaches every flip-flop at every edge Good nothing beyond the enable's own paths
Clock-gating cell Built from: a latch and an AND gate Good none: the same clock, one cell later Good none in the 64 cycles of the run Good the gated flip-flops get no edges while off Mixed a clock-gating check on the enable at the cell
AND gate on the clock Built from: one gate Good none: the same clock Poor 25 short pulses and 13 extra edges in 64 cycles Good the same saving as the cell Poor no check makes an enable that changes after the edge safe
Glitch-free switch Built from: two enables of two flip-flops Mixed its output is one of two clocks, never both Good none under 5 ns in 200 switches Mixed not what it is for Mixed two clocks on one net, declared exclusive
Divided clock Built from: a counter and two flip-flops Poor a second clock with crossings to plan Good from flip-flops: 50.0 % duty and no glitch Mixed its logic is clocked less often Mixed create_generated_clock with its edges
How the answers decide
  • “What does the logic need from its clock?” To act only every Nth cycle: rules out Glitch-free switch and Divided clock. Logic that acts every Nth cycle needs no second clock; an enable on the same clock does it and adds no domain.
  • “What does the logic need from its clock?” To stop for long stretches: rules out Glitch-free switch and Divided clock and adds a caveat to Clock enable. To save the power of the clock itself the gated flip-flops must stop seeing edges; an enable stops only their work.
  • “What does the logic need from its clock?” A slower clock for a pin or block: rules out Clock enable, Clock-gating cell and Glitch-free switch. A pin or a block that needs a slower clock needs a real one, divided by flip-flops and declared as a generated clock.
  • “What does the logic need from its clock?” One of two clock sources: rules out Clock enable, Clock-gating cell and Divided clock. Choosing between two sources takes a switch that stops one clock while it is low before it starts the other.
  • “Where do the enable or the select come from?” A flip-flop on the same clock: rules out AND gate on the clock. An enable from a flip-flop on the same clock changes just after the rising edge, while the clock is high.
  • “Where do the enable or the select come from?” Another clock domain or software: rules out AND gate on the clock and adds a caveat to Clock-gating cell and Glitch-free switch. An enable from another domain changes at any moment; synchronize it to the clock first, or an edge is cut.

In short: an enable whenever logic only has to act less often; a gating cell, written as an enable and inserted by the flow, when the clock’s own power matters; a glitch-free switch between two sources that both run; a divider of flip-flops, declared as a generated clock, when a slower clock is the point; and never an AND gate or a plain multiplexer on a clock.

Checkpoint

Check: Choosing how to change a clock

  1. One question A radio block sits idle for most of each second, and its clock tree is a large part of the chip's power. Its enable comes from a register on the same clock. What fits best?

    Choose one answer.

    Show the answer: One question

    Answer: Write the enable in RTL and let the flow insert a clock-gating cell in front of the block's clock

    Clock power is saved only when the clock stops at the flip-flops, and the safe way to stop it is a clock-gating cell. An enable written in RTL is what the flow turns into one.

Practise: count the edges of two gated clocks

The exercise predicts what the run of the AND-gate section counted, without a simulator: the edges and the short pulses of both gates for any enable pattern. Its first sample test replays the 64 cycles of tb_clock_gate.sv, which gave 28, 41 and 25.

Exercise · Medium · Python

Count the edges of two gated clocks

Predict what the two clock gates of clock_gate.sv do with an enable, without simulating them.

gated_edges(en) gets the enable cycle by cycle, as tb_clock_gate.sv drives it: en[k] is its value from 1 ns after rising edge k of the 10 ns clock until 1 ns after edge k + 1. Before edge 0 the enable is 0. The clock is high for the first 5 ns after each rising edge.

Return a dictionary with three counts over edges 0 to len(en) - 1:

  • "latch_edges": the rising edges of the latch gate's clock;
  • "and_edges": the rising edges of clk & en;
  • "and_short": the pulses of clk & en shorter than 5 ns.

The sample tests replay the lesson's 64 cycles, which gave 28, 41 and 25 in the simulation, and a few short patterns.

Starter code · gates.py

def gated_edges(en):
    """Counts the rising edges and short pulses of the two gated clocks of clock_gate.sv."""
    latch_edges = and_edges = and_short = 0
    for k in range(len(en)):
        # One clock pulse: rising edge k, high for 5 ns.
        if en[k]:
            latch_edges += 1
            and_edges += 1
    return {"latch_edges": latch_edges, "and_edges": and_edges, "and_short": and_short}
The sample tests · test_gates.py
from gates import gated_edges


def lesson_pattern():
    """The 64 enable values of tb_clock_gate.sv: runs of 1 to 4 cycles from its xorshift generator."""
    state = 2463534242

    def next_random():
        nonlocal state
        state ^= (state << 13) & 0xFFFFFFFF
        state ^= state >> 17
        state ^= (state << 5) & 0xFFFFFFFF
        return state

    pattern, value = [], 0
    while len(pattern) < 64:
        run = next_random() % 4 + 1
        pattern += [value] * min(run, 64 - len(pattern))
        value = 1 - value
    return pattern


def test_the_lessons_64_cycles():
    """the simulation counted 28 latch-gate edges, 41 AND-gate edges and 25 short AND-gate pulses"""
    assert gated_edges(lesson_pattern()) == {"latch_edges": 28, "and_edges": 41, "and_short": 25}


def test_enable_never_on():
    """an enable that stays 0 lets no edge through either gate"""
    assert gated_edges([0, 0, 0, 0, 0]) == {"latch_edges": 0, "and_edges": 0, "and_short": 0}


def test_enable_on_from_the_start():
    """the enable rises 1 ns after edge 0: the AND gate makes a 4 ns pulse there, the latch gate waits for edge 1"""
    assert gated_edges([1, 1, 1, 1]) == {"latch_edges": 3, "and_edges": 4, "and_short": 1}


def test_one_cycle_of_enable():
    """one cycle of enable: the latch gate passes one full pulse, the AND gate makes two short ones"""
    assert gated_edges([0, 1, 0, 0]) == {"latch_edges": 1, "and_edges": 2, "and_short": 2}
A hint

Look at one clock pulse at a time. At rising edge k the AND gate still sees the old enable, en[k - 1], for 1 ns, then the new one, en[k], for 4 ns. The latch gate sees only the enable it held while the clock was low before edge k, which is en[k - 1].

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Then practise on enables, gates, switches and generated clocks. The questions start where your answers have been weakest so far:

Practice that adapts to you

Practise this lesson

14 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 14 What is a clock domain?

    Choose one answer.

    Show the answer: Question 1 of 14

    Answer: The flip-flops clocked by one clock, or by clocks with a fixed timing relationship to it

    A clock domain is defined by its clock. Signals inside it are timed against that clock; signals that leave it cross to another domain.

  2. Question 2 of 14 A UART receiver on a 48 MHz clock must sample its input 16 times per bit at 115,200 baud. How should the sampling run?

    Choose one answer.

    Show the answer: Question 2 of 14

    Answer: On the 48 MHz clock, with an enable pulse from a counter at 16 × 115,200 a second

    A rate inside one domain comes from an enable: a counter on the system clock pulses once per sample, and the receiver acts only in those cycles.

  3. Question 3 of 14 Why does clk & en glitch when en comes from a flip-flop on clk?

    Choose one answer.

    Show the answer: Question 3 of 14

    Answer: The flip-flop changes en just after the rising edge, while clk is high, and the gate passes the change into the clock

    An enable made on the same clock always changes a clock-to-output delay after the rising edge, inside the high phase. An AND gate turns that into a pulse that starts or ends early.

  4. Question 4 of 14 The enable of tb_clock_gate.sv takes the values 0, 1, 1, 0 in four cycles, each set 1 ns after a rising edge, starting from 0. How many pulses of clk & en in those four cycles are shorter than 5 ns?

    Type a number.

    A hint

    A pulse is short in a cycle where the enable changes.

    Show the answer: Question 4 of 14

    Answer: 2 pulses

    The enable changes in the second cycle (0 to 1: a 4 ns pulse) and in the fourth (1 to 0: a 1 ns pulse). In the third cycle it stays 1 and the pulse is whole.

  5. Question 5 of 14 The enable rises 1 ns after edge 4. At which edge does the latch gate's clock carry its first pulse?

    Choose one answer.

    Show the answer: Question 5 of 14

    Answer: Edge 5

    An enable set in one cycle lets the next edge through: the latch passes it during the low half, holds it through edge 5, and the gate passes that pulse whole.

  6. Question 6 of 14 A clock-gating cell has passed every simulation, but timing analysis reports a violation of its clock-gating check. What does that mean?

    Choose one answer.

    Show the answer: Question 6 of 14

    Answer: The enable reaches the cell's latch too close to the rising edge, so the cell may take the wrong value for that pulse

    A gating cell is safe only if its enable settles before the clock rises, which is what timing analysis checks (set_clock_gating_check in OpenSTA). A path that is too slow there needs fixing like any setup violation.

  7. Question 7 of 14 What did the plain multiplexer do in 200 switches between the 10 ns and the 26 ns clock?

    Choose one answer.

    Show the answer: Question 7 of 14

    Answer: It made 71 high and 74 low phases shorter than 5 ns, the shortest 0.3 ns

    A plain multiplexer switches at a random point of both clocks' periods, so the output gets phases of any length: 145 phases under 5 ns in the run.

  8. Question 8 of 14 Why does mux_safe's output stay low for a while during a switch?

    Choose one answer.

    Show the answer: Question 8 of 14

    Answer: The old clock's enable must fall at its own falling edge before the new clock's enable may rise at the new clock's falling edges

    The gap is the interlock at work: old clock off while it is low, then new clock on while it is low, each through two flip-flops. Its length depends on both clocks' periods.

  9. Question 9 of 14 A board must switch its core from a 25 MHz crystal clock to a PLL clock right after power-up, before the PLL has locked. What happens with mux_safe if the select changes at once?

    Choose one answer.

    Show the answer: Question 9 of 14

    Answer: clk_a's enable falls, but the PLL clock has no falling edges yet, so the output stays low until it starts

    The safe switch needs edges of both clocks: falling edges of the old one to let go, falling edges of the new one to take hold. With the new clock stopped it waits with its output low, as the run showed when clk_b stopped.

  10. Question 10 of 14 Why must timing analysis be told about a divided clock with create_generated_clock?

    Choose one answer.

    Show the answer: Question 10 of 14

    Answer: So that it knows the clock's period and edges relative to its source and can time paths between the two

    A generated clock is described from its source, by a division factor or by the source edges it uses, so timing analysis can work out every edge of both clocks.

  11. Question 11 of 14 clock_div3.sv runs on a clock of 8 ns instead of 10 ns. For how long is its 50 % output high in each period?

    Type a number.

    A hint

    The output is high for one and a half periods of the input clock.

    Show the answer: Question 11 of 14

    Answer: 12 ns

    The output's period is three input periods, 24 ns, and it is high for 1.5 of them: 12 ns, half the period.

  12. Question 12 of 14 Two clocks reach the same flip-flops through a clock switch. Why are they declared exclusive instead of left as two related clocks?

    Choose one answer.

    Show the answer: Question 12 of 14

    Answer: They are never on the net at the same moment, so a path launched by one and captured by the other cannot happen

    A switch passes one clock at a time, so the two are mutually exclusive on its output, which set_clock_groups with -physically_exclusive or -logically_exclusive tells the tool.

  13. Question 13 of 14 An external chip needs a 25 MHz clock from your 100 MHz design. Which way fits?

    Choose one answer.

    Show the answer: Question 13 of 14

    Answer: A divider of flip-flops, declared with create_generated_clock

    When a slower clock is the point, divide with flip-flops so that the output is clean, and declare it so that timing analysis knows it.

  14. Question 14 of 14 Which two circuits from the lesson never belong on a clock?

    Choose one answer.

    Show the answer: Question 14 of 14

    Answer: An AND gate with an enable, and a plain multiplexer

    Logic on a clock is safe only when its control changes while the clock cannot be affected, which the latch of the gating cell and the falling-edge enables of the switch ensure; a bare AND gate or multiplexer does not.

Interview questions

Warm-up (fresher): what is an integrated clock-gating cell, and why does it contain a latch?

It is a standard cell that stops a clock for the flip-flops behind it while their enable is 0, so they spend no power on clock edges. Inside are a latch and an AND gate. The latch is open while the clock is low and closed while it is high, so an enable that changes during a clock pulse waits until the clock has fallen; the AND gate then passes whole pulses or nothing. Without the latch, an enable from a flip-flop on the same clock changes just after the rising edge and the AND gate cuts or adds pulses: 25 short pulses in the lesson’s 64 cycles, against none with the latch. In RTL you write the enable, and the flow inserts the cell.

Two harder questions follow, on moving a running chip to another clock and on a clock gated by a bare AND gate. For each, draw the clocks and their enables over a few cycles before you look at the first step:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    A chip boots on a 25 MHz crystal clock and must move its core to a 400 MHz PLL clock once the PLL locks, without stopping the software. Design the switch, explain why a plain multiplexer is unsafe, and say what can make your switch hang.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    In a code review you find assign gclk = clk & en; where en comes from a flip-flop on clk and gclk clocks 64 registers. The simulations pass. Is it safe, what would you measure to convince the author, and what do you change for an ASIC and for an FPGA?

    Model answer, Pro. First step and follow-ups

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. Why does a design keep as few clocks as it can?

    Each extra clock is another network and clock domain: every signal between domains must be synchronized, every path between them needs a timing constraint, and every crossing needs its own verification.

  2. Why does assign gclk = clk & en; misbehave when en is registered on the same clock?

    en changes just after the rising edge, while the clock is high, so the gate passes each change into the clock: an early edge when en rises and a cut pulse when it falls. The run counted 41 edges where 28 were allowed.

  3. What is inside a clock-gating cell, and why?

    A latch that is open while the clock is low, and an AND gate. The enable can then change only while the clock is low, so the gated clock carries whole pulses or none.

  4. How does a clock-gating cell usually get into an ASIC design?

    The RTL writes an enable and the flow moves it into gating cells: Yosys's clockgate pass turned eight enabled flip-flops into eight plain ones and one sky130_fd_sc_hd__dlclkp_1.

  5. How does a glitch-free clock switch avoid short pulses, and what does it cost?

    Each clock has an enable of two flip-flops on its falling edge, and one enable may rise only after the other has fallen, so the output lets go of one clock before taking the other. It costs a gap with the output low.

  6. Why can a glitch-free clock switch hang?

    Its old clock's enable can fall only on that clock's falling edge. If that clock has stopped, the edge never comes and the output gives no edge at all, so switch only while both clocks run.

  7. How is a 50 % duty clock at a third of clk declared to timing analysis?

    As a generated clock from the source's edges, numbered from 1: create_generated_clock with -edges {1 4 7}, rising at edge 1 and falling at edge 4 of clk.

  8. How are two clocks that share one net through a switch declared?

    As exclusive, with set_clock_groups -physically_exclusive or -logically_exclusive, because they can never be on the net at the same time.

Key takeaways

  • Every extra clock is a domain with crossings, constraints and checks of its own, so logic that only needs to act less often uses a clock enable and keeps one clock.
  • An AND gate on a clock turns every change of an enable from the same clock into a short pulse or an extra edge: 41 edges where 28 were allowed in the lesson’s run.
  • A clock-gating cell holds the enable in a latch that is open only while the clock is low, so it passes whole pulses or none; you write the enable and the flow inserts the cell.
  • A glitch-free switch turns the old clock off while it is low, then turns the new one on while it is low; it pays with a gap in the output and needs both clocks running.
  • Divided and switched clocks are generated clocks: declare them from their source’s edges with create_generated_clock, and declare two clocks that share a net through a switch as exclusive.

Terms in this lesson

clock domain
The flip-flops clocked by one clock, or by clocks that have a fixed timing relationship to it. A signal that goes from one domain to another crosses domains and needs a synchronizer or a protocol.
clock gating
Stopping the clock of a group of flip-flops while their enable is off, so that they spend no power on clock edges. It is done with a clock-gating cell, never with a plain AND gate on the clock.
clock tree
The network of buffers and wires that carries a clock to every flip-flop of a chip so that its edges arrive at nearly the same time. FPGAs have dedicated global clock networks for the same job.
clock-gating cell
A standard cell that gates a clock without glitches: a latch, open while the clock is low, holds the enable, and an AND gate passes the clock only while the held enable is 1.
duty cycle
The share of each period that a clock or a pulse train is high: 50 % for a symmetric clock, 33.3 % for a divide-by-3 counter output that is high for one cycle in three.
generated clock
A clock that logic makes from another clock, such as a divider's output or a clock switch's output. Timing analysis is told about it with create_generated_clock, so that paths between it and its source are timed.
glitch-free clock switch
A circuit that moves its output from one clock to another without short pulses: it turns the old clock off while that clock is low, and only then turns the new one on while the new one is low.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.