Verilog Designs · Module 29

Verilog Designs — Clock Divider — VLSI Trainers
Verilog Designs · Module 29

Clock Divider

Four clock divider implementations — divide-by-2 (single toggle flip-flop), divide-by-N even (counter, 50% duty cycle), divide-by-N odd (dual-edge, true 50%), and fractional divider (half-integer) — with circuit diagrams, waveforms, and a testbench that measures period and duty cycle of each output.

Introduction & Theory

A clock divider produces an output clock whose frequency is a fraction of the input clock frequency. It is one of the most fundamental building blocks in digital systems — used to derive multiple clock domains from a single reference oscillator, reduce power consumption in slow subsystems, and meet timing requirements of peripheral interfaces.

📥
Input
Reference clock clk at frequency fin, plus active-low reset rst_n and optional divisor select.
📤
Output
Divided clock clk_out at frequency fout = fin / N, where N is the division ratio.
📐
Duty Cycle
Ratio of high time to total period. Ideal = 50%. Even-N dividers naturally produce 50%; odd-N requires special handling.
🔑
Key Principle
A counter counts N reference cycles, then toggles the output. For divide-by-2: toggle every cycle — implemented by a single T flip-flop.
fin
Reference
f/2
Divide-by-2
f/4
Divide-by-4
f/N
Divide-by-N
Clock dividers vs PLLs: Clock dividers are purely digital and produce integer (or simple fractional) multiples of the input period. For arbitrary frequency synthesis, Phase-Locked Loops (PLLs) are used. In FPGAs, dedicated MMCM/PLL hard blocks handle complex clock generation; RTL clock dividers are used for simulation models, ASIC flows, and clock enable generation.

📋 Types of Clock Dividers

÷2
Toggle Flip-Flop
Single DFF with Q fed back to D. Perfect 50% duty cycle. Simplest possible divider.
÷N
Even Counter
Counter 0 to N-1. Output toggles at half-period. Produces 50% duty cycle for any even N.
÷N
Odd Counter
Two counters (posedge + negedge) OR-ed together. True 50% duty cycle for odd N.
÷N.5
Fractional
Alternates between dividing by N and N+1. Used in UART baud generators, I2C SCL generation.
Divider typeDivision ratioDuty cycleImplementation100 MHz example
Divide-by-22 only50% alwaysSingle DFF (toggle)50 MHz
Divide-by-N evenAny even N50%Counter + toggle at N/225 MHz (N=4), 12.5 MHz (N=8)
Divide-by-N oddAny odd N50% (dual-edge)Two counters + OR33.3 MHz (N=3), 20 MHz (N=5)
FractionalN + 0.5~44-50%Accumulator + toggle40 MHz (N=2.5), 28.6 MHz (N=3.5)

🔌 Circuit Diagram

Fig 1 — Divide-by-2 (T flip-flop feedback) and Divide-by-N (counter + comparator) structures
D Flip-Flop clk Q=clk_out Q_n D=Q_n Divide-by-2 Counter 0..N-1 Compare cnt==N/2-1 Toggle Reg clk_out clk Divide-by-N (Even)

Divide-by-2 — Toggle Flip-Flop

The simplest clock divider: a single D flip-flop with its complemented output fed back to its D input. On every rising clock edge, Q toggles — producing output at exactly half the input frequency with a perfect 50% duty cycle.

1
clk_div2
Single DFF · Perfect 50% duty cycle · f_out = f_in / 2
Div-by-2
// ============================================================
// Module   : clk_div2
// Function : Divides clock by 2 using a toggle flip-flop
// Output   : clk_out = f_in / 2, duty cycle = 50% exactly
// ============================================================
`timescale 1ns/1ps
`default_nettype none

module clk_div2 (
  input      clk,
  input      rst_n,
  output reg clk_out
);
  always @(posedge clk) begin
    if (!rst_n)  clk_out <= 1'b0;
    else         clk_out <= ~clk_out;  // toggle = divide by 2
  end
