Skip to content

RTL Design Patterns · Chapter 3 · Counters, Timers & Pulse Generators

Clock Dividers & Timers

A board has one fast oscillator, but the design needs many slower time bases: an LED blink, a baud tick, a periodic interrupt, a watchdog. The tempting move, and one of the most damaging mistakes in RTL, is to divide the clock by counting and wire the divided output as a clock into the slow logic. It works in simulation and fails in silicon, because a flip-flop output used as a clock is a new, unanalyzed clock domain with skew and no synchronizer. The right pattern is different: in RTL you do not make new clocks, you make clock-enables. A divide-by-N is a mod-N counter that pulses a one-cycle tick every N cycles, and the slow logic runs on the same clock but advances only when tick is high. This lesson builds clock-enable dividers, the toggle-flop divider, and one-shot and periodic timers, verified in SystemVerilog, Verilog, and VHDL.

Intermediate16 min readRTL Design PatternsClock DividerClock EnableTimerWatchdogClock Domain

Chapter 3 · Section 3.5 · Counters, Timers & Pulse Generators

1. The Engineering Problem

Your board has exactly one crystal. It arrives as a single clock — say 100 MHz — and every flop in your design toggles off it. But nothing your product actually does happens at 100 MHz. You need to blink a status LED at 1 Hz. You need a serial port to sample at 115200 baud. You need a periodic interrupt every millisecond so software can schedule work. You need a watchdog that resets the chip if firmware goes quiet for 30 seconds. Every one of these is a slower time base derived from the one fast clock you were given, and every design you will ever build has a fistful of them.

There are really two shapes of need here. The first is periodic events at a slower rate: a 1 Hz blink is a divide-by-100,000,000; a 115200-baud tick is a divide by roughly 868; a 1 ms interrupt on a 100 MHz clock is a divide-by-100,000. The second is elapsed-time measurement: a timeout that fires 500 µs after it is armed, a watchdog that must be fed every N cycles or it bites, a one-shot delay that pulses once and stops. The first is a frequency problem, the second is a duration problem, and — the point of this page — they are the same circuit pointed in two directions: a counter that reaches a programmed value and does something on the cycle it gets there.

The trap is in how you get from "I need something slower" to hardware. The instinct that ruins designs is to take the phrase "divide the clock" literally: count the fast clock, and when the count reaches its terminal value toggle a flip-flop and use that flip-flop's output as the clock for the slow logic. In an RTL simulator this looks perfect — the divided signal ticks at the right rate, the slow flops update on its edges, the waveform is beautiful. In silicon it is a latent bug: that divided flop output is now a clock with skew relative to the source clock, the boundary between the two is an unanalyzed clock-domain crossing, and static timing analysis never even sees the path because it does not know that net is a clock. It passes simulation, passes STA, and fails intermittently on hardware — the worst possible failure profile.

the-need.v — one fast clock in, many slow time bases needed
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // One oscillator feeds every flop:
   input wire clk;                         // 100 MHz — the ONLY clock
 
   // The system needs slower time bases derived from it:
   //   1 Hz LED blink        => divide by 100_000_000
   //   115200 baud tick      => divide by ~868
   //   1 ms periodic tick    => divide by 100_000
   //   30 s watchdog timeout  => count 3_000_000_000 cycles
   //   a 500 us one-shot     => count 50_000 cycles, fire once
 
   // THE DAMAGING INSTINCT — divide, then use the divided flop AS a clock:
   //   reg clk_div;
   //   always @(posedge clk) if (count == N-1) clk_div <= ~clk_div;
   //   always @(posedge clk_div) slow_reg <= ...;   // <-- NEW clock domain, skew, unanalyzed
 
   // THE PATTERN THIS PAGE BUILDS — one clock, generate an ENABLE (tick):
   //   the slow logic stays on clk and advances only on the cycles tick==1.

2. Mental Model

3. Pattern Anatomy

The family has three members — the clock-enable divider, the toggle-flop 50%-duty divider, and the loadable timer — plus the anti-pattern that motivates the whole approach. Each is a small structure over one counter.

The clock-enable divider (mod-N → one-cycle tick). This is the 3.2 mod-N counter with its wrap pulse reinterpreted as a divided enable. A WIDTH-bit count register advances every source-clock cycle; an equality comparator fires when count == N-1; on that cycle tick goes high for exactly one clock and the counter wraps to 0. The tick is the deliverable: a clean, registered, one-cycle strobe at f_clk / N. Downstream slow logic consumes it as a clock-enable — a register that updates only when tick is high (the 2.2 pattern). Nothing here is a new clock; tick is data that happens to mean "advance now."

The /2^k toggle-flop divider (50% duty). Sometimes you genuinely want a symmetric square wave at a divided rate — a 50%-duty divided clock signal to drive off-chip or to feed a clock-management cell — not a one-cycle strobe. The classic structure is a toggle flip-flop: a flop whose output inverts every time it is enabled. Chain the enable through a divider and the output is a divide-by-2N square wave with a 50% duty cycle. A single toggle flop clocked every cycle is a divide-by-2 with perfect 50% duty; k of them in series give /2^k. The crucial nuance: an even integer divide with 50% duty is easy (toggle at the half-period), but an odd integer divide with a true 50% duty cannot be made from a single edge — it requires using both the rising and falling edges of the source clock (two toggle structures, one per edge, combined), because half of an odd number of cycles is not a whole cycle. Any time you see "divide by an odd number, exactly 50% duty," expect a both-edges design.

