The clocked-register template from the Verilog path's sequential-logic lesson โ a single always block, non-blocking assignment, reset checked first โ is the one piece of hardware every structure in this lesson is built from. A counter, a ring counter, a Johnson counter and a linear feedback shift register (LFSR) all look, at the Verilog level, like the same register with a different expression feeding its own next value back into it. This lesson works through that family and verifies four of its members against real simulation output.
Reading time: about 10 minutes.
7.1 The register with enable
An ordinary clocked register updates every clock edge. Adding an en input and checking it inside the clocked block โ after the reset check, before the functional assignment โ turns that into a register that only updates when told to, and holds its value on every other cycle. This single addition is what every counter below actually uses to pause counting without disturbing the stored value, and it is worth separating conceptually from reset: reset forces a known value regardless of enable, while a de-asserted enable simply means "no new information this cycle," which is a different, and much more common, situation in real designs than reset is.
7.2 Modulo-N counters, up and down
A modulo-N counter cycles through N distinct values and then wraps back to the start, rather than rolling over at its register's full binary range. For N values that are not a power of two, the wrap has to be written explicitly โ the hardware does not do it automatically just because the register is wide enough to hold the count.
module mod6_updown (
input wire clk,
input wire rst_n,
input wire en,
input wire up_down, // 1 = count up, 0 = count down
output reg [2:0] count
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 3'd0;
else if (en) begin
if (up_down)
count <= (count == 3'd5) ? 3'd0 : count + 3'd1;
else
count <= (count == 3'd0) ? 3'd5 : count - 3'd1;
end
end
endmodule
The comparison against the boundary value โ count == 3'd5 going up, count == 3'd0 going down โ is the entire modulo-6 behavior; everything else is the ordinary enabled-register template from the previous section. Driven through Icarus Verilog, the counter produces exactly the sequence this reads as:
up count wrapped correctly: 0..5..0
down count OK: wrapped 0->5->4
enable=0 held count at 4
SELF-CHECK PASSED
Counting up wraps 5 back to 0 rather than continuing to 6 or 7, which the register's three bits could otherwise represent; counting down from 0 wraps to 5, not to a negative value, since count is unsigned and the wrap is handled by the explicit comparison rather than by subtraction underflow. Yosys's synthesis and check pass confirmed zero inferred latches and zero problems. That result does not depend on every branch being written out: the if (en) has no else, and in an edge-triggered block a missing branch simply means "keep the old value," which synthesizes to a flip-flop with an enable, not a latch. Latches come from incomplete assignment in a combinational (always @*) block, never from a missing branch in a clocked one.
7.3 Ring and Johnson counters
A ring counter is a shift register whose output is fed back into its own input unchanged, so a single bit (set once at reset) circulates endlessly around an N-bit register, producing N distinct states before repeating. A Johnson counter (also called a switch-tail ring counter) feeds back the complement of the last bit instead of the bit itself, which doubles the period to 2N states for the same N flip-flops โ the extra states come from the register passing through both an all-0s-filling-with-1s phase and an all-1s-filling-with-0s phase before returning to where it started.
module ring4 (
input wire clk,
input wire rst_n,
output wire [3:0] q
);
reg [3:0] state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) state <= 4'b0001;
else state <= {state[0], state[3:1]};
end
assign q = state;
endmodule
module johnson4 (
input wire clk,
input wire rst_n,
output wire [3:0] q
);
reg [3:0] state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) state <= 4'b0000;
else state <= {~state[0], state[3:1]};
end
assign q = state;
endmodule
The only line that differs between them is the bit fed back in: state[0] unchanged for the ring counter, ~state[0] for the Johnson counter. Simulated from their respective reset values:
johnson4 sequence (starting from 0000):
step=0 johnson=1000
step=1 johnson=1100
step=2 johnson=1110
step=3 johnson=1111
step=4 johnson=0111
step=5 johnson=0011
step=6 johnson=0001
step=7 johnson=0000
ring4 sequence (starting from 0001):
step=0 ring=1000
step=1 ring=0100
step=2 ring=0010
step=3 ring=0001
SELF-CHECK PASSED
The ring counter returns to its seed after exactly 4 steps (N states for an N-bit register); the Johnson counter returns to its seed after exactly 8 steps (2N states), visiting four states with a growing run of 1s and four more with a growing run of 0s in between. Thus, both decode very cheaply โ a ring counter's "which position is hot" output needs no logic beyond reading the flip-flop directly, and a Johnson counter's "count so far" can be decoded with a single 2-input gate per output line, which is the usual reason either shows up in a design: not more counting range for the registers spent, but a next-state and output structure simple enough that it rarely becomes a timing bottleneck. Neither is a practical choice when the actual numeric count value matters to the rest of the design โ a modulo-N binary counter remains the right tool there โ since reading "the count" back out of a ring or Johnson pattern means decoding a bit position, not reading a number.
Neither counter is self-correcting. A 4-bit Johnson counter uses 8 of its 16 codes, and the other 8 form a second, disjoint 8-state cycle under the same next-state function: tracing johnson4's RTL from 0010 gives 0010, 1001, 0100, 1010, 1101, 0110, 1011, 0101 and back to 0010, so a counter knocked into any of those codes stays in the wrong cycle forever. A ring counter is worse: it has 2^N - N unused states (12 for N = 4), including 0000 and 1111, which rotate into themselves and never move. Robust designs either rely on reset to place the register in the legal cycle, or add self-correcting feedback that steers any illegal pattern back into it.
7.4 Linear feedback shift registers
A linear feedback shift register builds its feedback bit from an XOR of two or more existing bits (the "taps") rather than from a single bit, and the resulting sequence of states, for the right choice of taps, visits every nonzero value of an N-bit register exactly once before repeating โ a maximal-length sequence of 2^N - 1 states. This is the standard building block behind pseudo-random bit generators, built-in self-test pattern generation, and scrambling, precisely because the sequence looks unstructured bit-by-bit while actually being completely deterministic and reproducible from the seed.
module lfsr4 (
input wire clk,
input wire rst_n,
output wire [3:0] lfsr
);
reg [3:0] state;
wire feedback = state[3] ^ state[2]; // taps 4,3: x^4 + x^3 + 1 in tap notation
always @(posedge clk or negedge rst_n) begin
if (!rst_n) state <= 4'b0001; // any nonzero seed
else state <= {state[2:0], feedback};
end
assign lfsr = state;
endmodule
LFSR visited 15 distinct nonzero states before repeating (expect 15)
SELF-CHECK PASSED
Fifteen is 2^4 - 1 โ every nonzero 4-bit value, confirming the chosen tap positions (taps 4,3, written x^4 + x^3 + 1 in tap notation; its reciprocal x^4 + x + 1 is equally primitive) really do produce a maximal-length sequence for this register width, rather than a shorter repeating cycle. The all-zero state is deliberately excluded from that count on purpose, not as an oversight: an LFSR built purely from XOR feedback can never leave 0000 once it reaches it, since XOR-ing any number of zeros always produces another zero โ which is exactly why the register must be seeded with a nonzero value at reset, and why a design that cannot tolerate ever landing on all-zeros (through a transient fault, for instance) needs an explicit all-zero detector feeding an exception into the feedback path, not just the plain two-tap XOR shown here.
7.5 Interview questions
What is the practical difference between a register's reset and its enable? Reset forces a known value unconditionally, overriding everything else happening that cycle. A de-asserted enable simply holds the current value โ no new information arrives, but nothing is forced either. In an if/else if chain, reset is checked first precisely because it must take priority over enable.
Why does a modulo-6 counter need an explicit comparison against the boundary value, instead of just letting a 3-bit register overflow? A 3-bit register's natural range is 0 through 7, not 0 through 5. Without an explicit check such as count == 3'd5 before wrapping, the counter would count through all eight 3-bit values rather than cycling through six.
What turns a ring counter into a Johnson counter in RTL? Feeding back the complement of the last bit (~state[0]) instead of the bit itself (state[0]). That one change doubles the achievable period from N states to 2N states for the same N-bit register. Neither is self-correcting: a 4-bit Johnson counter's 8 unused codes form a second, disjoint 8-state cycle, and a ring counter's 2^N - N unused states include 0000 and 1111, which never leave. Reset, or added self-correcting feedback, is what keeps either in its legal cycle.
Why must an LFSR built from plain XOR feedback be seeded with a nonzero value? XOR-ing any combination of zeros always produces zero, so an all-zero state is a fixed point the register can never leave once it reaches it. Seeding with any nonzero value at reset keeps the register inside its 2^N - 1 maximal-length cycle.
Key takeaways
- Every structure in this lesson is the same clocked-register template, differing only in the expression fed back into the next-value input โ enable adds a hold condition, a counter adds a boundary comparison, a shift register changes which bits move where.
- A modulo-N counter needs an explicit wraparound comparison whenever N is not a power of two, since the register's natural binary range does not wrap there on its own.
- A ring counter (N states) and a Johnson counter (2N states) differ by one inverted bit in the feedback path, and both trade counting range for next-state and output logic simple enough to decode from a single flip-flop or a single gate; neither is self-correcting, so both depend on reset or added correction logic to stay in their legal cycle.
- A well-chosen pair of XOR taps makes an LFSR visit all 2^N - 1 nonzero states before repeating โ confirmed here for a 4-bit register with taps at bit3 and bit2, giving a 15-state maximal-length sequence.
- An all-zero state is a trap for plain XOR-feedback LFSRs; a nonzero reset seed is what keeps the register inside its intended cycle.