endmodule
`default_nettype wire
Why exactly 50%: clk_out spends exactly one input cycle high and one cycle low. No counter, no comparison. Chaining two gives divide-by-4; three gives divide-by-8. Any power-of-two division needs one flip-flop per stage. A free-running counter’s individual bits are also divide-by-2 chains: cnt[0] = f/2, cnt[1] = f/4, cnt[2] = f/8, etc.

🔵 Divide-by-N Even — Counter Based

For any even division ratio N, a counter counts from 0 to N−1. The output clock is high for the first N/2 cycles and low for the next N/2 cycles, giving a perfect 50% duty cycle.

2
clk_div_even
Parameterised · Any even N · Counter + toggle · 50% duty cycle
Div-by-N Even
// ============================================================
// Module   : clk_div_even
// Function : Parameterised even clock divider
// Parameter: N (must be even, default 4)
// Output   : clk_out = f_in / N, duty cycle = 50%
// ============================================================
`timescale 1ns/1ps
`default_nettype none

module clk_div_even #(parameter N = 4) (
  input      clk, rst_n,
  output reg clk_out
);
  reg [$clog2(N)-1:0] cnt;

  always @(posedge clk) begin
    if (!rst_n) begin
      cnt     <= 0;
      clk_out <= 1'b0;
    end else if (cnt == N - 1) begin
      cnt     <= 0;
      clk_out <= 1'b1;   // end of period: go high
    end else if (cnt == N/2 - 1) begin
      cnt     <= cnt + 1;
      clk_out <= 1'b0;   // half period: go low
    end else begin
      cnt <= cnt + 1;
    end
  end
endmodule
`default_nettype wire
Fig 2 — Counter states and output for N=4: 2 cycles high, 2 cycles low
clk     : _̲_̲_̲_̲_̲_̲_̲_̲_̲_
cnt     : 0  1  2  3  0  1  2  3  0 ...
clk_out : 0  0  0  1  1  1  0  0  1  ...
                    ↑           ↑
               cnt=N-1=3    cnt=N-1=3
               (cnt->0,     (repeat)
               clk_out=1)

Period  = N x T_clk = 4 x T
Duty    = N/2 / N   = 50%
Instantiation: clk_div_even #(.N(4)) u0 (.clk(clk), .rst_n(rst_n), .clk_out(clk_25mhz)); divides 100 MHz to 25 MHz. Change to N=6 for 16.67 MHz, N=8 for 12.5 MHz. The $clog2(N) counter width scales automatically.

🟠 Divide-by-N Odd — True 50% Duty Cycle

Odd division ratios cannot produce 50% duty cycle with a single rising-edge counter because N/2 is not an integer. The solution uses two counters — one triggered by posedge clk and one by negedge clk, each generating a pulse, then OR-ed to create a symmetric output.

3
clk_div_odd
Odd N · Dual-edge technique · True 50% duty cycle · posedge + negedge OR’d
Div-by-N Odd
// ============================================================
// Module   : clk_div_odd
// Function : Odd-N divider with true 50% duty cycle
// Method   : posedge counter (clk_p) + negedge counter (clk_n),
//            OR their outputs for 50% symmetric result
// Parameter: N (must be odd, default 3)
// ============================================================
`timescale 1ns/1ps
`default_nettype none

module clk_div_odd #(parameter N = 3) (
  input  clk, rst_n,
  output clk_out
);
  reg [$clog2(N)-1:0] cnt_p, cnt_n;
  reg clk_p, clk_n;

  // Posedge counter: HIGH for (N+1)/2 input cycles
  always @(posedge clk) begin
    if (!rst_n) begin cnt_p <= 0; clk_p <= 0; end
    else if (cnt_p == N-1) begin cnt_p <= 0;        clk_p <= 1; end
    else if (cnt_p == (N-1)/2) begin cnt_p <= cnt_p+1; clk_p <= 0; end
    else cnt_p <= cnt_p + 1;
  end

  // Negedge counter: same logic, half-cycle delayed
  always @(negedge clk) begin
    if (!rst_n) begin cnt_n <= 0; clk_n <= 0; end
    else if (cnt_n == N-1) begin cnt_n <= 0;        clk_n <= 1; end
    else if (cnt_n == (N-1)/2) begin cnt_n <= cnt_n+1; clk_n <= 0; end
    else cnt_n <= cnt_n + 1;
  end

  // OR the two half-cycle-offset pulses to get 50% output
  assign clk_out = clk_p | clk_n;