The timer (loadable down-counter, one-shot vs periodic). A timer is a counter that measures a duration. Its structure: a loadable count register (2.2's load semantics — write a start value with a load strobe), a decrement each cycle (or each divider tick), and a comparator that detects the count reaching zero and raises timeout for one cycle. Two modes ride on top of that atom, and they differ only in what happens at zero. In one-shot mode the timer fires timeout once and then stops (holds at zero, disarmed) until it is reloaded — a single delayed pulse. In periodic (auto-reload) mode, on the cycle it hits zero it reloads the period register back into the count and keeps running, so timeout becomes a recurring strobe at a fixed interval — this is exactly how a periodic-interrupt timer or a baud generator's coarse tick is built. A watchdog is a periodic timer whose timeout triggers a reset unless software reloads it (feeds it) before it expires.

The anti-pattern — a divided flop used AS a clock. The structure to recognize and reject: an always @(posedge clk_div) block, where clk_div is a counter bit or a divided toggle-flop output generated in RTL. This introduces a second clock domain that (1) has skewclk_div arrives through logic and routing, not the balanced clock tree, so its edge is uncertain relative to clk; (2) is an unhandled CDC — signals passing from the clk domain to the clk_div domain cross clocks with no synchronizer, risking metastability; and (3) is untimed — STA does not know clk_div is a clock, so it never analyzes setup/hold on the crossing, and the design reports clean timing while harbouring a real violation. It simulates perfectly because an RTL simulator has zero skew and infinite setup margin. It is the definition of a bug that hides until silicon.

The clock-divider / timer family — one counter, generating enables (not clocks)

data flow
The clock-divider / timer family — one counter, generating enables (not clocks)one source clkthe ONLY clock — feeds every flopmod-N counter(3.2)counts 0..N-1 on clk, wrapstick(clock-enable)1 cycle high every N — a strobe at f/Nslow logic (2.2CE)on clk, advances only when tick==1loadabledown-counterload period, decrement, timeout at 0one-shot /periodicfire once, or auto-reload & repeat
Everything hangs off ONE source clock. The mod-N counter from 3.2 raises a one-cycle tick at f/N — that tick is a clock-ENABLE (data), never a clock. Slow logic is a 2.2 clock-enabled register on the same clk that advances only when tick is high: one clock domain, zero skew, every path analyzed by STA. A timer is the same counter measuring duration — a loadable down-counter that decrements each cycle (or each tick) and raises timeout at zero, either one-shot (fire once) or periodic (auto-reload). What you never build in RTL is a second clock: a divided flip-flop routed as a clock is skew + unhandled CDC + untimed, and it fails only in silicon. Same idea in SystemVerilog, Verilog, and VHDL.

Two closing notes on hardware reality. First, the divided tick is registered and glitch-free because it comes from a comparator on a clocked counter, sampled synchronously — unlike a clock derived by combinational division, which can glitch. Second, when you do need a real second clock frequency (not just a slower enable), that is a physical-design job: a PLL or an integrated clock-gating / clock-divider cell generates it on the clock tree, and any signal crossing between the two frequencies goes through a proper synchronizer. RTL's job is to generate enables and to hand the frequency requirement to the clocking infrastructure — not to fabricate a clock out of a flip-flop.

4. Real RTL Implementation

This is the core of the page. We build three patterns — (a) a clock-enable divider (mod-N → one-cycle tick at f/N, N-generic — the correct divider), (b) a timer (loadable down-counter with one-shot and periodic auto-reload modes and a timeout flag), and (c) the divided-flop-as-clock anti-pattern (buggy) versus the clock-enable fix — and each is shown in SystemVerilog, Verilog, and VHDL with a synthesizable RTL block and a clocked, self-checking testbench that generates a clock and asserts the tick period is exactly N and the timeout timing is exact. The idea is identical across the three languages; seeing them side by side is what makes the pattern language-independent.

One discipline runs through every RTL block: there is exactly one clock, clk, and it is the sensitivity of every always_ff / always @(posedge clk) / rising_edge(clk) process. Everything "slow" is expressed as a clock-enable (a signal that gates whether a register updates), never as a second clock edge. Reset is synchronous, active-high (rst), and <= (non-blocking) is used for all sequential updates — the same conventions inherited from 3.1 and 2.2.

4a. The clock-enable divider — mod-N → one-cycle tick, and slow logic gated by it

Start with the correct divider: a mod-N counter (3.2) whose wrap pulse is the divided tick, plus a tiny piece of downstream logic — a slow LED register — that advances only when tick is high. The whole point is that led toggles at f_clk / (2*N) while living entirely in the clk domain: no second clock, no skew, no CDC.

clkdiv_en.sv — clock-ENABLE divider: mod-N tick + clock-enabled slow logic
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module clkdiv_en #(
       parameter int N     = 100,                       // divide ratio (f_clk / N tick rate)
       localparam int WIDTH = (N > 1) ? $clog2(N) : 1   // holds 0 .. N-1
   )(
       input  logic clk,                                // the ONE clock — nothing else is clocked
       input  logic rst,                                // synchronous, active-high
       output logic tick,                               // 1-cycle clock-ENABLE, once every N cycles
       output logic led                                 // "slow" output, toggles at f_clk/(2N)
   );
       logic [WIDTH-1:0] count;
 
       // The mod-N counter from 3.2. tick is its wrap pulse — a clock-ENABLE, not a clock.
       always_ff @(posedge clk) begin
           if (rst)                  count <= '0;
           else if (count == WIDTH'(N-1)) count <= '0;  // reached terminal N-1 → wrap
           else                      count <= count + 1'b1;
       end
       assign tick = (count == WIDTH'(N-1));            // high for exactly 1 cycle per N
 
       // The "slow" logic is a 2.2 clock-ENABLED register: SAME clk, advances only on tick.
       // led therefore changes once per N ticks-worth of cycles — no second clock exists.
       always_ff @(posedge clk) begin
           if (rst)       led <= 1'b0;
           else if (tick) led <= ~led;                  // enable = tick; otherwise HOLD
       end
   endmodule

The self-checking testbench proves the two properties that make this a correct divider: (1) the tick-to-tick spacing is exactly N cycles (the divide ratio), and (2) led changes only on a tick and never on a non-tick cycle — the evidence that it lives in the single clk domain rather than a derived one.

clkdiv_en_tb.sv — clocked self-check: period == N, led moves ONLY on tick
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module clkdiv_en_tb;
       localparam int N = 5;                            // non-power-of-two on purpose
       logic clk = 0, rst, tick, led;
       int   errors = 0, cyc = 0, last = -1, gap;
       logic led_prev;
 
       clkdiv_en #(.N(N)) dut (.clk(clk), .rst(rst), .tick(tick), .led(led));
 
       always #5 clk = ~clk;                            // 100 MHz source clock
 
       initial begin
           rst = 1; @(posedge clk); #1; led_prev = led;
           rst = 0;
           for (cyc = 0; cyc < 6*N + 3; cyc++) begin
               @(posedge clk); #1;
               // (1) tick-to-tick period must be EXACTLY N (the divide ratio):
               if (tick) begin
                   if (last >= 0)
                       assert ((cyc - last) == N)
                           else begin $error("period=%0d exp=%0d", cyc-last, N); errors++; end
                   last = cyc;
               end
               // (2) led may change ONLY on a tick cycle — proof it is enable-gated, not re-clocked:
               if (led !== led_prev)
                   assert (tick)
                       else begin $error("led moved on a NON-tick cycle (cyc=%0d)", cyc); errors++; end
               led_prev = led;
           end
           if (errors == 0) $display("PASS: tick period == N and slow logic advances only on tick");
           else             $display("FAIL: %0d mismatches", errors);
           $finish;
       end
   endmodule

The Verilog form is identical in intent — reg/wire typing, always @(posedge clk), the same mod-N tick and the same enable-gated slow register. The self-check uses if (…) $display("FAIL") instead of assert.

clkdiv_en.v — clock-ENABLE divider in Verilog (one clk, tick as enable)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module clkdiv_en #(
       parameter N     = 100,
       parameter WIDTH = 7                              // must satisfy 2**WIDTH >= N
   )(
       input  wire clk,
       input  wire rst,                                 // synchronous, active-high
       output wire tick,
       output reg  led
   );
       reg [WIDTH-1:0] count;
 
       always @(posedge clk) begin
           if (rst)                 count <= {WIDTH{1'b0}};
           else if (count == N-1)   count <= {WIDTH{1'b0}};   // wrap on terminal N-1
           else                     count <= count + 1'b1;
       end
       assign tick = (count == N-1);                    // 1-cycle clock-ENABLE, period N
 
       // Slow logic: same clk, enable = tick, otherwise hold. No second clock domain.
       always @(posedge clk) begin
           if (rst)       led <= 1'b0;
           else if (tick) led <= ~led;
       end
   endmodule
clkdiv_en_tb.v — clocked self-check; period == N, led only on tick
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module clkdiv_en_tb;
       parameter N     = 5;
       parameter WIDTH = 3;
       reg clk, rst;
       wire tick, led;
       integer errors, cyc, last, gap;
       reg led_prev;
 
       clkdiv_en #(.N(N), .WIDTH(WIDTH)) dut (.clk(clk), .rst(rst), .tick(tick), .led(led));
 
       initial clk = 0;
       always #5 clk = ~clk;
 
       initial begin
           errors = 0; last = -1;
           rst = 1; @(posedge clk); #1; led_prev = led;
           rst = 0;
           for (cyc = 0; cyc < 6*N + 3; cyc = cyc + 1) begin
               @(posedge clk); #1;
               // period between ticks must be EXACTLY N:
               if (tick) begin
                   if (last >= 0) begin
                       gap = cyc - last;
                       if (gap !== N) begin
                           $display("FAIL: period=%0d exp=%0d", gap, N);
                           errors = errors + 1;
                       end
                   end
                   last = cyc;
               end
               // led must change ONLY on a tick cycle:
               if (led !== led_prev && tick !== 1'b1) begin
                   $display("FAIL: led moved on a non-tick cycle (cyc=%0d)", cyc);
                   errors = errors + 1;
               end
               led_prev = led;
           end
           if (errors == 0) $display("PASS: period == N and slow logic advances only on tick");
           else             $display("FAIL: %0d mismatches", errors);
           $finish;
       end
   endmodule

In VHDL the divide ratio is a generic, the register updates live in a clocked process guarded by rising_edge(clk), and arithmetic goes through numeric_std (unsigned). The tick is en-style data; the slow register's elsif tick = '1' is the clock-enable.

clkdiv_en.vhd — clock-ENABLE divider in VHDL (generic N, numeric_std)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
 
   entity clkdiv_en is
       generic (
           N     : positive := 100;                         -- divide ratio
           WIDTH : positive := 7                            -- must hold N-1
       );
       port (
           clk  : in  std_logic;                            -- the ONLY clock
           rst  : in  std_logic;                            -- synchronous, active-high
           tick : out std_logic;                            -- 1-cycle clock-ENABLE
           led  : out std_logic
       );
   end entity;
 
   architecture rtl of clkdiv_en is
       signal cnt     : unsigned(WIDTH-1 downto 0) := (others => '0');
       signal tick_i  : std_logic;
       signal led_r   : std_logic := '0';
   begin
       tick_i <= '1' when cnt = to_unsigned(N-1, WIDTH) else '0';  -- terminal N-1
 
       process (clk)
       begin
           if rising_edge(clk) then
               if rst = '1' then
                   cnt <= (others => '0');
               elsif tick_i = '1' then
                   cnt <= (others => '0');                  -- wrap to 0
               else
                   cnt <= cnt + 1;                          -- advance
               end if;
 
               -- Slow logic: SAME clk, enable = tick_i, otherwise hold.
               if rst = '1' then
                   led_r <= '0';
               elsif tick_i = '1' then
                   led_r <= not led_r;
               end if;
           end if;
       end process;
 
       tick <= tick_i;
       led  <= led_r;
   end architecture;
clkdiv_en_tb.vhd — clocked self-check; assert period = N, led only on tick
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
 
   entity clkdiv_en_tb is
   end entity;
 
   architecture sim of clkdiv_en_tb is
       constant N     : positive := 5;
       constant WIDTH : positive := 3;
       signal clk  : std_logic := '0';
       signal rst  : std_logic := '1';
       signal tick : std_logic;
       signal led  : std_logic;
   begin
       dut : entity work.clkdiv_en
           generic map (N => N, WIDTH => WIDTH)
           port map (clk => clk, rst => rst, tick => tick, led => led);
 
       clk <= not clk after 5 ns;
 
       stim : process
           variable last     : integer := -1;
           variable cyc      : integer := 0;
           variable led_prev : std_logic;
       begin
           wait until rising_edge(clk); wait for 1 ns;
           led_prev := led;
           rst <= '0';
           for c in 0 to 6*N + 2 loop
               wait until rising_edge(clk); wait for 1 ns;
               -- period between ticks must be EXACTLY N:
               if tick = '1' then
                   if last >= 0 then
                       assert (cyc - last) = N
                           report "tick period /= N" severity error;
                   end if;
                   last := cyc;
               end if;
               -- led must change ONLY on a tick cycle:
               if led /= led_prev then
                   assert tick = '1'
                       report "led moved on a non-tick cycle" severity error;
               end if;
               led_prev := led;
               cyc := cyc + 1;
           end loop;
           report "clkdiv_en self-check complete (period = N, enable-gated)" severity note;
           wait;
       end process;
   end architecture;

4b. The timer — loadable down-counter, one-shot and periodic auto-reload

Now the duration side: a timer that loads a period, decrements each cycle, and raises timeout for one cycle when it reaches zero. A mode bit selects behaviour at zero — one-shot (fire once, then hold disarmed) or periodic (auto-reload the period and keep going). load writes a new period and (re)arms the timer; one_shot picks the mode.

timer.sv — loadable timer: one-shot vs periodic auto-reload, timeout flag
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module timer #(
       parameter int WIDTH = 16                         // period width (max count)
   )(
       input  logic             clk,
       input  logic             rst,                    // synchronous, active-high
       input  logic             load,                   // 1-cycle: capture period & arm
       input  logic [WIDTH-1:0] period,                 // cycles-1 to count (terminal at 0)
       input  logic             one_shot,               // 1 = fire once; 0 = periodic (auto-reload)
       output logic             timeout                 // 1-cycle strobe when count hits 0
   );
       logic [WIDTH-1:0] count;
       logic             running;                       // armed & counting
 
       // timeout fires on the cycle the running count is at zero.
       assign timeout = running & (count == '0);
 
       always_ff @(posedge clk) begin
           if (rst) begin
               count   <= '0;
               running <= 1'b0;
           end else if (load) begin
               count   <= period;                       // arm with the programmed period
               running <= 1'b1;
           end else if (running) begin
               if (count == '0) begin
                   // At terminal: one-shot stops; periodic reloads and continues.
                   if (one_shot) running <= 1'b0;        // fire once, then disarm
                   else          count   <= period;      // auto-reload → recurring timeout
               end else begin
                   count <= count - 1'b1;                // decrement toward zero
               end
           end
       end
   endmodule

The self-checking testbench proves the timeout timing in both modes: a one-shot armed with period = P must raise timeout exactly P+1 cycles after load (P decrements from P down through 0) and then never again; a periodic timer must raise timeout every P+1 cycles, repeatedly.

timer_tb.sv — self-check: one-shot fires once at P+1; periodic repeats every P+1
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module timer_tb;
       localparam int WIDTH = 16;
       logic clk = 0, rst, load, one_shot;
       logic [WIDTH-1:0] period;
       logic timeout;
       int   errors = 0, cyc, fires, last;
 
       timer #(.WIDTH(WIDTH)) dut
           (.clk(clk), .rst(rst), .load(load), .period(period),
            .one_shot(one_shot), .timeout(timeout));
 
       always #5 clk = ~clk;
 
       initial begin
           rst = 1; load = 0; one_shot = 1; period = 0; @(posedge clk); #1;
           rst = 0;
 
           // --- ONE-SHOT: period=4 → timeout exactly ONCE, at 5 cycles after load ---
           period = 4; one_shot = 1;
           @(posedge clk); load = 1; @(posedge clk); #1; load = 0;
           fires = 0; last = -1;
           for (cyc = 0; cyc < 20; cyc++) begin
               if (timeout) begin fires++; last = cyc; end
               @(posedge clk); #1;
           end
           assert (fires == 1) else begin $error("one-shot fired %0d times, exp 1", fires); errors++; end
           assert (last == 4)  else begin $error("one-shot fired at cyc=%0d, exp 4", last); errors++; end
 
           // --- PERIODIC: period=3 → timeout every 4 cycles, repeatedly ---
           period = 3; one_shot = 0;
           @(posedge clk); load = 1; @(posedge clk); #1; load = 0;
           fires = 0; last = -1;
           for (cyc = 0; cyc < 20; cyc++) begin
               if (timeout) begin
                   if (last >= 0)
                       assert ((cyc - last) == 4)
                           else begin $error("periodic interval=%0d exp=4", cyc-last); errors++; end
                   last = cyc; fires++;
               end
               @(posedge clk); #1;
           end
           assert (fires >= 3) else begin $error("periodic fired only %0d times", fires); errors++; end
 
           if (errors == 0) $display("PASS: one-shot fires once; periodic repeats at the right interval");
           else             $display("FAIL: %0d mismatches", errors);
           $finish;
       end
   endmodule

The Verilog timer is the same loadable down-counter with reg/wire typing; the testbench counts timeout pulses and checks the interval with if (…) $display("FAIL").

timer.v — loadable timer in Verilog (one-shot + periodic auto-reload)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module timer #(
       parameter WIDTH = 16
   )(
       input  wire             clk,
       input  wire             rst,
       input  wire             load,                    // capture period & arm
       input  wire [WIDTH-1:0] period,
       input  wire             one_shot,                // 1 = fire once, 0 = periodic
       output wire             timeout
   );
       reg [WIDTH-1:0] count;
       reg             running;
 
       assign timeout = running & (count == {WIDTH{1'b0}});
 
       always @(posedge clk) begin
           if (rst) begin
               count   <= {WIDTH{1'b0}};
               running <= 1'b0;
           end else if (load) begin
               count   <= period;
               running <= 1'b1;
           end else if (running) begin
               if (count == {WIDTH{1'b0}}) begin
                   if (one_shot) running <= 1'b0;         // fire once, disarm
                   else          count   <= period;       // auto-reload
               end else begin
                   count <= count - 1'b1;
               end
           end
       end
   endmodule
timer_tb.v — self-check; one-shot fires once, periodic repeats
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module timer_tb;
       parameter WIDTH = 16;
       reg clk, rst, load, one_shot;
       reg  [WIDTH-1:0] period;
       wire timeout;
       integer errors, cyc, fires, last;
 
       timer #(.WIDTH(WIDTH)) dut
           (.clk(clk), .rst(rst), .load(load), .period(period),
            .one_shot(one_shot), .timeout(timeout));
 
       initial clk = 0;
       always #5 clk = ~clk;
 
       initial begin
           errors = 0;
           rst = 1; load = 0; one_shot = 1; period = 0; @(posedge clk); #1;
           rst = 0;
 
           // ONE-SHOT: period=4 → fire once, at cyc 4 after load release
           period = 4; one_shot = 1;
           @(posedge clk); load = 1; @(posedge clk); #1; load = 0;
           fires = 0; last = -1;
           for (cyc = 0; cyc < 20; cyc = cyc + 1) begin
               if (timeout) begin fires = fires + 1; last = cyc; end
               @(posedge clk); #1;
           end
           if (fires !== 1) begin $display("FAIL: one-shot fired %0d times, exp 1", fires); errors = errors + 1; end
           if (last  !== 4) begin $display("FAIL: one-shot fired at %0d, exp 4", last); errors = errors + 1; end
 
           // PERIODIC: period=3 → timeout every 4 cycles
           period = 3; one_shot = 0;
           @(posedge clk); load = 1; @(posedge clk); #1; load = 0;
           fires = 0; last = -1;
           for (cyc = 0; cyc < 20; cyc = cyc + 1) begin
               if (timeout) begin
                   if (last >= 0 && (cyc - last) !== 4) begin
                       $display("FAIL: periodic interval=%0d exp=4", cyc-last);
                       errors = errors + 1;
                   end
                   last = cyc; fires = fires + 1;
               end
               @(posedge clk); #1;
           end
           if (fires < 3) begin $display("FAIL: periodic fired only %0d times", fires); errors = errors + 1; end
 
           if (errors == 0) $display("PASS: one-shot fires once; periodic repeats at interval");
           else             $display("FAIL: %0d mismatches", errors);
           $finish;
       end
   endmodule

In VHDL the period is a std_logic_vector port converted to unsigned; load arms, the process decrements, and the one_shot boolean picks stop-vs-reload at zero. The timeout is a combinational decode of running and count = 0.

timer.vhd — loadable timer in VHDL (one-shot + periodic, numeric_std)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
 
   entity timer is
       generic ( WIDTH : positive := 16 );
       port (
           clk      : in  std_logic;
           rst      : in  std_logic;                        -- synchronous, active-high
           load     : in  std_logic;                        -- capture period & arm
           period   : in  std_logic_vector(WIDTH-1 downto 0);
           one_shot : in  std_logic;                        -- '1' fire once, '0' periodic
           timeout  : out std_logic
       );
   end entity;
 
   architecture rtl of timer is
       signal cnt     : unsigned(WIDTH-1 downto 0) := (others => '0');
       signal running : std_logic := '0';
   begin
       timeout <= '1' when (running = '1' and cnt = to_unsigned(0, WIDTH)) else '0';
 
       process (clk)
       begin
           if rising_edge(clk) then
               if rst = '1' then
                   cnt     <= (others => '0');
                   running <= '0';
               elsif load = '1' then
                   cnt     <= unsigned(period);            -- arm with the programmed period
                   running <= '1';
               elsif running = '1' then
                   if cnt = to_unsigned(0, WIDTH) then
                       if one_shot = '1' then
                           running <= '0';                 -- fire once, disarm
                       else
                           cnt <= unsigned(period);        -- auto-reload → periodic
                       end if;
                   else
                       cnt <= cnt - 1;                     -- decrement toward zero
                   end if;
               end if;
           end if;
       end process;
   end architecture;
timer_tb.vhd — self-check; assert one-shot fires once, periodic repeats (severity error)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
 
   entity timer_tb is
   end entity;
 
   architecture sim of timer_tb is
       constant WIDTH : positive := 16;
       signal clk      : std_logic := '0';
       signal rst      : std_logic := '1';
       signal load     : std_logic := '0';
       signal period   : std_logic_vector(WIDTH-1 downto 0) := (others => '0');
       signal one_shot : std_logic := '1';
       signal timeout  : std_logic;
   begin
       dut : entity work.timer
           generic map (WIDTH => WIDTH)
           port map (clk => clk, rst => rst, load => load, period => period,
                     one_shot => one_shot, timeout => timeout);
 
       clk <= not clk after 5 ns;
 
       stim : process
           variable fires : integer;
           variable last  : integer;
           variable cyc   : integer;
       begin
           wait until rising_edge(clk); wait for 1 ns;
           rst <= '0';
 
           -- ONE-SHOT: period=4 → fire once, at cyc 4 after load
           period   <= std_logic_vector(to_unsigned(4, WIDTH));
           one_shot <= '1';
           wait until rising_edge(clk); load <= '1';
           wait until rising_edge(clk); wait for 1 ns; load <= '0';
           fires := 0; last := -1; cyc := 0;
           for i in 0 to 19 loop
               if timeout = '1' then fires := fires + 1; last := cyc; end if;
               wait until rising_edge(clk); wait for 1 ns;
               cyc := cyc + 1;
           end loop;
           assert fires = 1 report "one-shot did not fire exactly once" severity error;
           assert last  = 4 report "one-shot fired at the wrong cycle"   severity error;
 
           -- PERIODIC: period=3 → timeout every 4 cycles
           period   <= std_logic_vector(to_unsigned(3, WIDTH));
           one_shot <= '0';
           wait until rising_edge(clk); load <= '1';
           wait until rising_edge(clk); wait for 1 ns; load <= '0';
           fires := 0; last := -1; cyc := 0;
           for i in 0 to 19 loop
               if timeout = '1' then
                   if last >= 0 then
                       assert (cyc - last) = 4
                           report "periodic interval /= 4" severity error;
                   end if;
                   last := cyc; fires := fires + 1;
               end if;
               wait until rising_edge(clk); wait for 1 ns;
               cyc := cyc + 1;
           end loop;
           assert fires >= 3 report "periodic did not repeat" severity error;
 
           report "timer self-check complete (one-shot + periodic)" severity note;
           wait;
       end process;
   end architecture;

4c. The divided-flop-as-clock anti-pattern — buggy vs fixed, in all three HDLs

Pattern (c) is the signature failure of this page, shown as buggy vs fixed RTL in each language and dramatized in §7. The bug is the same everywhere: a counter/toggle-flop output (clk_div) is generated in RTL and then used as a clockalways @(posedge clk_div) — for the slow logic. The fix keeps the single source clock and turns the divided signal into a clock-enable instead. Both "look" like they divide; only the fix is a single, analyzable clock domain.

clkdiv_bug.sv — BUGGY (divided flop AS a clock) vs FIXED (clock-enable)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // BUGGY: clk_div is a divided flip-flop output used AS A CLOCK for slow_reg.
   //   → clk_div is a NEW clock domain: skew vs clk, an unhandled CDC on data_in,
   //     and STA never analyzes the clk→clk_div path. Sims perfectly; fails in silicon.
   module divider_bad #(
       parameter int N = 4
   )(
       input  logic clk, rst, data_in,
       output logic slow_reg
   );
       logic [$clog2(N)-1:0] count;
       logic                 clk_div;
       always_ff @(posedge clk) begin                  // count on the real clock
           if (rst)                       {count, clk_div} <= '0;
           else if (count == N-1) begin count <= '0; clk_div <= ~clk_div; end
           else                           count <= count + 1'b1;
       end
       // THE BUG: a flop clocked by a DERIVED clock — new domain, skew, CDC, untimed.
       always_ff @(posedge clk_div) begin
           if (rst) slow_reg <= 1'b0;
           else     slow_reg <= data_in;               // data_in crosses clk → clk_div unsynchronized
       end
   endmodule
 
   // FIXED: ONE clock. The divided signal is a clock-ENABLE (tick); slow_reg is a
   //   clock-enabled register on clk. One domain, zero skew, every path analyzed.
   module divider_good #(
       parameter int N = 4
   )(
       input  logic clk, rst, data_in,
       output logic slow_reg
   );
       logic [$clog2(N)-1:0] count;
       logic                 tick;
       always_ff @(posedge clk) begin
           if (rst)               count <= '0;
           else if (count == N-1) count <= '0;
           else                   count <= count + 1'b1;
       end
       assign tick = (count == N-1);                   // clock-ENABLE, not a clock
       always_ff @(posedge clk) begin                  // SAME clk as the counter
           if (rst)       slow_reg <= 1'b0;
           else if (tick) slow_reg <= data_in;         // advance only when enabled
       end
   endmodule
clkdiv_bug_tb.sv — clocked self-check: slow_reg updates ONLY on tick cycles
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module clkdiv_good_tb;
       localparam int N = 4;
       logic clk = 0, rst, data_in, slow_reg;
       int   errors = 0, cyc = 0, changes = 0;
       logic q_prev;
 
       // Bind to divider_good (single clock, safe). Point at divider_bad to observe
       // the derived-clock domain: in a zero-skew RTL sim it "works" — the hazard is
       // silicon skew/CDC/STA, which a functional TB cannot see. That invisibility is
       // exactly why the rule is structural: never clock on a divided flop.
       divider_good #(.N(N)) dut (.clk(clk), .rst(rst), .data_in(data_in), .slow_reg(slow_reg));
 
       always #5 clk = ~clk;
 
       // Reference divider: a tick every N cycles, on the SAME clock as the DUT.
       logic [$clog2(N)-1:0] cnt = 0;
       logic ref_tick;
       always @(posedge clk) begin
           if (rst)               cnt <= 0;
           else if (cnt == N-1)   cnt <= 0;
           else                   cnt <= cnt + 1;
       end
       assign ref_tick = (cnt == N-1);
 
       initial begin
           rst = 1; data_in = 0; @(posedge clk); #1; q_prev = slow_reg;
           rst = 0;
           for (cyc = 0; cyc < 8*N; cyc++) begin
               data_in = $urandom;                     // change data every cycle
               @(posedge clk); #1;
               // slow_reg (the correct, enable-gated register) may change ONLY on a tick:
               if (slow_reg !== q_prev) begin
                   changes++;
                   assert (ref_tick)
                       else begin $error("slow_reg changed on a NON-tick cycle (cyc=%0d)", cyc); errors++; end
               end
               q_prev = slow_reg;
           end
           if (errors == 0 && changes > 0)
                $display("PASS: single-clock divider advances only on the enable tick");
           else $display("FAIL: %0d mismatches (%0d changes)", errors, changes);
           $finish;
       end
   endmodule

The Verilog buggy/fixed pair is the same story with reg/wire: the bad module has an always @(posedge clk_div) on a derived clock; the fixed module keeps always @(posedge clk) and gates the update with tick.

clkdiv_bug.v — BUGGY (posedge clk_div) vs FIXED (enable on clk) in Verilog
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // BUGGY: slow_reg is clocked by clk_div, a divided flop output → derived clock
   //        domain: skew, unhandled CDC on data_in, STA-invisible. Sims fine, fails in HW.
   module divider_bad #(
       parameter N = 4,
       parameter W = 2                                  // clog2(N)
   )(
       input  wire clk, rst, data_in,
       output reg  slow_reg
   );
       reg [W-1:0] count;
       reg         clk_div;
       always @(posedge clk) begin
           if (rst)              begin count <= 0; clk_div <= 1'b0; end
           else if (count == N-1) begin count <= 0; clk_div <= ~clk_div; end
           else                   count <= count + 1'b1;
       end
       always @(posedge clk_div) begin                  // THE BUG: derived-clock flop
           if (rst) slow_reg <= 1'b0;
           else     slow_reg <= data_in;                // unsynchronized crossing
       end
   endmodule
 
   // FIXED: single clock; the divided signal is an ENABLE (tick), slow_reg on clk.
   module divider_good #(
       parameter N = 4,
       parameter W = 2
   )(
       input  wire clk, rst, data_in,
       output reg  slow_reg
   );
       reg [W-1:0] count;
       wire        tick;
       always @(posedge clk) begin
           if (rst)              count <= 0;
           else if (count == N-1) count <= 0;
           else                   count <= count + 1'b1;
       end
       assign tick = (count == N-1);                    // clock-ENABLE
       always @(posedge clk) begin                      // SAME clk
           if (rst)       slow_reg <= 1'b0;
           else if (tick) slow_reg <= data_in;          // advance only when enabled
       end
   endmodule
clkdiv_bug_tb.v — self-check; the fixed DUT's slow_reg changes only on tick
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   module clkdiv_good_tb;
       parameter N = 4;
       parameter W = 2;
       reg clk, rst, data_in;
       wire slow_reg;
       integer errors, cyc, changes;
       reg q_prev;
 
       // Bind to divider_good (single clock). Point at divider_bad to see that a
       // zero-skew RTL sim CANNOT expose the derived-clock hazard — proof the rule
       // must be structural, not verification-caught.
       divider_good #(.N(N), .W(W)) dut (.clk(clk), .rst(rst), .data_in(data_in), .slow_reg(slow_reg));
 
       initial clk = 0;
       always #5 clk = ~clk;
 
       reg [W-1:0] cnt;
       wire ref_tick;
       always @(posedge clk) begin
           if (rst)              cnt <= 0;
           else if (cnt == N-1)   cnt <= 0;
           else                   cnt <= cnt + 1;
       end
       assign ref_tick = (cnt == N-1);
 
       initial begin
           errors = 0; changes = 0;
           rst = 1; data_in = 0; @(posedge clk); #1; q_prev = slow_reg;
           rst = 0;
           for (cyc = 0; cyc < 8*N; cyc = cyc + 1) begin
               data_in = $random;
               @(posedge clk); #1;
               if (slow_reg !== q_prev) begin
                   changes = changes + 1;
                   if (ref_tick !== 1'b1) begin
                       $display("FAIL: slow_reg changed on a non-tick cycle (cyc=%0d)", cyc);
                       errors = errors + 1;
                   end
               end
               q_prev = slow_reg;
           end
           if (errors == 0 && changes > 0) $display("PASS: single-clock divider advances only on tick");
           else                            $display("FAIL: %0d mismatches (%0d changes)", errors, changes);
           $finish;
       end
   endmodule

In VHDL the identical bug is a second clocked process sensitive to rising_edge(clk_div), where clk_div is a signal the first process toggles. The fix keeps every register in one rising_edge(clk) process and gates the slow update with a tick enable.

clkdiv_bug.vhd — BUGGY (rising_edge(clk_div)) vs FIXED (enable on clk)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
 
   -- BUGGY: slow_reg is clocked by clk_div, a divided flop → derived clock domain:
   --        skew, unhandled CDC on data_in, STA-invisible. Sims fine; fails in silicon.
   entity divider_bad is
       generic ( N : positive := 4; W : positive := 2 );
       port ( clk, rst, data_in : in std_logic; slow_reg : out std_logic );
   end entity;
   architecture rtl of divider_bad is
       signal cnt     : unsigned(W-1 downto 0) := (others => '0');
       signal clk_div : std_logic := '0';
   begin
       process (clk)
       begin
           if rising_edge(clk) then
               if rst = '1' then
                   cnt <= (others => '0'); clk_div <= '0';
               elsif cnt = to_unsigned(N-1, W) then
                   cnt <= (others => '0'); clk_div <= not clk_div;
               else
                   cnt <= cnt + 1;
               end if;
           end if;
       end process;
       process (clk_div)                                -- THE BUG: derived-clock process
       begin
           if rising_edge(clk_div) then
               slow_reg <= data_in;                     -- unsynchronized clk → clk_div crossing
           end if;
       end process;
   end architecture;
 
   -- FIXED: single clock; the divided signal is an ENABLE (tick), slow_reg on clk.
   entity divider_good is
       generic ( N : positive := 4; W : positive := 2 );
       port ( clk, rst, data_in : in std_logic; slow_reg : out std_logic );
   end entity;
   architecture rtl of divider_good is
       signal cnt  : unsigned(W-1 downto 0) := (others => '0');
       signal tick : std_logic;
   begin
       tick <= '1' when cnt = to_unsigned(N-1, W) else '0';   -- clock-ENABLE
       process (clk)                                    -- SAME clk for every register
       begin
           if rising_edge(clk) then
               if rst = '1' then
                   cnt <= (others => '0'); slow_reg <= '0';
               else
                   if tick = '1' then cnt <= (others => '0');
                   else               cnt <= cnt + 1; end if;
                   if tick = '1' then slow_reg <= data_in; end if;  -- advance only when enabled
               end if;
           end if;
       end process;
   end architecture;
clkdiv_bug_tb.vhd — self-check; fixed DUT's slow_reg changes only on tick (severity error)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
 
   entity clkdiv_good_tb is
   end entity;
 
   architecture sim of clkdiv_good_tb is
       constant N : positive := 4;
       constant W : positive := 2;
       signal clk      : std_logic := '0';
       signal rst      : std_logic := '1';
       signal data_in  : std_logic := '0';
       signal slow_reg : std_logic;
       signal cnt      : unsigned(W-1 downto 0) := (others => '0');
       signal ref_tick : std_logic;
   begin
       -- Bind to divider_good (single clock, safe). Binding divider_bad would still
       -- "pass" in a zero-skew sim — proof the derived-clock hazard is a silicon issue
       -- a functional TB cannot catch, so the rule must be structural.
       dut : entity work.divider_good
           generic map (N => N, W => W)
           port map (clk => clk, rst => rst, data_in => data_in, slow_reg => slow_reg);
 
       clk <= not clk after 5 ns;
 
       ref : process (clk)
       begin
           if rising_edge(clk) then
               if rst = '1' then cnt <= (others => '0');
               elsif cnt = to_unsigned(N-1, W) then cnt <= (others => '0');
               else cnt <= cnt + 1; end if;
           end if;
       end process;
       ref_tick <= '1' when cnt = to_unsigned(N-1, W) else '0';
 
       stim : process
           variable q_prev  : std_logic;
           variable changes : integer := 0;
           variable seed1, seed2 : positive := 7;
           variable r : real;
       begin
           wait until rising_edge(clk); wait for 1 ns; q_prev := slow_reg;
           rst <= '0';
           for i in 0 to 8*N - 1 loop
               uniform(seed1, seed2, r);
               data_in <= '1' when r > 0.5 else '0';
               wait until rising_edge(clk); wait for 1 ns;
               if slow_reg /= q_prev then
                   changes := changes + 1;
                   assert ref_tick = '1'
                       report "slow_reg changed on a non-tick cycle" severity error;
               end if;
               q_prev := slow_reg;
           end loop;
           assert changes > 0 report "slow_reg never changed" severity error;
           report "single-clock divider self-check complete (advances only on tick)" severity note;
           wait;
       end process;
   end architecture;

Across all three languages the lesson is one sentence: in RTL you generate clock-enables, not clocks — never route a divided flip-flop output as a clock, because that creates an unanalyzed clock domain that simulates perfectly and fails in silicon.

5. Verification Strategy

A clock divider and a timer are sequential, so correctness is a behaviour over time and the testbench must be clocked: generate one source clock, release reset, and sample after each edge with the self-checking discipline from 3.1. Two families of invariants capture this page — a divider's rate and a timer's timing — and both hinge on the fact that everything lives in the single clk domain:

(1) The tick (divided enable) is high for exactly one cycle every N cycles; (2) the 'slow' logic changes value ONLY on a tick cycle — never in between; (3) a one-shot timer raises timeout exactly once, N cycles after arm; a periodic timer raises it every N cycles, forever.

  • Measure the tick period (the divide ratio). Record the cycle of each tick; when the next fires, assert the gap is exactly N — the same period measurement that guards the mod-N off-by-one (3.2). The tick is the divided signal, so its period is the divide ratio; a period of N+1 is a frequency error. The §4a testbenches do this in all three HDLs (SV assert, Verilog if(...)$display("FAIL"), VHDL assert … severity error).
  • Assert the slow logic advances ONLY on tick. This is the check that proves the design is a single clock domain rather than a derived one. Snapshot the slow output each cycle; whenever it changes, assert tick was high on that cycle. A change on a non-tick cycle means the logic is being clocked by something other than the enable — the signature of the divided-clock bug. The §4a and §4c testbenches both include this "changes-only-on-tick" assertion.
  • Verify timeout timing in both modes. For a one-shot loaded with period P, assert timeout fires exactly once and at the expected offset after load (P decrements P→0), then never again — count the pulses and assert the count is 1. For a periodic timer, assert timeout recurs at a fixed interval (P+1 cycles) across several periods — measure the pulse-to-pulse gap just like the divider period. The §4b testbenches drive both modes and check both properties.
  • Corner cases: N=1, period=0, and re-arm. A divide-by-1 (N=1) should tick every cycle (period 1); a timer with period=0 should time out immediately (the same cycle it is armed) — verify these degenerate points explicitly, because a count == N-1 or a decrement-then-compare written assuming N ≥ 2 can misbehave when the terminal is already zero. Also exercise re-arm: reload a one-shot mid-run and confirm it fires again from the new period, and reload (feed) a periodic/watchdog timer before it expires and confirm it does not time out — the exact behaviour a watchdog depends on.
  • The anti-pattern is a review check, not a sim check. The divided-clock bug cannot be caught by a functional testbench, because an RTL simulator has zero clock skew and infinite setup margin — the buggy posedge clk_div design passes simulation. Its detection lives in structural review and CDC/lint tooling: a lint rule that flags "clock generated from a flip-flop / non-primary clock," a CDC checker that flags the unsynchronized crossing, and STA (which will either miss the path or, with clock definitions, flag an unconstrained generated clock). The verification lesson is itself a lesson: some bugs are prevented by construction and tooling, not by testbenches — which is why the rule "generate enables, not clocks" is a hard structural rule.
  • Expected waveform. A correct divider shows the counter ramping 0 → N-1, tick pulsing high for one cycle at the top, and the slow output stepping only at those pulses — flat between them. A correct one-shot shows the down-counter ramping period→0 once, a single timeout pulse at zero, then a flat line; a periodic timer shows that saw-tooth repeating with a timeout pulse at every zero-crossing. The visual signature of the divided-clock bug is subtler: in RTL sim it looks fine (that is the danger) — you only see it on hardware as intermittent, temperature/voltage-dependent glitches on the crossing.

6. Common Mistakes

Using a divided flip-flop output as a clock (always @(posedge clk_div)). The signature failure and the reason this pattern gets its own page. Counting the source clock and then routing the divided output — a counter bit, or a toggled flop — as the clock of downstream logic creates a new clock domain with three fatal properties: it has skew (it arrives through logic and routing, not the balanced clock tree), it is an unhandled CDC (data crossing into it has no synchronizer and can go metastable), and it is untimed (STA does not recognize it as a clock, so the crossing is never analyzed). It simulates perfectly — zero skew, infinite margin — and then fails intermittently in silicon, the worst failure profile there is. The fix is always the same: keep one clock and turn the divided signal into a clock-enable that gates a register on the source clock. In RTL you generate enables, not clocks.

Treating a /N tick as if it were a 50%-duty divided clock. The mod-N tick is a one-cycle strobe — high for one cycle, low for N-1 — not a symmetric square wave. If you actually need a 50%-duty divided clock signal (to drive an output pin or a clock cell), you need a toggle-flop divider, not the raw tick, and even then the result is a /2N (or /2^k) clock, not a /N one. Confusing the strobe with a clock also feeds straight into the previous bug — a one-cycle pulse used as a clock has a runt high-time and is doubly wrong.

Assuming an odd integer divide can have a 50% duty from one edge. A /2, /4, /6 (even) divide is easy to make 50%-duty by toggling at the half-period. An odd integer divide (/3, /5) at a true 50% duty is not achievable from the rising edge alone, because half of an odd number of clock cycles is not a whole cycle — you must combine logic clocked on the rising edge with logic clocked on the falling edge (a both-edges design) to place the transition at the half-cycle point. Writing a single-edge /3 and expecting exactly 50% duty gives an unbalanced (e.g. 2-high/1-low) waveform instead. If duty does not matter, prefer the clock-enable tick and avoid the issue entirely.

Forgetting to re-arm a one-shot (or to feed a watchdog). A one-shot timer fires timeout once and then holds disarmed — that is the point of "one-shot." A common bug is expecting it to keep firing, or forgetting to reload it before the next expected event, so the second event never triggers. The mirror bug is a watchdog (a periodic/reloadable timer that resets the system on timeout): if firmware forgets to feed it (reload it before it expires), it bites and resets the chip — which is either the intended safety behaviour or a spurious reset from a missed feed. Be explicit about the mode: one-shot needs a re-arm per event; periodic/watchdog needs a periodic reload to prevent the timeout.

Off-by-one in the divide ratio or the timeout period. Inherited straight from 3.2: the divider's terminal value is N-1 (compare count == N-1), not N, or the period becomes N+1 and the divided frequency is subtly wrong. Likewise a down-counting timer loaded with period = P and counting P … 0 takes P+1 cycles to time out — decide deliberately whether you load desired_cycles or desired_cycles - 1, and measure the interval in verification rather than eyeballing it. A divide ratio and a timeout are both counts of cycles, and the only proof is to count them.

7. DebugLab

The blink that worked on the bench and glitched in the field — a divided flop used as a clock

The engineering lesson: in RTL you generate clock-enables, not clocks — a divided flip-flop output used as a clock is a new, unanalyzed clock domain, and it is the most dangerous kind of bug because it passes every check you run and fails only in silicon. That is what makes it lethal: the RTL simulator has zero skew and infinite setup margin, so the buggy design is perfectly green in functional sim; STA never sees the generated clock, so timing signs off clean; and the failure surfaces only as intermittent, temperature- and voltage-dependent corruption in the field, on some boards, sometimes. Two habits make it impossible, and they are identical across SystemVerilog, Verilog, and VHDL: keep exactly one clock and express every 'slower' rate as a clock-enable that gates a register on that one clock, and hand any genuine second-frequency requirement to the clocking infrastructure — a PLL or clock-divider cell on the clock tree, with a proper synchronizer at the crossing — rather than manufacturing a clock from a flip-flop.

8. Interview Q&A

9. Exercises

Design and reasoning exercises — no syntax drills. Each rehearses the "generate enables, not clocks" and "the divider/timer is one counter" habits.

You must blink a status LED at 1 Hz (on for 0.5 s, off for 0.5 s) from a 100 MHz source clock. (a) Using the clock-enable pattern, what divide ratio N gives a tick you can use, and what does the LED register do on each tick to get a 1 Hz, 50%-duty blink? (b) What minimum counter WIDTH do you need? (c) A colleague instead builds a chain of toggle flops and routes the final divided output as the clock for the LED flop — name the three specific hazards that introduces and why none of them appear in an RTL simulation. (d) State the one-line self-checking assertion (in words) that proves the LED changes only on a tick.

Exercise 2 — Baud tick and the off-by-one

A UART on a 100 MHz clock needs a 115200-baud sample tick at 16× oversampling (the sample strobe runs at 16 × baud). (a) Compute the ideal divide ratio N = f_clk / (16 × 115200) — is it an integer? (b) Choose the nearest integer N and state the actual oversample-tick frequency and the resulting error in percent. (c) Your divider compares count == N instead of count == N-1; what period does the tick actually have, and how would a period-measuring self-check expose it where an eyeball would not? (d) Explain why this baud tick should be a clock-enable consumed by the UART's sampling FSM rather than a divided clock fed to that FSM.

Exercise 3 — One-shot vs periodic vs watchdog on paper

A single loadable down-counter can serve three roles. (a) For a one-shot loaded with period = 50 on a 100 MHz clock, how many cycles and how much wall-clock time until timeout, and what does the timer do after it fires? (b) Convert it to periodic mode: what changes at the terminal (zero) count, and what is the resulting timeout interval? (c) A watchdog is a periodic timer that resets the chip on timeout unless firmware feeds it. Describe the sequence of events if firmware feeds it every 30 ms with a 50 ms watchdog, versus what happens if a firmware hang stops the feeds — and identify which timer input the "feed" drives. (d) Why is a watchdog's timeout-to-reset path one of the few places you might want a timer to fire, rather than a bug to avoid?

Exercise 4 — The odd-divide duty-cycle trap

You need a /3 divided clock signal (not just an enable) with an exact 50% duty cycle to drive an off-chip peripheral. (a) Why can a single rising-edge design not achieve exactly 50% duty for a /3 divide — what duty cycle does a naive single-edge /3 produce, and why? (b) Sketch (in words) the both-edges structure that does achieve 50% duty, naming what the rising-edge and falling-edge parts each contribute. (c) If the peripheral actually only needs a periodic enable rather than a true clock, what simpler structure removes the whole duty-cycle problem? (d) Why is generating this /3 clock in RTL and routing it to the pin still safer than routing it internally to clock on-chip logic — what makes the off-chip case different from the DebugLab's on-chip case?

Continue in RTL Design Patterns (sibling and forward links unlock as they ship):

  • Ring & Johnson Counters — Chapter 3; shift-register counters that are themselves a form of clock/phase divider — a ring counter of length N produces N evenly-spaced one-cycle phases, another way to build divided enables.
  • Pulse & Strobe Generators — Chapter 3; the tick and timeout strobes generalized into one-shot, edge-detected, and delayed pulse generation — the direct forward step from this page's enables.
  • FSM Fundamentals — Chapter 4; the controllers that consume these ticks and timeouts as clock-enables and sequencing events (a UART sampler advances its FSM on the baud tick).

Builds on (in-track):

  • Mod-N & Programmable Counters — Chapter 3.2; the compare-and-reset counter whose one-cycle wrap pulse is the divided tick — a clock-enable divider is a mod-N counter, and the terminal-value off-by-one carries straight over.
  • Register with Enable & Load — Chapter 2.2; the clock-enable and load semantics at the heart of this page — the "slow" logic is a clock-enabled register, and a timer is a loadable down-counter.
  • Up/Down Counters — Chapter 3.1; the count register + enable + reset the divider extends and the down-count a timer uses.
  • The Register Pattern (D-FF) — Chapter 2.1; the clocked register underneath every counter, divider, and timer, and the single-clock discipline this page insists on.
  • Synchronous Reset — Chapter 2; the reset-to-zero / disarm discipline the divider and timer inherit.
  • Gray-Code Counters — Chapter 3; the sibling counter built for safe clock-domain crossing — the correct tool for the real CDC that the divided-clock anti-pattern mishandles.

Method / overview:

  • The RTL Design Mindset — Chapter 0.2; the Interface → State → Datapath → Control → Verification lenses this page applies (a divider/timer is state plus a tiny bit of control, on one clock).
  • What Is an RTL Design Pattern? — Chapter 0.1; why "generate enables, not clocks" earns the name pattern — a recurring need, a reusable form, a synthesis reality, and a signature silicon-only failure.

Verilog v1 prerequisites (the grammar this pattern transcribes into):

  • Arithmetic Operators — the + 1 advance, the - 1 decrement, and the N - 1 terminal-value computation.
  • Relational Operators — the == terminal compare that fires the tick and the timeout.
  • If-Else Statements — the if (tick) … clock-enable gating and the one-shot-vs-periodic branch at zero.
  • Case Statements — the selection construct behind mode and next-value choices in the counter and timer.
  • Blocking and Non-Blocking Assignments — why every register here uses <= in its single clocked always, the sequential idiom the whole page follows.

11. Summary

  • In RTL you generate clock-enables, not clocks. The design has exactly one clock — the source oscillator; everything "slower" is a one-cycle enable that gates whether a register updates. A divide-by-N is a mod-N counter (3.2) raising a tick high for one cycle every N cycles, and the slow logic is a clock-enabled register (2.2) on the same clock, advancing only on tick. One clock domain, zero skew, every path analyzed.
  • A divided flip-flop output used as a clock is the signature bug. always @(posedge clk_div) on an RTL-generated divided signal creates a new clock domain with skew, an unhandled CDC, and paths STA never sees. It simulates perfectly (zero skew, infinite margin) and passes STA (the clock is undeclared), then fails intermittently in silicon, worse when hot — the worst possible failure profile (the §7 DebugLab). Fix: convert it to a clock-enable on the one source clock.
  • Timers are the same counter, pointed at duration. A loadable down-counter decrements each cycle (or each tick) and raises timeout at zero: one-shot fires once and disarms; periodic auto-reloads and repeats; a watchdog is a periodic timer that resets unless fed. The divider (frequency) and timer (elapsed time) are one atom — a counter reaching a programmed value.
  • A /N tick is a strobe, not a 50%-duty clock — and odd 50%-duty divides need both edges. The mod-N tick is one cycle high, N-1 low; for a symmetric divided clock signal use a toggle-flop (/2^k), and for an exact 50% duty on an odd integer divide you must combine rising- and falling-edge logic, because half of an odd count is not a whole cycle. If duty does not matter, prefer the enable and avoid the issue.
  • Verify by measuring, and prevent the anti-pattern structurally. A clocked self-checking testbench asserts the tick period is exactly N, the slow logic changes only on tick, and the one-shot fires once / periodic repeats at the right interval — self-checking testbenches shown here in SystemVerilog, Verilog, and VHDL. The divided-clock bug, though, is invisible to functional sim; it is caught by structural review, CDC/lint, and STA — so "generate enables, not clocks" is a hard rule enforced by construction, not by a testbench.