Ring Counter & Johnson Counter Verilog Code (4-bit)
A ring counter and a Johnson counter are shift-register counters that circulate a bit pattern around a register instead of counting up in binary. Below is complete, runnable 4-bit Verilog for each, with a synchronous reset that seeds a known starting value and a testbench that prints the pattern on every clock edge. Copy a block, simulate it, and watch the single hot bit (or the growing block of ones) walk around the four flip-flops.
Ring counter Verilog code (4-bit)
The ring counter holds a single 1 and rotates it left one position per clock. Reset seeds the register to 0001 so exactly one bit is hot before the rotation begins.
// ring_counter.v -- 4-bit one-hot ring counter with synchronous reset seeding
module ring_counter #(
parameter WIDTH = 4
)(
input wire clk,
input wire rst, // synchronous, active-high
output reg [WIDTH-1:0] q
);
always @(posedge clk) begin
if (rst)
q <= {{(WIDTH-1){1'b0}}, 1'b1}; // seed a single 1 -> 0001
else
q <= {q[WIDTH-2:0], q[WIDTH-1]}; // rotate left, MSB wraps to LSB
end
endmodule
// tb_ring_counter.v
module tb_ring_counter;
localparam WIDTH = 4;
reg clk = 1'b0;
reg rst;
wire [WIDTH-1:0] q;
ring_counter #(.WIDTH(WIDTH)) dut (.clk(clk), .rst(rst), .q(q));
always #5 clk = ~clk; // 10 ns period
integer i;
initial begin
$display("time | rst | q(bin) | q(hex)");
$monitor("%4t | %b | %b | %h", $time, rst, q, q);
rst = 1'b1; // assert reset to seed 0001
@(posedge clk); #1;
rst = 1'b0; // release, let the 1 circulate
for (i = 0; i < 8; i = i + 1) @(posedge clk);
#1;
$display("Done: pattern circulated through all %0d positions twice.", WIDTH);
$finish;
end
endmoduletime | rst | q(bin) | q(hex) 0 | 1 | xxxx | x 5 | 1 | 0001 | 1 6 | 0 | 0001 | 1 15 | 0 | 0010 | 2 25 | 0 | 0100 | 4 35 | 0 | 1000 | 8 45 | 0 | 0001 | 1 55 | 0 | 0010 | 2 65 | 0 | 0100 | 4 75 | 0 | 1000 | 8 85 | 0 | 0001 | 1 Done: pattern circulated through all 4 positions twice. /var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpn0j3_f0u/ring_counter.v:40: $finish called at 86 (1s)
Johnson counter Verilog code (4-bit)
The Johnson (twisted-ring) counter shifts right and feeds the inverted least-significant bit back into the most-significant bit. Reset seeds 0000; the inversion then fills the register with ones and empties it again, giving eight states from four flip-flops.
// johnson_counter.v -- 4-bit Johnson (twisted-ring) counter with reset seeding
module johnson_counter #(
parameter WIDTH = 4
)(
input wire clk,
input wire rst, // synchronous, active-high
output reg [WIDTH-1:0] q
);
always @(posedge clk) begin
if (rst)
q <= {WIDTH{1'b0}}; // seed all-zeros -> 0000
else
q <= {~q[0], q[WIDTH-1:1]}; // shift right, feed inverted LSB into MSB
end
endmodule
// tb_johnson_counter.v
module tb_johnson_counter;
localparam WIDTH = 4;
reg clk = 1'b0;
reg rst;
wire [WIDTH-1:0] q;
johnson_counter #(.WIDTH(WIDTH)) dut (.clk(clk), .rst(rst), .q(q));
always #5 clk = ~clk; // 10 ns period
integer i;
initial begin
$display("time | rst | q(bin) | q(hex)");
$monitor("%4t | %b | %b | %h", $time, rst, q, q);
rst = 1'b1; // assert reset to seed 0000
@(posedge clk); #1;
rst = 1'b0; // release, generate the 2*WIDTH-state sequence
for (i = 0; i < 9; i = i + 1) @(posedge clk);
#1;
$display("Done: completed one full %0d-state Johnson cycle.", 2*WIDTH);
$finish;
end
endmoduletime | rst | q(bin) | q(hex) 0 | 1 | xxxx | x 5 | 1 | 0000 | 0 6 | 0 | 0000 | 0 15 | 0 | 1000 | 8 25 | 0 | 1100 | c 35 | 0 | 1110 | e 45 | 0 | 1111 | f 55 | 0 | 0111 | 7 65 | 0 | 0011 | 3 75 | 0 | 0001 | 1 85 | 0 | 0000 | 0 95 | 0 | 1000 | 8 Done: completed one full 8-state Johnson cycle. /var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpnydic2w6/johnson_counter.v:40: $finish called at 96 (1s)
How the code works
Both modules are a single always @(posedge clk) block that uses non-blocking assignments (<=) so every flip-flop updates from the previous cycle’s values at the same edge. The only real difference is the feedback term that decides which bit enters the register as the rest shift along.
In the ring counter, {q[WIDTH-2:0], q[WIDTH-1]} takes the lower three bits and appends the old MSB at the bottom — a left rotate. The seed {{(WIDTH-1){1'b0}}, 1'b1} builds 0001 for any width, so the design scales if you change the WIDTH parameter. A 4-bit ring counter therefore visits 4 states: 0001, 0010, 0100, 1000, and back. Because only one bit is ever high, the output is one-hot and needs no decoder to tell which phase you are in.
The Johnson counter uses {~q[0], q[WIDTH-1:1]}: it shifts every bit down one place and drops the inverted old LSB in at the top. Starting from 0000, that inversion feeds in a 1, and the register fills from the MSB side until it reads 1111, then inverts back toward zeros. The full cycle is 8 states (2 × WIDTH): 0000, 1000, 1100, 1110, 1111, 0111, 0011, 0001. The simulation log above confirms this exact walk.
| Property | Ring counter | Johnson counter |
|---|---|---|
| Reset seed | 0001 (one hot bit) | 0000 (all zero) |
| Feedback | MSB wraps to LSB, unchanged | LSB inverted into MSB |
| States (4-bit) | 4 | 8 |
| States (N-bit) | N | 2N |
| Output style | One-hot, decode-free | Only one bit changes per edge |
Reset seeding, and why it matters
Shift-register counters have no inherent value they settle into — their behaviour depends entirely on the bits already present. In simulation, power-up leaves flip-flops in an unknown x state, and in hardware they come up arbitrary. The synchronous reset here forces a legal starting point on the first clock edge after rst is asserted: a lone 1 for the ring counter, all zeros for the Johnson counter. Without that seed the ring counter’s log would show xxxx rotating meaninglessly, which is the first thing to check if your pattern never appears.
Running the testbench
Each testbench generates a 10 ns clock, pulses reset for one edge, then releases it and lets the pattern circulate. $monitor reprints the line whenever an input or output changes, so the log is a clean per-edge trace in binary and hex. Compile and simulate with any Verilog-2005 tool; with Icarus Verilog the two commands are iverilog -g2005 -o sim ring_counter.v followed by vvp sim. The $finish call stops the run once the pattern has looped, keeping the log short and readable.
Common mistakes
- Never seeding the ring counter. If reset leaves the register at
0000(or undefinedx), rotating zeros produces zeros forever and the counter never moves. Always load a single1on reset, as the code does. - Dropping the inversion in the Johnson counter. Feeding the LSB back without inverting it turns the design straight back into a ring counter — four states, not eight. The
~onq[0]is the whole point of the “twist”. - Using blocking assignments. Writing
q = ...inside a clocked block can create a collapsing shift instead of a clean circulation. Use non-blocking<=for every sequential assignment. - Reversing the concatenation order. Swapping the two halves inside the
{ }flips the shift direction. Double-check thatq[WIDTH-2:0]is the part that moves and the old end bit is what gets appended. - Ignoring illegal states. On real silicon, noise can push either counter into a state outside its intended cycle (for example
0011in a one-hot ring counter). The reset path recovers it here, but production designs often add self-correcting feedback logic.
Quick check
How many unique states does a 4-bit ring counter cycle through, and why?
Four. The register is one-hot — a single 1 occupies one of the four bit positions at a time, so there are exactly WIDTH distinct patterns before it repeats.
How many states does a 4-bit Johnson counter produce?
Eight (2 × WIDTH). The inverted feedback first fills the register with ones and then empties it, doubling the sequence length compared with a plain ring counter of the same width.
What happens to the ring counter if reset never loads a 1?
It stays stuck. Rotating an all-zero register (or an undefined x register) just yields the same value every edge, so the pattern never circulates. Seeding 0001 on reset is what makes it work.
What single code change converts a ring counter into a Johnson counter?
Invert the bit that feeds back. Changing the feedback from the plain end bit to ~q[0] (and shifting the other direction) turns the 4-state one-hot ring into the 8-state twisted-ring Johnson sequence.
Share your question in comments or talk to our mentor team for batch guidance.
Learn Verilog with mentors, labs and placement support
This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.
Explore VLSI Courses