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.
📋 Types of Clock Dividers
| Divider type | Division ratio | Duty cycle | Implementation | 100 MHz example |
|---|---|---|---|---|
| Divide-by-2 | 2 only | 50% always | Single DFF (toggle) | 50 MHz |
| Divide-by-N even | Any even N | 50% | Counter + toggle at N/2 | 25 MHz (N=4), 12.5 MHz (N=8) |
| Divide-by-N odd | Any odd N | 50% (dual-edge) | Two counters + OR | 33.3 MHz (N=3), 20 MHz (N=5) |
| Fractional | N + 0.5 | ~44-50% | Accumulator + toggle | 40 MHz (N=2.5), 28.6 MHz (N=3.5) |
🔌 Circuit Diagram
⚫ 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.
// ============================================================ // 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
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.
// ============================================================ // 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
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%
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.
// ============================================================ // 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
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
🟣 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.
// ============================================================ // 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
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.
// ============================================================ // 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
💻 Simulation Console Output
How to Run
# 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
| Module | Division ratio | Duty cycle | Flip-flops | Edges used | FPGA-safe? |
|---|---|---|---|---|---|
| clk_div2 | 2 only | 50% exact | 1 | posedge | Yes |
| clk_div_even | Any even N | 50% | ceil(log2 N)+1 | posedge | Yes |
| clk_div_odd | Any odd N | 50% | 2*ceil(log2 N)+2 | posedge + negedge | ASIC only |
| clk_div_frac | N + 0.5 | ~43-50% | ceil(log2(2N+2))+1 | posedge | Yes |
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.
always @(posedge clk) if (ce) q <= d; where ce pulses every N cycles. RTL clock dividers are correct for simulation and ASIC flows.
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.
// 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.
