Ring Counter (One-Hot): Concept to Code
What is a ring counter (one-hot)?
A ring counter is a shift-register style counter where a single ‘1’ bit “circulates” through a bank of flip-flops. Because exactly one flip-flop is high at a time (i.e., one-hot), the current state is easy to decode—no combinational next-state logic is required beyond the rotation.
Why designers like it
-
Glitch-free decode: Each state is a single bit; just tap Q[i].
-
Fast & simple next-state: Rotate the vector; no adder/carry chain.
-
Timing-friendly: All flops sample the same clock; no ripples.
Trade-offs
-
Area: Needs N flip-flops for N states (vs. log2(N) for binary).
-
Reset discipline: Must start one-hot; if all bits become 0, it can “die.”
Problem Statement (your spec)
-
6-bit ring; one ‘1’ rotates each clock.
-
Async reset to the one-hot seed 000001.
-
Ports: clk, arst, Q[5:0].
-
Expected sequence:
000001 → 000010 → 000100 → 001000 → 010000 → 100000 → 000001 → …
RTL: 6-bit Ring Counter
Verilog
module ring6 (
input wire clk,
input wire arst,
output reg [5:0] Q
);
always @(posedge clk or posedge arst) begin
if (arst)
Q <= 6'b000001; // seed state (one-hot)
else
Q <= {Q[4:0], Q[5]}; // rotate-left by 1
end
endmodule
Code, line by line
-
Async reset (posedge arst)
Including arst in the sensitivity list makes reset immediate. As soon as arst=1, Q becomes 000001 regardless of the clock. That guarantees a valid one-hot seed.
-
Rotation logic: Q <= {Q[4:0], Q[5]};
This is a rotate-left by 1:
-
The high-order bit (Q[5]) moves to the least-significant position.
-
All other bits shift up by one.
With an initial 000001, successive clocks produce the one-hot cycle above.
-
-
No combinational next-state
The “next state” is the old state, just rotated. That’s the hallmark of a ring counter: simple, synchronous, predictable.
⚠️ Note: If Q ever becomes 000000 (e.g., due to a glitch or an uninitialized power-on), rotation keeps it at zero forever. That’s why the reset is required (or you add self-healing—see tips below).
Testbench: Drive & Observe
Verilog
module tb_ring6;
reg clk = 0;
reg arst = 1;
wire [5:0] Q;
ring6 tb (.clk(clk), .arst(arst), .Q(Q));
// 10-time-unit clock
always #5 clk = ~clk;
initial begin
arst = 1; // hold in reset
#12; // release reset before a posedge
arst = 0;
#100; // run long enough to see multiple rotations
$finish;
end
initial $monitor("Time=%0t | arst=%b | Q=%b", $time, arst, Q);
endmodule
What the TB proves
-
Reset seeding: With arst=1, Q is 000001.
Reset is released at t=12, so the first active posedge after release (at t=15) starts rotation from the seeded state.
-
Rotation timing: Every rising clock edge changes Q to the next one-hot position. With a 10-unit period, you’ll see the full 6-state cycle in 60 time units.
-
Monitoring: $monitor prints time, reset, and Q continuously so you can correlate reset and state changes.
Expected waveform behavior (mental picture)
-
Exactly one bit high at a time.
-
No intermediate glitches (purely sequential update).
Practical notes & pro tips
-
Reset deassertion: In real silicon, deassert async resets cleanly (meet recovery/removal to the clock). A common pattern is async assert, sync deassert.
-
Self-healing (optional but nice): If you want resilience against “all-zero” lock-up (e.g., after scan or power-up without reset), add a guard:
-
Or move this into a synthesis-guarded block if it’s only for sim safety.
Enable input (pause):
-
Keeps state when en=0.
Parameterize N (easy upgrade):
SystemVerilog assertion (sanity):
In SV, assert the one-hot property on every cycle:
-
Great for catching any accidental multi-hot or zero-hot states during verification.
-
Johnson counter (twisted ring) variant: If you invert the feedback before feeding it back, you get a Johnson (Möbius) counter, which yields 2N states with a similar “shift” simplicity. Handy when you want more states with little extra logic.
swift
clk: _/‾\_/‾\_/‾\_/‾\_/‾\_/‾\_/‾\_
Q: 000001 000010 000100 001000 010000 100000 000001 ...
Verilog
else if (Q == 6'b000000)
Q <= 6'b000001; // re-seed if ever all-zero
else
Q <= {Q[4:0], Q[5]};
Verilog
module ring #(parameter N=6) (...);
reg [N-1:0] Q;
if (arst) Q <= {{(N-1){1'b0}},1'b1};
else Q <= {Q[N-2:0], Q[N-1]};
endmodule
Verilog
module ring #(parameter N=6) (...);
reg [N-1:0] Q;
if (arst) Q <= {{(N-1){1'b0}},1'b1};
else Q <= {Q[N-2:0], Q[N-1]};
endmodule
Verilog
assert property (@(posedge clk) disable iff (arst) $onehot(Q));
Where one-hot rings shine
-
Fast state machines (no dense decode, easy timing).
-
Scanning/LED chasers, simple sequencers.
-
Clock division / phase stepping (tap different one-hot bits).
-
Arbiter tokens (token passing per cycle).
TL;DR
-
A 6-bit one-hot ring is a rotate-left of a single ‘1’ through six flip-flops.
-
Async reset seeds Q=000001; every posedge rotates the ‘1’.
-
Simple, decode-friendly, timing-friendly—at the cost of extra flops.
Ring Counter (One-Hot) — 15 Interview Q&As (Refined & Explained)
Q1) Why is one-hot encoding often faster in FPGAs?
Refined answer:
Only one flip-flop is asserted per state, so next-state logic becomes trivial (often just wiring/rotation). That means:
-
Shallow LUT depth (sometimes 0 LUTs for straight rotate).
-
No carry chains or large decoders.
-
Higher fMAX at the cost of more flip-flops (area trade-off).
Rule of thumb: in LUT-rich, FF-plentiful FPGAs, one-hot often beats dense encodings for speed.
Q2) What are the downsides of ring counters?
Refined answer:
-
Area: Needs N FFs for N states (vs. ⌈log₂N⌉).
-
Initialization sensitivity: Must start one-hot; otherwise it can “die” in all-zero or multi-hot states.
-
Fault tolerance: Requires checks or self-healing to recover from upset/faults.
Q3) How can state errors be detected in ring counters?
Refined answer:
Detect not-one-hot states:
-
In SystemVerilog: assert property (@(posedge clk) disable iff (rst) $onehot(Q));
-
In plain RTL: (Q==0) → zero-hot; (Q & (Q-1))!=0 → multi-hot.
You can raise an error flag or force a re-seed on detection.
Q4) How does a Johnson counter provide more states than a ring counter?
Refined answer:
A Johnson (twisted-ring) counter feeds back inverted MSB to LSB, producing 2N unique states with N FFs.
-
Ring: N states (one-hot token rotates).
-
Johnson: 2N states (a walking 1s/0s pattern).
Good when you need more states with similar simplicity.
Q5) How can ring counters be used for sequence generation?
Refined answer:
Map each one-hot bit to an enable/trigger:
-
Q[0] → action A, Q[1] → action B, etc.
Because only one bit is high, the control is glitch-free and decode is a single tap per step—great for stepper sequences, phased enables, and time-slot scheduling.
Q6) How to recover from multiple-ones caused by faults?
Refined answer:
-
Detect (see Q3) then re-seed synchronously or via async reset.
-
Add self-healing: if Q==0 or !$onehot(Q), force Q<=SEED on the next cycle.
-
In radiation-prone designs, consider TMR (triple modular redundancy) on state bits.
Q7) Why do ring counters avoid carry logic?
Refined answer:
Next state is just a rotation ({Q[N-2:0],Q[N-1]}), not arithmetic. This:
-
Avoids adder/carry chains entirely.
-
Keeps critical paths short and predictable.
Q8) How to expand the length of a ring counter?
Refined answer:
Increase FF count and keep the rotate feedback:
verilog
Q <= {Q[N-2:0], Q[N-1]}; // rotate-left
Seed to ...0001. The method scales linearly; just ensure proper reset and one-hot checks.
Q9) How to implement a ring counter using shift-register primitives?
Refined answer:
Chain FFs (or FPGA SRL/shift primitives), and loop last bit to the input:
verilog
Q <= {Q[N-2:0], Q[N-1]}; // serial shift + feedback
With FPGA SRLs, verify reset/initialization behavior (some SRLs don’t have async reset—seed via load or small wrapper FFs).
Q10) What are common interview pitfalls?
Refined answer:
-
Not explaining initialization (how you guarantee one-hot on power-up).
-
Ignoring fault recovery (multi-hot/zero-hot detection).
-
Missing trade-offs vs. binary/Gray/Johnson encodings (speed vs. FF cost).
-
Forgetting assertions or self-checks in verification.
Q11) Can a ring counter be used as a Johnson counter?
Refined answer:
No—different feedback.
-
Ring: rotate stored bit.
-
Johnson: feed back inverted MSB → Q <= {Q[N-2:0], ~Q[N-1]}.
Choose by state count needs and decode convenience.
Q12) How to create a variable-step ring counter?
Refined answer:
Insert a selectable rotate:
verilog
case (step)
1: Q_next = {Q[N-2:0], Q[N-1]};
2: Q_next = {Q[N-3:0], Q[N-1:N-2]};
// ...
endcase
Or use a barrel shifter to rotate by k. Useful for skipping phases or non-uniform schedules. Mind timing if step is dynamic (adds LUT depth).
Q13) How to write ring counters in Verilog for synthesis portability?
Refined answer:
-
Use a pos-edge clocked always with explicit async/sync reset.
-
Express rotation with concatenation, not tool-specific primitives.
-
Optionally parameterize N and seed; avoid vendor-only SRL inference unless guarded for portability.
Q14) How to test a ring counter thoroughly?
Refined answer:
-
Reset test: confirm seed (000…1).
-
Cycle test: observe all N states in order, then wrap.
-
Fault tests: force multi-hot/zero-hot; confirm detection and recovery.
-
Assertions: $onehot(Q); optional functional coverage on each state index.
-
Corner: toggle reset near clock edge; verify clean recovery (consider async-assert, sync-deassert).
Q15) How to reduce power consumption in ring counters?
Refined answer:
-
Add enable: only rotate when needed (tools may infer CE on FFs).
-
Clock gating via vendor ICG cells (ASIC) or dedicated primitives (FPGA), used carefully.
-
Lower frequency for the ring or grouped enables if multiple rings exist.
-
Avoid unnecessary glitching (purely sequential update already helps).
Tiny, Practical RTL Patterns
One-hot ring (parameterized, with enable & self-healing):
Verilog
module ring #(parameter N=6, parameter [N-1:0] SEED={{(N-1){1'b0}},1'b1})(
input wire clk, arst, en,
output reg [N-1:0] Q
);
wire onehot = (Q!=0) && ((Q & (Q-1))==0); // plain-RTL onehot check
always @(posedge clk or posedge arst) begin
if (arst) Q <= SEED;
else if (en) Q <= onehot ? {Q[N-2:0], Q[N-1]} : SEED; // self-heal
end
endmodule
Johnson counter (2N states):
Verilog
always @(posedge clk or posedge arst)
if (arst) Q <= '0;
else Q <= {Q[N-2:0], ~Q[N-1]};
SVA one-hot property (SystemVerilog):
Verilog
assert property (@(posedge clk) disable iff (arst) $onehot(Q));