A Mod-N counter is a counter that steps through exactly N states, from 0 to N - 1, and then returns to 0. N is called the modulus. In Verilog, a Mod-N counter is a register that increments on every clock edge and is cleared to 0 on the edge after it reaches N - 1, which lets it count or divide by any whole number, not just a power of two.
10 min read | Beginner Level
What You'll Learn
- How a Mod-N counter differs from a plain binary counter, and why N - 1 is the terminal count
- Write a parameterized Mod-N counter with a synchronous clear
- Why a synchronous clear is preferred over an asynchronous one
- How to size the counter, handle unused states and chain counters with a terminal count
What Is a Mod-N Counter?
Every binary counter is already a Mod-N counter with N equal to a power of two: a 3-bit counter is Mod-8, and a 4-bit counter is Mod-16. Those counters wrap around by themselves, because the carry out of the top bit is dropped.
Many applications need a modulus that is not a power of two, such as Mod-5, Mod-6, Mod-10, Mod-12 or Mod-60. A register of a given width cannot produce these by itself. A 4-bit register can hold 16 values, so a Mod-10 counter built from it has to be forced back to 0 after 9. The remaining six values, 10 to 15, are never used.
| Modulus N | Bits needed, $clog2(N) | Unused states | Typical use |
|---|---|---|---|
| 6 | 3 | 2 | Tens of seconds or minutes (0 to 5) |
| 10 | 4 | 6 | Decimal (BCD) digits |
| 12 | 4 | 4 | Hours on a 12-hour clock, months |
| 60 | 6 | 4 | Seconds and minutes |
Counting Sequence
The counter increments by 1 on each active clock edge. When it holds N - 1, the next edge loads 0 instead of N, so each cycle visits exactly N states: 0, 1, 2, ..., N - 1, 0, 1, ...
Because one full cycle takes N clock periods, a signal that marks one point in the cycle, such as a pulse while the count equals N - 1, repeats at the clock frequency divided by N:
f_out = f_clk / N
For example, a Mod-10 counter on a 1 MHz clock produces one pulse every 10 cycles, a 100 kHz rate. This is why Mod-N counters are used for timekeeping, baud rate generation and clock division.
How to reset
When N is not a power of two, the counter does not roll over at the right point on its own, so the design must detect the last state and force the count back to 0. There are two ways to do it, and the choice affects the reliability of the hardware.
Approach 1: Count-to-N-then-Reset (Synchronous Clear)
The counter counts normally up to N - 1. A comparator detects that the count equals N - 1, and on the next clock edge the register loads 0 instead of the incremented value. The value N never appears. The counter holds N - 1 for a full clock cycle, like every other state, and all changes happen on the clock edge, so timing is predictable and easy to analyze.
Approach 2: Count-to-N-then-Reset (Asynchronous or Instantaneous Clear)
In this older style, often seen in discrete-logic designs, the counter is allowed to reach N. Logic that detects the value N drives the counter's asynchronous clear, which forces it to 0 almost immediately. The value N exists only for a very short time, as a glitch that is easy to miss in a waveform. This approach has serious problems:
- The glitch is real. Logic that decodes the count can see the brief value N and react to it.
- The clear pulse lasts only until the counter clears, which removes the condition that created it. If the pulse is too short, some flip-flops may clear and others may not.
- The state changes are no longer synchronous to the clock, which complicates timing analysis and can cause metastability.
Modern design guidelines use the synchronous clear of Approach 1, and the design below follows it.
Pros/Cons
Advantages:
- Divides by any integer N, while a plain binary counter can only divide by powers of two
- The terminal count (count equal to N - 1) gives a one-cycle pulse that can enable the next counter, so counters with different moduli chain into larger counting systems
- The modulus is a parameter, so one module serves every value of N
Disadvantages:
- Unused states exist whenever N is not a power of two. Designs that must recover from any state, such as safety-critical designs, need logic that guarantees an escape from them
- The comparison against N - 1 adds logic to the counter's feedback path, which can limit the maximum clock frequency of wide or very fast counters
Design
module modN_ctr
# (parameter N = 10, // Modulus: number of states
parameter WIDTH = 4) // Register width: must satisfy 2**WIDTH >= N
( input clk,
input rstn, // Active-low synchronous reset
output reg[WIDTH-1:0] out);
always @ (posedge clk) begin
if (!rstn) begin
out <= 0;
end else begin
if (out == N-1) // Terminal count reached
out <= 0; // Synchronous clear on this edge
else
out <= out + 1;
end
end
endmodule
Synthesis result: The tool builds WIDTH flip-flops, an incrementer, and a comparator that checks out == N-1. Because N is a constant, the comparator reduces to a small AND gate on the bits that are 1 in N - 1. For N = 10, N - 1 is 4'b1001, so the comparator checks out[3] & ~out[2] & ~out[1] & out[0]. A mux then selects 0 or out + 1 for the flip-flops' D inputs.
Instead of passing WIDTH separately, derive it from N so the two can never disagree: declare localparam WIDTH = $clog2(N); inside the module and remove WIDTH from the parameter list.
Quick Check
Q: In modN_ctr with N = 10, a radiation upset flips a bit and out becomes 12. What happens next?
Show Answer
It counts 13, 14, 15, then the 4-bit increment wraps to 0, and normal counting resumes. The counter recovers by itself after a few cycles, but it produces wrong values in the meantime. Writing the comparison as out >= N-1 makes any unused value clear to 0 on the next edge.
Where are Mod-N Counters Used?
Real-time clock blocks count time with a chain of Mod-N counters: Mod-60 for seconds, Mod-60 for minutes and Mod-24 for hours, often split further into BCD digits such as Mod-10 and Mod-6. Each counter's terminal count enables the next one, so the hours counter advances once every 3600 seconds.
Testbench
The testbench uses a 20 ns clock period, holds reset for two clock edges, then runs for 20 edges, which is enough to see two full cycles of a Mod-10 counter.
module tb;
parameter N = 10;
parameter WIDTH = 4;
reg clk;
reg rstn;
wire [WIDTH-1:0] out;
// Pass the testbench parameters to the design so both use the same values
modN_ctr #(.N(N), .WIDTH(WIDTH)) u0 ( .clk(clk),
.rstn(rstn),
.out(out));
always #10 clk = ~clk; // Rising edges at 10, 30, 50, ...
initial begin
{clk, rstn} <= 0;
$monitor ("T=%0t rstn=%0b out=0x%0h", $time, rstn, out);
repeat(2) @ (posedge clk);
rstn <= 1;
repeat(20) @ (posedge clk);
$finish;
end
endmodule
$ /usr/bin/vvp simulation +random_seed+2011182796 T=0 rstn=0 out=0xx T=10 rstn=0 out=0x0 T=30 rstn=1 out=0x0 T=50 rstn=1 out=0x1 T=70 rstn=1 out=0x2 T=90 rstn=1 out=0x3 T=110 rstn=1 out=0x4 T=130 rstn=1 out=0x5 T=150 rstn=1 out=0x6 T=170 rstn=1 out=0x7 T=190 rstn=1 out=0x8 T=210 rstn=1 out=0x9 T=230 rstn=1 out=0x0 T=250 rstn=1 out=0x1 T=270 rstn=1 out=0x2 T=290 rstn=1 out=0x3 T=310 rstn=1 out=0x4 T=330 rstn=1 out=0x5 T=350 rstn=1 out=0x6 T=370 rstn=1 out=0x7 T=390 rstn=1 out=0x8 T=410 rstn=1 out=0x9 testbench.v:23: $finish called at 430 (1ns) T=430 rstn=1 out=0x0 ✓ Simulation completed successfully in 0.17s
Reset clears out at the first edge (10 ns) and is released at 30 ns. The count then runs 1 to 9 and, at 230 ns, returns to 0 instead of continuing to 10 (0xa). One full cycle takes 10 clock periods (200 ns), so a signal decoded from this counter would repeat at 1/10 of the clock frequency.
Video Timing Generators
A display controller scans each frame with two Mod-N counters. For a 640 x 480 display at 60 Hz, a Mod-800 counter tracks the pixel position along a line, including the blanking interval, and a Mod-525 counter tracks the line number. Comparators on the two counts generate the horizontal and vertical sync pulses.
Decade Counters in Instruments
Frequency counters and digital meters display their results in decimal, so their counting chains use Mod-10 (decade) counters, one per displayed digit. Each digit's terminal count enables the next digit, and the outputs drive the display decoders directly, with no binary-to-decimal conversion.
Quick Check
Q: You need a Mod-100 counter. What is the smallest WIDTH that works, and how many states are unused?
Show Answer
WIDTH = 7, since 26 = 64 is too small and 27 = 128 is enough. 128 - 100 = 28 states are unused. $clog2(100) gives 7 directly.
Common Beginner Mistakes
Mistake #1: Comparing against N instead of N - 1
Wrong: if (out == N) out <= 0;
Right: if (out == N-1) out <= 0;
Why? With a synchronous clear, the counter loads 0 on the edge after the comparison is true. Comparing against N lets the counter reach N, so it cycles through N + 1 states (0 to N) and divides by N + 1 instead of N.
Mistake #2: WIDTH too small for N
Wrong: modN_ctr #(.N(20), .WIDTH(4))
Right: modN_ctr #(.N(20), .WIDTH(5)), or derive WIDTH with $clog2(N)
Why? A 4-bit out can only reach 15, so out == 19 is never true. The counter wraps naturally at 15 and silently becomes a Mod-16 counter. Simulation runs without errors and synthesis may only warn that the comparison is always false.
Mistake #3: Not passing parameters to the instance
Wrong: modN_ctr u0 (.clk(clk), .rstn(rstn), .out(out)); in a testbench whose own parameter is N = 6
Right: modN_ctr #(.N(N), .WIDTH(WIDTH)) u0 (...);
Why? A parameter declared in the testbench is a different parameter from the one in the design. Without the #( ) override, the instance uses its own default values, here N = 10, and the test checks the wrong configuration. See Verilog Parameters.
Mistake #4: Clearing through the asynchronous reset
Wrong: assign clr_n = rstn & ~(out == N); driving an asynchronous active-low reset input of the counter
Right: Clear synchronously inside the clocked block, with if (out == N-1) out <= 0;
Why? The counter briefly reaches N, and the clear pulse ends as soon as the counter starts clearing, so it can be too short to clear every flip-flop reliably. The brief value N also appears as a glitch on the outputs. This is Approach 2 described above.
Practice Exercise
Challenge: Seconds Counter from Two Mod-N Counters
Add an enable input en and a terminal count output tc to the Mod-N counter, creating modN_ctr_en. tc should be high while en is 1 and the count equals N - 1. Then build a module seconds that counts 0 to 59 as two BCD digits: a Mod-10 counter for the ones digit, and a Mod-6 counter for the tens digit that advances only when the ones digit wraps. Assume tick is a one-cycle pulse once per second.
Hint
Connect tick to the en of the ones counter, and connect the ones counter's tc to the en of the tens counter. Both counters use the same clock.
Solution
module modN_ctr_en #(parameter N = 10, parameter WIDTH = $clog2(N)) (
input clk,
input rstn,
input en, // Count only when en is 1
output reg [WIDTH-1:0] out,
output tc // High during the last state while enabled
);
always @(posedge clk) begin
if (!rstn)
out <= 0;
else if (en) begin
if (out == N-1) out <= 0;
else out <= out + 1'b1;
end
end
assign tc = en & (out == N-1);
endmodule
module seconds (
input clk,
input rstn,
input tick, // One-cycle pulse, once per second
output [3:0] ones, // 0 to 9
output [2:0] tens // 0 to 5
);
wire ones_tc;
modN_ctr_en #(.N(10)) u_ones (.clk(clk), .rstn(rstn), .en(tick),
.out(ones), .tc(ones_tc));
// The tens digit advances only when the ones digit wraps from 9 to 0
modN_ctr_en #(.N(6)) u_tens (.clk(clk), .rstn(rstn), .en(ones_tc),
.out(tens), .tc());
endmodule
The counters together step through 00 to 59 and back to 00, one step per tick. u_tens's own tc marks the end of each minute and could enable a minutes counter. Both counters share clk, so the whole chain stays synchronous.
Summary
In this tutorial, you learned:
- A Mod-N counter cycles through N states, from 0 to N - 1, and divides the clock frequency by N
- When N is not a power of two, the counter must detect N - 1 and clear itself
- A synchronous clear on the edge after N - 1 is reliable; an asynchronous clear at N creates glitches
- The register needs
$clog2(N)bits, and the remaining states are unused - Comparing with
>= N-1makes the counter leave any unused state on the next edge - A terminal count output lets Mod-N counters chain, for example into seconds, minutes and hours
- Pass parameters explicitly with
#( )so the instance uses the intended modulus