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
endmodule
PASS 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 PASSED

The log shows each vector reversed correctly (1000_0000 → 0000_0001, 1111_0000 → 0000_1111), the double-reverse returning the original, and the constant check 0xF0 → 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 procedural for loop. A function acts 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
endmodule
PASS 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 PASSED

Each line captures the registered output one clock after the input is applied and checks it against the ref_rev function. Note symmetric values like 8f1 that reverse to themselves, and asymmetric ones like 127 → 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 i is driven by input index WIDTH-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]. Writing in[WIDTH-i] is off by one: when i = 0 it selects bit WIDTH, which is out of range (Verilog returns x), 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_reverse synthesizes 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_reg infers WIDTH flip-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 an always block 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_0000 complements to 8'b0111_1111 but reverses to 8'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 Lab

Open this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.

Run it in the Lab

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
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD