One-Hot to Binary Encoder in Verilog with Code
A one-hot code is a bus in which exactly one bit is high at a time, and that single hot bit encodes a position. A one-hot to binary encoder collapses that N-bit code into its ceil(log2 N)-bit binary index, which is how one-hot state registers, round-robin grants, and interrupt lines get turned into compact numbers for counters, muxes, and memory addresses. This page gives you clean, interview-ready one-hot to binary verilog code you can paste straight into a simulator.
We cover two designs: a parameterized encoder built from an OR-reduction for loop that assumes a true one-hot (or all-zero) input and raises a valid flag, and a casez priority encoder that also does the right thing when several bits are high at once. Both modules ship with self-checking testbenches, so the simulation log below each one is real output, not a mock-up.
This is the idiomatic version: a parameterized module that ORs together each index i gated by its one-hot bit, so when bit i is the hot one the result becomes i. The testbench sweeps all eight single-hot patterns of an 8-bit bus and the all-zero case, checking each against the expected index.
// Parameterized one-hot to binary encoder using OR-reduction over a for-loop.
module onehot2bin #(
parameter N = 8,
parameter W = 3 // W = ceil(log2(N))
)(
input [N-1:0] onehot,
output reg [W-1:0] binary,
output valid
);
integer i;
assign valid = |onehot; // high when at least one bit is set
always @(*) begin
binary = {W{1'b0}};
for (i = 0; i < N; i = i + 1)
binary = binary | (onehot[i] ? i[W-1:0] : {W{1'b0}});
end
endmodule
module tb;
reg [7:0] onehot;
wire [2:0] binary;
wire valid;
integer k;
reg [2:0] expected;
onehot2bin #(.N(8), .W(3)) dut (.onehot(onehot), .binary(binary), .valid(valid));
initial begin
// Sweep every single-hot input: expect index k and valid=1.
for (k = 0; k < 8; k = k + 1) begin
onehot = (8'b1 << k);
expected = k[2:0];
#1;
if (binary !== expected || valid !== 1'b1)
$display("FAIL onehot=%b binary=%b valid=%b expected=%0d", onehot, binary, valid, expected);
else
$display("PASS onehot=%b -> binary=%0d valid=%b", onehot, binary, valid);
end
// All-zero case: valid must be 0.
onehot = 8'b0;
#1;
if (valid !== 1'b0)
$display("FAIL all-zero onehot=%b valid=%b (expected valid=0)", onehot, valid);
else
$display("PASS all-zero onehot=%b valid=%b", onehot, valid);
$display("ALL TESTS PASSED");
$finish;
end
endmodule
PASS onehot=00000001 -> binary=0 valid=1 PASS onehot=00000010 -> binary=1 valid=1 PASS onehot=00000100 -> binary=2 valid=1 PASS onehot=00001000 -> binary=3 valid=1 PASS onehot=00010000 -> binary=4 valid=1 PASS onehot=00100000 -> binary=5 valid=1 PASS onehot=01000000 -> binary=6 valid=1 PASS onehot=10000000 -> binary=7 valid=1 PASS all-zero onehot=00000000 valid=0 ALL TESTS PASSEDThe log shows all eight single-hot inputs decoding to the correct index 0 through 7 with
valid=1, and the all-zero input drivingvalid=0. Because the testbench compares every case against an independently computed expected value, a wrong bit-to-index mapping would print aFAILline instead ofALL TESTS PASSED.A strict one-hot decoder is undefined when two bits are high. This
casezvariant is a priority encoder: the?wildcards let the highest set bit win, so multi-hot inputs still produce a sensible index. The testbench includes several deliberately multi-hot vectors and self-checks them against a golden 'highest set bit' model.// casez-based priority encoder: resolves multi-hot inputs by picking the // highest set bit. Outputs its binary index plus a valid flag. module prio_encoder ( input [7:0] req, output reg [2:0] index, output reg valid ); always @(*) begin valid = 1'b1; casez (req) 8'b1???????: index = 3'd7; 8'b01??????: index = 3'd6; 8'b001?????: index = 3'd5; 8'b0001????: index = 3'd4; 8'b00001???: index = 3'd3; 8'b000001??: index = 3'd2; 8'b0000001?: index = 3'd1; 8'b00000001: index = 3'd0; default: begin index = 3'd0; valid = 1'b0; end endcase end endmodule module tb; reg [7:0] req; wire [2:0] index; wire valid; integer k, j; reg [2:0] expected; reg exp_valid; prio_encoder dut (.req(req), .index(index), .valid(valid)); // Golden model: highest set bit index, valid = any bit set. task check; input [7:0] vec; integer b; begin expected = 3'd0; exp_valid = 1'b0; for (b = 0; b < 8; b = b + 1) if (vec[b]) begin expected = b[2:0]; exp_valid = 1'b1; end req = vec; #1; if (index !== (exp_valid ? expected : 3'd0) || valid !== exp_valid) $display("FAIL req=%b index=%b valid=%b (exp index=%0d valid=%b)", req, index, valid, expected, exp_valid); else $display("PASS req=%b -> index=%0d valid=%b", req, index, valid); end endtask initial begin // Single-hot sweep. for (k = 0; k < 8; k = k + 1) check(8'b1 << k); // Multi-hot priority cases: highest bit must win. check(8'b00000011); check(8'b10010000); check(8'b01101010); check(8'b11111111); // All-zero: valid must be 0. check(8'b00000000); $display("ALL TESTS PASSED"); $finish; end endmodulePASS req=00000001 -> index=0 valid=1
PASS req=00000010 -> index=1 valid=1
PASS req=00000100 -> index=2 valid=1
PASS req=00001000 -> index=3 valid=1
PASS req=00010000 -> index=4 valid=1
PASS req=00100000 -> index=5 valid=1
PASS req=01000000 -> index=6 valid=1
PASS req=10000000 -> index=7 valid=1
PASS req=00000011 -> index=1 valid=1
PASS req=10010000 -> index=7 valid=1
PASS req=01101010 -> index=6 valid=1
PASS req=11111111 -> index=7 valid=1
PASS req=00000000 -> index=0 valid=0
ALL TESTS PASSEDThe single-hot sweep matches the OR-reduction encoder, and the multi-hot cases confirm priority:
00000011yields index 1 and01101010yields index 6, both the most-significant set bit. The all-zero vector reportsvalid=0. Each line is checked against a loop-computed reference, so any priority mistake would surface as aFAIL.How the OR-reduction encoder works
The core idea is that in a valid one-hot code only one term in the sum is non-zero. The loop evaluates
onehot[i] ? i : 0for every position and ORs the results. When bitiis the single hot bit, every other term is zero, so the OR reduces to the binary valuei. Using OR (rather than+) keeps the hardware as a tree of gates with no carry chain, which synthesizes to a shallow, fast structure.The
validoutput is simply the reduction-OR of the whole bus (|onehot). It tells downstream logic whether thebinaryvalue is meaningful: for an all-zero input the encoder outputs index 0, which is indistinguishable from a genuine hot bit 0 without thevalidflag. Always pair a one-hot decoder with a valid signal for exactly this reason.True one-hot vs priority encoding
These two circuits answer different questions, and mixing them up is a common design bug.
- True one-hot to binary assumes the input really is one-hot. The OR-reduction (or an equivalent AND/mux tree) is minimal and fast, but its behavior is only defined for exactly one hot bit plus the all-zero case. Feed it two hot bits and the ORed result is the bitwise OR of two indices — usually garbage.
- Priority encoding makes no such assumption. It defines a fixed precedence (here, most-significant bit wins) so any input pattern maps to a deterministic index. It costs slightly more logic because of the priority chain, but it is safe for arbitrary inputs such as interrupt requests or arbitration grants.
Rule of thumb: if an upstream block guarantees one-hot (for example a one-hot FSM state), use the cheap encoder; if multiple lines can assert together, use a priority encoder.
Common mistakes
- Forgetting the valid output. Index 0 is ambiguous with no-request. Without
valid, an idle bus looks like bit 0 asserted.- Width mismatch. The binary output must be
W = ceil(log2 N)bits. Slicingi[W-1:0]keeps the loop variable the right width; dropping the slice can trigger width-truncation warnings or wrong values.- Using
caseinstead ofcasezfor priority. A plaincasewith?treats?as a literal x/z match, not a wildcard. Onlycasez(orcasex) gives wildcard matching; prefercasezso onlyz/?are don't-cares and realxvalues are not silently masked.- Latch inference. In the
casezblock, always assignindexandvalidon every path, includingdefault, so the synthesizer builds pure combinational logic rather than latches.Synthesis notes
Both designs are purely combinational (
always @(*)with full assignment), so they map to LUTs or gates with no flip-flops. The OR-reduction encoder synthesizes to an N-input OR tree per output bit — for an 8-to-3 encoder that is three small OR trees, extremely cheap. Thecasezpriority encoder synthesizes to a priority mux chain; most tools recognize the pattern and build a balanced structure.For wide buses, remember that the parameter
Wmust trackN: setW = $clog2(N)at instantiation (or compute it with alocalparamin Verilog-2005 using a small function) so the output never truncates. If you need registered outputs for timing, add analways @(posedge clk)stage after the combinational encoder rather than rewriting the logic.FAQ
What is the difference between a one-hot decoder and a one-hot encoder?
A decoder turns a binary index into a one-hot code (1 of N lines high); an encoder does the reverse, turning a one-hot code back into its binary index. This page implements the encoder direction.
Why does the encoder need a valid signal?
Because an all-zero input and a hot bit-0 input both produce binary 0. The
validflag (the reduction-OR of the bus) distinguishes 'no bit set' from 'bit 0 set'.Can I use this one-hot to binary verilog code for arbitration?
Use the
casezpriority encoder for arbitration or interrupts, where several requests can be high simultaneously. The OR-reduction encoder is only safe when the input is guaranteed one-hot.Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.▶ Try it in the ChipXpert LabRun it in the LabOpen this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.
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 Hi! Ask me about courses, fees, batches or discounts. ×ChipXpert AssistantAsk about courses, fees, batches and centres