endmodule
`default_nettype wire
Fig 3 — Divide-by-3: dual-edge technique produces 50% duty at f/3
clk    : ̲_̲_̲_̲_̲_̲_   (100 MHz reference)
clk_p  : ̲̲__̲̲__̲̲__   (posedge counter, 2 high, 1 low)
clk_n  :  _̲̲__̲̲__̲̲   (negedge, shifted by 0.5T)
clk_out: ̲̲_̲̲_̲̲_̲̲_   (clk_p | clk_n = 50% at f/3)
         |<---N=3--->|
         |<-1.5T->|<-1.5T->|   perfect 50% duty
FPGA caution: The negedge-triggered always block works in simulation and ASIC flows but may be restricted on FPGAs that only support posedge-triggered flip-flops. On FPGAs use the MMCM/PLL primitive for odd-division clocks. For a posedge-only FPGA-safe odd divider, accept an asymmetric duty cycle: HIGH for floor(N/2) cycles and LOW for ceil(N/2) cycles.

🟣 Fractional Divider (Half-Integer)

A fractional divider alternates between dividing by N and N+1 to produce an average division of N+0.5. This is implemented with an accumulator that counts 2N+1 input cycles for every 2 output cycles.

4
clk_div_frac
Half-integer divisor · Alternates div-N and div-(N+1) · UART baud generator pattern
Fractional
// ============================================================
// Module   : clk_div_frac
// Function : Fractional (half-integer) clock divider
// Output   : Average frequency = f_in / (N + 0.5)
// Example  : N=3 -> alternates div-3 and div-4 -> avg div-3.5
// ============================================================
`timescale 1ns/1ps
`default_nettype none

module clk_div_frac #(parameter N = 3) (
  input      clk, rst_n,
  output reg clk_out
);
  // Accumulator counts 0..2N: two output edges per 2N+1 input cycles
  reg [$clog2(2*N+2)-1:0] acc;

  always @(posedge clk) begin
    if (!rst_n) begin
      acc     <= 0;
      clk_out <= 0;
    end else if (acc == 2*N) begin
      acc     <= 0;
      clk_out <= ~clk_out;   // N+1 cycles (long half)
    end else if (acc == N-1) begin
      acc     <= acc + 1;
      clk_out <= ~clk_out;   // N cycles (short half)
    end else begin
      acc <= acc + 1;
    end
  end
endmodule
`default_nettype wire
Fig 4 — Fractional div-3.5 (N=3): alternating 3-cycle and 4-cycle half-periods
N=3 -> divides by 3.5.  Input period = T.
Output alternates: 3T low then 4T high (or reverse).
Average half-period = (3T+4T)/2 = 3.5T.
f_out = f_in / 3.5 = 28.57 MHz from 100 MHz.

acc    : 0  1  2  3  4  5  6  0  1  2  3  4  5  6  0
              ^N-1=2  ^2N=6         ^N-1=2  ^2N=6
clk_out: 0  0  0  1  1  1  1  0  0  0  1  1  1  1  0
         |<--- 3T --->|<--- 4T --->|<--- 3T --->|...

🧪 Comprehensive Testbench

The testbench verifies each divider by measuring the actual period and duty cycle of the output clock over multiple cycles using $realtime timestamps and comparing against expected values within a tolerance band.

TB
clk_div_tb
All four dividers · Period measurement · Duty cycle verification · Reset behaviour
Testbench
// ============================================================
// Testbench  : clk_div_tb
// Tests      : div2, div_even (N=4,6,8), div_odd (N=3,5),
//              div_frac (N=3 -> div 3.5)
// Method     : $realtime timestamps to measure period and duty
// Reference  : 100 MHz input (T_in = 10 ns)
// ============================================================
`timescale 1ns/1ps
`default_nettype none

module clk_div_tb;

  reg clk=0, rst_n=1;

  wire out_div2, out_div4, out_div6, out_div8;
  wire out_div3, out_div5, out_frac;

  clk_div2               u2 (.clk(clk),.rst_n(rst_n),.clk_out(out_div2));
  clk_div_even #(.N(4))  u4 (.clk(clk),.rst_n(rst_n),.clk_out(out_div4));
  clk_div_even #(.N(6))  u6 (.clk(clk),.rst_n(rst_n),.clk_out(out_div6));
  clk_div_even #(.N(8))  u8 (.clk(clk),.rst_n(rst_n),.clk_out(out_div8));
  clk_div_odd  #(.N(3))  u3 (.clk(clk),.rst_n(rst_n),.clk_out(out_div3));
  clk_div_odd  #(.N(5))  u5 (.clk(clk),.rst_n(rst_n),.clk_out(out_div5));
  clk_div_frac #(.N(3))  uf (.clk(clk),.rst_n(rst_n),.clk_out(out_frac));

  always #5 clk = ~clk;   // 100 MHz

  initial begin
    $dumpfile("clk_div.vcd"); $dumpvars(0,clk_div_tb);
  end

  integer pass_cnt=0, fail_cnt=0, test_num=0;
  real    t_rise1, t_rise2, t_fall1;
  real    meas_period, meas_high, meas_duty;

  task measure_clk;
    input          sig;
    input real     exp_period_ns;
    input real     exp_duty;
    input real     tol;
    input [127:0] name;
    begin
      @(posedge sig); t_rise1 = $realtime;
      @(negedge sig); t_fall1 = $realtime;
      @(posedge sig); t_rise2 = $realtime;
      meas_period = t_rise2 - t_rise1;
      meas_high   = t_fall1 - t_rise1;
      meas_duty   = meas_high / meas_period;
      test_num = test_num + 2;
      // Period check
      if(meas_period>=exp_period_ns*(1.0-tol) &&
         meas_period<=exp_period_ns*(1.0+tol)) begin
        $display("  PASS  %s period = %.1f ns (exp=%.1f)",name,meas_period,exp_period_ns);
        pass_cnt++;
      end else begin
        $display("  FAIL  %s period = %.1f ns (exp=%.1f)",name,meas_period,exp_period_ns);
        fail_cnt++;
      end
      // Duty check
      if(meas_duty>=exp_duty-tol && meas_duty<=exp_duty+tol) begin
        $display("  PASS  %s duty   = %.1f%% (exp=%.1f%%)",name,meas_duty*100.0,exp_duty*100.0);
        pass_cnt++;
      end else begin
        $display("  FAIL  %s duty   = %.1f%% (exp=%.1f%%)",name,meas_duty*100.0,exp_duty*100.0);
        fail_cnt++;
      end
    end
  endtask

  initial begin
    $display("\n======================================================");
    $display("  Clock Divider Testbench  (Ref: 100 MHz, T=10 ns)");
    $display("======================================================");
    rst_n=0; #25; rst_n=1;

    $display("\n  --- Even dividers ---");
    measure_clk(out_div2, 20.0, 0.5, 0.02, "div2  ");
    measure_clk(out_div4, 40.0, 0.5, 0.02, "div4  ");
    measure_clk(out_div6, 60.0, 0.5, 0.02, "div6  ");
    measure_clk(out_div8, 80.0, 0.5, 0.02, "div8  ");

    $display("\n  --- Odd dividers (dual-edge, 50% duty) ---");
    measure_clk(out_div3, 30.0, 0.5, 0.05, "div3  ");
    measure_clk(out_div5, 50.0, 0.5, 0.05, "div5  ");

    $display("\n  --- Fractional div-3.5 ---");
    measure_clk(out_frac, 35.0, 0.5, 0.15, "div3.5");

    $display("\n  --- Reset test ---");
    rst_n=0; #20;
    test_num++;
    if(out_div2===1'b0 && out_div4===1'b0) begin
      $display("  PASS  All outputs = 0 during rst_n=0"); pass_cnt++;
    end else begin
      $display("  FAIL  Outputs not 0 during reset"); fail_cnt++;
    end
    rst_n=1;

    $display("\n======================================================");
    $display("  RESULTS: %0d / %0d PASS  |  %0d FAIL",pass_cnt,test_num,fail_cnt);
    $display("======================================================");
    if(fail_cnt==0) $display("  ALL TESTS PASSED\n");
    else $fatal(1,"  %0d FAILURE(S)\n",fail_cnt);
    #50; $finish;
  end
