You blinked an LED in Day 8 using a simple counter. Now let's go deeper: parameterized counters, modulo-N counters, the crucial difference between a clock divider and a clock enable (and why you should almost always use the latter on FPGAs), and a reusable clkdiv.v module that generates clean enable pulses at any rate.
| Type | Behaviour | Verilog pattern |
|---|---|---|
| Up counter | 0 → MAX → 0 (wraps) | cnt <= cnt + 1 |
| Down counter | MAX → 0 → MAX (wraps) | cnt <= cnt - 1 |
| Modulo-N counter | 0 → N-1 → 0 | if(cnt==N-1) cnt<=0; else cnt<=cnt+1 |
| Loadable counter | load a value, then count | if(load) cnt<=d; else cnt<=cnt+1 |
Generating a new clock signal by toggling a register creates a gated clock — this bypasses the FPGA's dedicated clock distribution network, causes skew, and can fail timing analysis. The right approach: keep everything in the same clock domain, and generate a one-cycle enable pulse at the slower rate. Downstream logic checks if (en) before updating.
| Port | Dir | Width | Meaning |
|---|---|---|---|
| clk | input | 1 | system clock (all logic runs here) |
| rst | input | 1 | synchronous reset |
| en_out | output | 1 | one-cycle high pulse every DIV clock cycles |
// Clock enable generator: pulses en_out for one cycle every DIV clk cycles.
// Use en_out as a gate in downstream always blocks, NOT as a clock signal.
module clkdiv #(parameter DIV = 100) (
input wire clk,
input wire rst,
output reg en_out // one-cycle enable pulse
);
// Width must hold DIV-1. $clog2(DIV) bits is the minimum.
// We use a generous 32-bit counter for clarity.
reg [31:0] cnt;
always @(posedge clk) begin
if (rst) begin
cnt <= 32'd0;
en_out <= 1'b0;
end else if (cnt == DIV - 1) begin
cnt <= 32'd0;
en_out <= 1'b1; // pulse for exactly one cycle
end else begin
cnt <= cnt + 1;
en_out <= 1'b0;
end
end
endmodulemodule slow_counter (input clk, input rst, output reg [7:0] cnt);
wire tick;
clkdiv #(.DIV(100)) div0 (.clk(clk),.rst(rst),.en_out(tick));
always @(posedge clk)
if (rst) cnt <= 8'd0;
else if (tick) cnt <= cnt + 1; // only increments every 100 cycles
endmodule`timescale 1ns/1ps
module tb_clkdiv;
reg clk=0, rst=1;
wire en_out;
clkdiv #(.DIV(4)) dut(.clk(clk),.rst(rst),.en_out(en_out));
always #5 clk=~clk;
integer errors=0, pulses=0;
initial begin
@(posedge clk); rst=0;
repeat(20) begin
@(posedge clk); #1;
if(en_out) begin pulses=pulses+1; $display("pulse at t=%0t",$time);end
end
// Expect 5 pulses in 20 cycles (every 4th cycle)
if(pulses==5) $display("ok got %0d pulses in 20 cycles",pulses);
else begin $display("FAIL: expected 5, got %0d",pulses);errors=errors+1;end
if(errors==0) $display("ALL TESTS PASSED"); else $display("%0d FAILED",errors);
$finish;
end
endmodulepulse at t=45 pulse at t=85 pulse at t=125 pulse at t=165 pulse at t=205 ok got 5 pulses in 20 cycles ALL TESTS PASSED
cnt==N-1 to count 0..N-1 precisely.if(en) to update at the slow rate — no new clock signal created.Clock divider generates a new (slower) clock signal — avoid on FPGAs. Clock enable keeps one clock but pulses an enable signal at the lower rate — the correct FPGA approach.
Counts 0 to N-1 then wraps to 0. Reset when cnt==N-1. Used to generate periodic pulses at non-power-of-2 rates.