Bit Reversal in Verilog: Reverse Bit Order with Code
A bit-reversal circuit flips the order of the bits on a bus so that the most-significant bit becomes the least-significant bit and vice versa: out[i] = in[WIDTH-1-i]. It is purely a rewiring of signals, so the combinational version is free of logic gates — it is just a permutation of wires. This page gives clean, idiomatic bit reversal Verilog code you can drop into a design and reuse at any width.
Below are two complete, self-checking modules. The first is a parameterized combinational reverse built with a generate loop; the second is a clocked (registered) reverse using a procedural for loop. Each testbench reverses known vectors, double-reverses to confirm the operation is its own inverse, and compares against an independently computed golden model, so a real indexing bug would print a FAIL.
The clearest form: a parameterized, purely combinational reverse. A generate loop wires each output bit to the mirror-image input bit. Instantiating the module twice (reverse, then reverse again) must return the original value — a strong self-check that the indexing is correct.
module bit_reverse #(parameter WIDTH = 8) (
input [WIDTH-1:0] in,
output [WIDTH-1:0] out
);
genvar i;
generate
for (i = 0; i < WIDTH; i = i + 1) begin : rev
assign out[i] = in[WIDTH-1-i];
end
endgenerate
endmodule
module tb;
localparam W = 8;
reg [W-1:0] a;
wire [W-1:0] r;
wire [W-1:0] rr;
bit_reverse #(.WIDTH(W)) u1 (.in(a), .out(r));
bit_reverse #(.WIDTH(W)) u2 (.in(r), .out(rr));
integer k, j;
reg [W-1:0] vec [0:4];
reg [W-1:0] gold;
initial begin
vec[0] = 8'b1000_0000;
vec[1] = 8'b1010_0110;
vec[2] = 8'b0000_0001;
vec[3] = 8'b1111_0000;
vec[4] = 8'b1100_1001;
for (k = 0; k < 5; k = k + 1) begin
a = vec[k];
#1;
gold = 0;
for (j = 0; j < W; j = j + 1)
gold[j] = a[W-1-j];
if (r !== gold)
$display("FAIL vector %0d: in=%b rev=%b expected=%b", k, a, r, gold);
else if (rr !== a)
$display("FAIL vector %0d: double-reverse rr=%b != in=%b", k, rr, a);
else
$display("PASS vector %0d: in=%b rev=%b (double=%b)", k, a, r, rr);
end
a = 8'hF0; #1;
if (r !== 8'h0F) $display("FAIL const: 0xF0 -> %h", r);
else $display("PASS const: 0xF0 reverses to 0x%0h", r);
$display("ALL TESTS PASSED");
$finish;
end
endmodulePASS vector 0: in=10000000 rev=00000001 (double=10000000) PASS vector 1: in=10100110 rev=01100101 (double=10100110) PASS vector 2: in=00000001 rev=10000000 (double=00000001) PASS vector 3: in=11110000 rev=00001111 (double=11110000) PASS vector 4: in=11001001 rev=10010011 (double=11001001) PASS const: 0xF0 reverses to 0xf ALL TESTS PASSEDThe log shows each vector reversed correctly (
1000_0000→0000_0001,1111_0000→0000_1111), the double-reverse returning the original, and the constant check0xF0→0x0F. Because the testbench compares against an independently built golden value, a one-off slip in the index would surface as a FAIL rather than passing silently.A meaningful variant: a wider (12-bit) registered reverse that computes the permutation inside a clocked
always @(posedge clk)block with a proceduralforloop. Afunctionacts as the golden reference, and a deterministic 16-pattern sweep exercises it.module bit_reverse_reg #(parameter WIDTH = 12) ( input clk, input [WIDTH-1:0] in, output reg [WIDTH-1:0] out ); integer i; always @(posedge clk) begin for (i = 0; i < WIDTH; i = i + 1) out[i] <= in[WIDTH-1-i]; end endmodule module tb; localparam W = 12; reg clk; reg [W-1:0] a; wire [W-1:0] r; bit_reverse_reg #(.WIDTH(W)) dut (.clk(clk), .in(a), .out(r)); function [W-1:0] ref_rev; input [W-1:0] x; integer j; begin ref_rev = 0; for (j = 0; j < W; j = j + 1) ref_rev[j] = x[W-1-j]; end endfunction integer n, fails; reg [W-1:0] expected; always #5 clk = ~clk; initial begin clk = 0; fails = 0; for (n = 0; n < 16; n = n + 1) begin a = (n * 12'h137) ^ (n << 4); expected = ref_rev(a); @(posedge clk); #1; if (r !== expected) begin fails = fails + 1; $display("FAIL n=%0d in=%b out=%b exp=%b", n, a, r, expected); end else begin $display("PASS n=%0d in=%h out=%h", n, a, r); end end if (fails == 0) $display("ALL TESTS PASSED"); else $display("TESTS FAILED: %0d", fails); $finish; end endmodulePASS n=0 in=000 out=000 PASS n=1 in=127 out=e48 PASS n=2 in=24e out=724 PASS n=3 in=395 out=a9c PASS n=4 in=49c out=392 PASS n=5 in=643 out=c26 PASS n=6 in=72a out=54e PASS n=7 in=8f1 out=8f1 PASS n=8 in=938 out=1c9 PASS n=9 in=a7f out=fe5 PASS n=10 in=c86 out=613 PASS n=11 in=ded out=b7b PASS n=12 in=e54 out=2a7 PASS n=13 in=f1b out=d8f PASS n=14 in=1e2 out=478 PASS n=15 in=2c9 out=934 ALL TESTS PASSEDEach line captures the registered output one clock after the input is applied and checks it against the
ref_revfunction. Note symmetric values like8f1that reverse to themselves, and asymmetric ones like127→e48; all 16 deterministic patterns pass, proving the clocked loop produces the same permutation as the combinational form, just delayed by one cycle.How bit reversal works
Bit reversal is a fixed permutation: output index
iis driven by input indexWIDTH-1-i. Pair up the ends and walk inward — bit 0 swaps with bit WIDTH-1, bit 1 with bit WIDTH-2, and so on. For an even width every bit moves; for an odd width the exact middle bit maps to itself. The operation is its own inverse: reversing twice returns the original word, which is exactly what Example 1's double-reverse check exploits.In the combinational version each
assign out[i] = in[WIDTH-1-i];is literally a wire crossing, so the circuit has zero gate delay and zero area beyond routing. The registered version adds a flip-flop per output bit, giving a one-cycle latency but letting the reversed value drive a timing-clean pipeline stage.Why bit reversal matters
- FFT address generation. The decimation-in-time FFT reads or writes samples in bit-reversed index order. A hardware FFT uses a bit-reverse block on the address counter so the butterfly network sees inputs in the right sequence.
- Endianness and bit-ordering. Serial links, LCD/LED drivers and some sensors expect bits LSB-first while a register holds them MSB-first (or vice versa). A reverse block adapts one convention to the other without a lookup table.
- Serial shift order. SPI-like and scan interfaces may shift MSB-first or LSB-first; reversing the parallel word before load lets one shift register serve both orders.
- CRC and scramblers. Many CRC specifications reflect input and/or output bits; a reverse block implements that reflection directly.
The off-by-one indexing mistake
The single most common bug in bit reversal Verilog code is the index expression. The correct mirror is
in[WIDTH-1-i]. Writingin[WIDTH-i]is off by one: wheni = 0it selects bitWIDTH, which is out of range (Verilog returnsx), and it never touches bit 0.// WRONG - off by one, selects a non-existent bit when i = 0 assign out[i] = in[WIDTH - i]; // RIGHT assign out[i] = in[WIDTH - 1 - i];A second trap is parameter width: if the reference or the DUT hardcodes 8 while the other uses
WIDTH, the halves of a wider bus will look reversed only in part. Always derive both sides from the same parameter, as these examples do, and keep a double-reverse self-check so the mistake cannot pass unnoticed.Synthesis notes
The combinational
bit_reversesynthesizes to pure routing: no LUTs, no gates, just net renaming. It is the preferred form whenever the reversed value feeds more combinational logic in the same cycle. Because it is wire-only, it adds essentially no delay, though the surrounding fan-out and routing still count toward timing.The registered
bit_reverse_reginfersWIDTHflip-flops. Use it to break a long combinational path or to place the reversed word cleanly on a clock boundary. Both styles are fully static — the index arithmetic is evaluated at elaboration, not at runtime — so they map identically across FPGA and ASIC flows. Avoid building a reverse from a variable-indexed shift in analwaysblock when a fixed permutation will do; the fixed form is simpler for the tool to recognize.FAQ
Is bit reversal the same as a NOT / bitwise complement?
No. Complement (
~in) flips each bit's value in place. Reversal keeps every bit's value but changes its position.8'b1000_0000complements to8'b0111_1111but reverses to8'b0000_0001.Can I reverse a bus with a single operator?
Verilog-2005 has no built-in reverse operator, so the generate or for-loop form shown here is the portable way. (Part-select streaming operators exist only in SystemVerilog.)
Does the width have to be a power of two?
No. The
out[i] = in[WIDTH-1-i]mapping works for any width. Powers of two matter for FFT addressing, not for the reverse primitive itself.Combinational or registered — which should I use?
Use the combinational version by default; reach for the registered version only when you need to retime a path or align the result to a clock edge.
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