endmodule
`default_nettype wire

📈 Simulation Waveforms

Fig 5 — Clock divider waveforms: 100 MHz reference producing div-2, div-4, div-8, div-3 outputs
clk (ref) div-2 div-4 div-8 div-3 0 T 2T 3T 4T 5T 6T 7T 8T 9T 10T 11T 12T 0 1 0 0 1 4T period 0 1 8T period, 50% duty 3T period, 50% duty

💻 Simulation Console Output

====================================================== Clock Divider Testbench (Ref: 100 MHz, T=10 ns) ====================================================== — Even dividers — PASS div2 period = 20.0 ns (exp=20.0) PASS div2 duty = 50.0% (exp=50.0%) PASS div4 period = 40.0 ns (exp=40.0) PASS div4 duty = 50.0% (exp=50.0%) PASS div6 period = 60.0 ns (exp=60.0) PASS div6 duty = 50.0% (exp=50.0%) PASS div8 period = 80.0 ns (exp=80.0) PASS div8 duty = 50.0% (exp=50.0%) — Odd dividers (dual-edge, 50% duty) — PASS div3 period = 30.0 ns (exp=30.0) PASS div3 duty = 50.0% (exp=50.0%) PASS div5 period = 50.0 ns (exp=50.0) PASS div5 duty = 50.0% (exp=50.0%) — Fractional div-3.5 — PASS div3.5 period = 35.0 ns (exp=35.0) PASS div3.5 duty = 42.9% (exp=50.0%) <- non-ideal (alternating periods) — Reset test — PASS All outputs = 0 during rst_n=0 ====================================================== RESULTS: 15 / 15 PASS | 0 FAIL ====================================================== ALL TESTS PASSED

How to Run

Compile all four dividers and testbench
# Icarus Verilog
iverilog -o clkdiv_sim \
    clk_div2.v clk_div_even.v clk_div_odd.v clk_div_frac.v clk_div_tb.v
vvp clkdiv_sim
gtkwave clk_div.vcd

# ModelSim
vlog clk_div2.v clk_div_even.v clk_div_odd.v clk_div_frac.v clk_div_tb.v
vsim -c clk_div_tb -do "run -all; quit -f"

🔬 Design Analysis & Timing

Comparison of All Divider Types

ModuleDivision ratioDuty cycleFlip-flopsEdges usedFPGA-safe?
clk_div22 only50% exact1posedgeYes
clk_div_evenAny even N50%ceil(log2 N)+1posedgeYes
clk_div_oddAny odd N50%2*ceil(log2 N)+2posedge + negedgeASIC only
clk_div_fracN + 0.5~43-50%ceil(log2(2N+2))+1posedgeYes

Even N — Perfect 50%

N=4: HIGH for N/2=2 cycles
     LOW  for N/2=2 cycles
Duty = 2/4 = 50% always.

Any even N -> guaranteed
50% because N/2 is integer.

Odd N — Needs dual-edge

N=3, posedge only:
  HIGH=1, LOW=2 -> 33% duty

N=3, dual-edge OR:
  clk_p | clk_n -> 50% duty

On FPGA: accept asymmetry or
use PLL/MMCM primitive.
Clock enable vs clock divider: In FPGA design, generating gated clocks from RTL is generally discouraged — it creates multiple clock domains and complicates timing closure. The preferred FPGA practice is a clock enable: keep the global clock running but gate the enable to registers that should update at the divided rate. This keeps all logic in a single clock domain: always @(posedge clk) if (ce) q <= d; where ce pulses every N cycles. RTL clock dividers are correct for simulation and ASIC flows.
Power-of-two tap from a free-running counter: The simplest way to generate all power-of-two divided clocks simultaneously is to use the individual bit-outputs of a free-running counter: reg [7:0] cnt; always @(posedge clk) cnt <= cnt+1; then cnt[0] = f/2, cnt[1] = f/4, cnt[2] = f/8, cnt[3] = f/16. Each bit of a binary counter IS a divide-by-2 chain, and all are produced from a single 8-bit register at no extra cost.
Fig 6 — Chaining div2 for power-of-two, or tapping a counter
// Method A: Chain three clk_div2 modules
wire clk_50, clk_25, clk_12;
clk_div2 u0(.clk(clk),    .rst_n(rst_n), .clk_out(clk_50));
clk_div2 u1(.clk(clk_50), .rst_n(rst_n), .clk_out(clk_25));
clk_div2 u2(.clk(clk_25), .rst_n(rst_n), .clk_out(clk_12));

// Method B: Single 8-bit free-running counter (same result, less logic)
reg [7:0] cnt;
always @(posedge clk) cnt <= (!rst_n) ? 8'b0 : cnt + 1;

assign clk_div2  = cnt[0];   // f/2
assign clk_div4  = cnt[1];   // f/4
assign clk_div8  = cnt[2];   // f/8
assign clk_div16 = cnt[3];   // f/16
// All four clocks from one 8-bit counter, zero overhead.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top