Counters & Registers

Counters and registers are built from flip-flops. Learn asynchronous (ripple) and synchronous counters, up/down and modulo-N counters, frequency division, shift registers (SISO, SIPO, PISO, PIPO), ring and Johnson counters, LFSRs, and finite state machines.

Counters generate timing, divide clocks and count events; shift registers convert between serial and parallel data (as in SPI and UARTs). Together they form the backbone of timers, communication peripherals and control logic.

An analogy

A counter is like a car odometer: each wheel rolls over and advances the next. A shift register is like a bucket brigade passing buckets one position per clock.

Ripple vs synchronous

Ripple counters clock each flip-flop from the previous output — simple but delays accumulate and outputs glitch. Synchronous counters clock all flip-flops together with next-state logic — standard in modern design.

Modulo-N and dividers

Reset or reload the counter at N − 1 to count 0…N − 1. Counters divide clocks (e.g. 50 MHz → 1 Hz needs a 26-bit counter). Cascade decade counters for BCD displays.

Shift registers

SISO (delay), SIPO (serial → parallel: receivers, 74HC595 port expanders), PISO (parallel → serial: transmitters, 74HC165 input expanders), PIPO (storage). Ring and Johnson counters are circulating shift registers.

LFSRs and state machines

Linear-feedback shift registers generate pseudo-random sequences (2ⁿ − 1 states) for CRC, scrambling and BIST. Counters are special finite state machines (Moore/Mealy); FSM design generalises them.

Formulas

Worked example: 1 Hz from 50 MHz

Given: f_in = 50 MHz, f_out = 1 Hz

Find: Counter size.

Answer: 26-bit counter counting 0 … 49 999 999

Worked example: Ripple counter speed

Given: 4-bit ripple counter, t_pd = 10 ns per flip-flop

Find: Max reliable frequency.

Answer: ≈ 25 MHz (synchronous would be much faster)

Modulo-10 counter and shift register

module mod10 (input clk, rst_n, en, output reg [3:0] q, output tc);
  assign tc = (q == 4'd9) & en;               // terminal count
  always @(posedge clk or negedge rst_n)
    if (!rst_n)      q <= 4'd0;
    else if (en)     q <= (q == 4'd9) ? 4'd0 : q + 4'd1;
endmodule

module sipo8 (input clk, sin, output reg [7:0] q);   // serial in, parallel out
  always @(posedge clk) q <= {q[6:0], sin};
endmodule

The synchronous counter wraps at 9 and produces a terminal-count pulse to cascade decades. The shift register moves one bit per clock — exactly what an SPI receiver does.

Common mistakes

Applications

Key takeaways

Going further