Barrel Shifter Verilog Code (Parameterized, with Testbench)

A barrel shifter moves every bit of a word by a programmable distance in a single combinational step, so there is no clock-by-clock iteration the way a simple shift register needs. The barrel shifter Verilog code below is fully parameterized on width and supports both logical shifts and rotations in either direction. Everything here compiles with iverilog -g2005 and is checked against a golden model, so you can paste it and run it immediately.

Parameterized barrel shifter Verilog code

The design is built from $clog2(WIDTH) stages of 2:1 multiplexers. Stage s either passes its input straight through or shifts it by exactly 2**s, controlled by bit s of the shift amount. Because each stage is a fixed, elaboration-time distance, the synthesizer can map every stage to a lean row of muxes. The accompanying testbench drives seven vectors covering logical shift, rotate, both directions, and a zero amount, and compares each result against a behavioral reference.

// barrel_shifter.v
// Parameterized combinational barrel shifter built from log2(WIDTH)
// stages of 2:1 multiplexers. Supports logical shift and rotate,
// in either direction, with no clock.
module barrel_shifter #(
    parameter WIDTH = 8
)(
    input  wire [WIDTH-1:0]         data_in,
    input  wire [$clog2(WIDTH)-1:0] shamt,   // shift/rotate amount
    input  wire                     dir,      // 0 = left, 1 = right
    input  wire                     rotate,   // 0 = fill zeros, 1 = rotate
    output wire [WIDTH-1:0]         data_out
);
    localparam STAGES = $clog2(WIDTH);

    // stage[0] is the raw input; each stage conditionally shifts by 2**s.
    wire [WIDTH-1:0] stage [0:STAGES];
    assign stage[0] = data_in;

    genvar s;
    generate
        for (s = 0; s < STAGES; s = s + 1) begin : g_stage
            localparam integer SH = (1 << s);          // this stage's distance
            wire [WIDTH-1:0] cur = stage[s];

            // Four candidate results for a fixed distance SH.
            wire [WIDTH-1:0] left_log  = {cur[WIDTH-1-SH:0], {SH{1'b0}}};
            wire [WIDTH-1:0] left_rot  = {cur[WIDTH-1-SH:0], cur[WIDTH-1:WIDTH-SH]};
            wire [WIDTH-1:0] right_log = {{SH{1'b0}}, cur[WIDTH-1:SH]};
            wire [WIDTH-1:0] right_rot = {cur[SH-1:0], cur[WIDTH-1:SH]};

            wire [WIDTH-1:0] moved = dir ? (rotate ? right_rot : right_log)
                                         : (rotate ? left_rot  : left_log);

            // Enable this stage only when the matching shamt bit is set.
            assign stage[s+1] = shamt[s] ? moved : cur;
        end
    endgenerate

    assign data_out = stage[STAGES];
endmodule

// tb_barrel_shifter.v
// Self-checking testbench. A behavioral reference computes the expected
// result for every vector and compares it against the structural DUT.
module tb_barrel_shifter;
    localparam WIDTH   = 8;
    localparam SHIFT_W = $clog2(WIDTH);

    reg  [WIDTH-1:0]   data_in;
    reg  [SHIFT_W-1:0] shamt;
    reg                dir;
    reg                rotate;
    wire [WIDTH-1:0]   data_out;

    integer errors = 0;

    barrel_shifter #(.WIDTH(WIDTH)) dut (
        .data_in (data_in),
        .shamt   (shamt),
        .dir     (dir),
        .rotate  (rotate),
        .data_out(data_out)
    );

    // Golden model using Verilog shift operators.
    function [WIDTH-1:0] model;
        input [WIDTH-1:0]   d;
        input [SHIFT_W-1:0] n;
        input               rdir;
        input               rrot;
        begin
            if (rrot)
                model = rdir ? ((d >> n) | (d << (WIDTH-n)))
                             : ((d << n) | (d >> (WIDTH-n)));
            else
                model = rdir ? (d >> n) : (d << n);
        end
    endfunction

    task check;
        input [WIDTH-1:0]   d;
        input [SHIFT_W-1:0] n;
        input               rdir;
        input               rrot;
        reg   [WIDTH-1:0]   exp;
        begin
            data_in = d; shamt = n; dir = rdir; rotate = rrot;
            #1;
            exp = model(d, n, rdir, rrot);
            $display("in=%b amt=%0d dir=%s rot=%b -> out=%b exp=%b %s",
                     d, n, rdir ? "R" : "L", rrot, data_out, exp,
                     (data_out === exp) ? "OK" : "MISMATCH");
            if (data_out !== exp) errors = errors + 1;
        end
    endtask

    initial begin
        $display("== Parameterized barrel shifter, WIDTH=%0d ==", WIDTH);
        check(8'b1001_0110, 3, 1'b0, 1'b0);   // logical left  by 3
        check(8'b1001_0110, 3, 1'b1, 1'b0);   // logical right by 3
        check(8'b0001_0011, 2, 1'b0, 1'b1);   // rotate  left  by 2
        check(8'b0001_0011, 5, 1'b1, 1'b1);   // rotate  right by 5
        check(8'b1111_0000, 0, 1'b0, 1'b1);   // amount 0 passes through
        check(8'b1010_1010, 4, 1'b1, 1'b0);   // logical right by 4
        check(8'b1100_0011, 1, 1'b0, 1'b1);   // rotate  left  by 1

        if (errors == 0) $display("RESULT: all vectors matched the model");
        else             $display("RESULT: %0d mismatch(es)", errors);
        $finish;
    end
endmodule
== Parameterized barrel shifter, WIDTH=8 ==
in=10010110 amt=3 dir=L rot=0 -> out=10110000 exp=10110000       OK
in=10010110 amt=3 dir=R rot=0 -> out=00010010 exp=00010010       OK
in=00010011 amt=2 dir=L rot=1 -> out=01001100 exp=01001100       OK
in=00010011 amt=5 dir=R rot=1 -> out=10011000 exp=10011000       OK
in=11110000 amt=0 dir=L rot=1 -> out=11110000 exp=11110000       OK
in=10101010 amt=4 dir=R rot=0 -> out=00001010 exp=00001010       OK
in=11000011 amt=1 dir=L rot=1 -> out=10000111 exp=10000111       OK
RESULT: all vectors matched the model
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmp_6fklz4o/barrel_shifter.v:110: $finish called at 7 (1s)

How the log-stage structure works

The key idea is that any shift distance from 0 to WIDTH-1 can be written as a sum of powers of two, which is exactly the binary representation of shamt. So a shift by 6 on an 8-bit word is a shift by 4 followed by a shift by 2, and shamt = 110 turns on precisely those two stages. With WIDTH = 8 you get three stages shifting by 1, 2, and 4; a 32-bit word needs five stages. That logarithmic depth is what makes a barrel shifter fast compared with a loop that moves one position per cycle.

Each stage computes four fixed-distance candidates with concatenation. For a left logical shift by SH, the low bits are padded with {SH{1'b0}}; for a left rotate, the bits that fall off the top are concatenated back in at the bottom with cur[WIDTH-1:WIDTH-SH]. Because SH is a localparam derived from the generate variable, every part-select range is constant, which is what lets the tool build clean hardware instead of a variable indexing mess.

The dir and rotate inputs choose between the four candidates, and the shamt[s] bit decides whether the stage is active at all. The output of the last stage is wired straight to data_out, so the whole block is purely combinational: change any input and the result settles after the mux propagation delay, with no clock involved. The testbench’s model function reproduces the same behavior using native <<, >>, and rotate expressions, giving an independent reference that catches any wiring slip in the structural version.

A compact behavioral alternative

If you only need a quick, readable block and trust the synthesizer to infer the mux tree, a behavioral description is far shorter. This version adds an arithmetic-right mode using a signed cast and the >>> operator, which replicates the sign bit instead of shifting in zeros.

// barrel_behav.v
// Compact behavioral barrel shifter. The synthesizer still infers a
// barrel (log-depth mux tree); this form is shorter to read and adds an
// arithmetic-right mode using a signed cast.
module barrel_behav #(
    parameter WIDTH = 8
)(
    input  wire [WIDTH-1:0]         data_in,
    input  wire [$clog2(WIDTH)-1:0] shamt,
    input  wire [1:0]               mode,   // 0=log-left 1=log-right 2=rotate-left 3=arith-right
    output reg  [WIDTH-1:0]         data_out
);
    wire signed [WIDTH-1:0] s_in = data_in;
    always @(*) begin
        case (mode)
            2'd0: data_out = data_in << shamt;                       // logical left
            2'd1: data_out = data_in >> shamt;                       // logical right
            2'd2: data_out = (data_in << shamt) |                    // rotate left
                             (data_in >> (WIDTH - shamt));
            2'd3: data_out = s_in >>> shamt;                         // arithmetic right
            default: data_out = data_in;
        endcase
    end
endmodule

// tb_barrel_behav.v
// Drives all four modes and prints each result with $monitor-style output.
module tb_barrel_behav;
    localparam WIDTH   = 8;
    localparam SHIFT_W = $clog2(WIDTH);

    reg  [WIDTH-1:0]   data_in;
    reg  [SHIFT_W-1:0] shamt;
    reg  [1:0]         mode;
    wire [WIDTH-1:0]   data_out;

    barrel_behav #(.WIDTH(WIDTH)) dut (
        .data_in (data_in),
        .shamt   (shamt),
        .mode    (mode),
        .data_out(data_out)
    );

    initial begin
        $display("== Behavioral barrel shifter, 4 modes ==");
        data_in = 8'b1011_0001; shamt = 3;

        mode = 2'd0; #1 $display("log-left   by %0d : %b -> %b", shamt, data_in, data_out);
        mode = 2'd1; #1 $display("log-right  by %0d : %b -> %b", shamt, data_in, data_out);
        mode = 2'd2; #1 $display("rotate-left by %0d : %b -> %b", shamt, data_in, data_out);
        mode = 2'd3; #1 $display("arith-right by %0d : %b -> %b", shamt, data_in, data_out);

        data_in = 8'b0100_1111; shamt = 2;
        mode = 2'd3; #1 $display("arith-right by %0d : %b -> %b (MSB=0)", shamt, data_in, data_out);

        $finish;
    end
endmodule
== Behavioral barrel shifter, 4 modes ==
log-left   by 3 : 10110001 -> 10001000
log-right  by 3 : 10110001 -> 00010110
rotate-left by 3 : 10110001 -> 10001101
arith-right by 3 : 10110001 -> 11110110
arith-right by 2 : 01001111 -> 00010011 (MSB=0)
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpdn0mu_t_/barrel_behav.v:56: $finish called at 5 (1s)

Notice in the log that arith-right on 10110001 fills with ones because the MSB is 1, while the same mode on 01001111 fills with zeros. That sign-aware fill is the one behavior a plain logical shift cannot reproduce.

Common mistakes

  • Using a variable in a part-select. Writing cur[WIDTH-1 : WIDTH-shamt] with a runtime shamt is illegal; part-select bounds must be constant. The staged design keeps every range tied to the elaboration-time SH, which is why it elaborates cleanly.
  • Rotating with the wrong complement. A rotate is (d << n) | (d >> (WIDTH - n)). Forgetting the OR, or using WIDTH instead of WIDTH - n, silently turns a rotate into a plain shift for most amounts.
  • Sizing the shift amount incorrectly. For a WIDTH-bit word, shamt needs $clog2(WIDTH) bits. Making it wider lets simulation request shifts past the word size, where real hardware would wrap or truncate differently than you expect.
  • Confusing logical and arithmetic right shift. >> always shifts in zeros; >>> only sign-extends when its operand is declared signed. Applying >>> to an unsigned vector just gives a logical shift.
  • Clocking a combinational shifter. A barrel shifter has no state. Wrapping it in always @(posedge clk) adds a needless register stage and hides timing; keep it in always @(*) or continuous assignments unless you deliberately want a pipeline.

Quick check

How many mux stages does a WIDTH-bit barrel shifter need, and why?

It needs $clog2(WIDTH) stages. Each stage shifts by a distinct power of two (1, 2, 4, …), and any amount is the binary sum of those powers, so one bit of shamt controls each stage.

Why is a barrel shifter combinational rather than sequential?

It produces the shifted result in a single propagation delay with no clock, giving constant latency. A sequential shift register would take up to N clock cycles to move by N positions.

What is the difference between logical and arithmetic right shift?

A logical right shift fills the vacated high bits with zeros (>>). An arithmetic right shift replicates the sign bit so negative numbers stay negative, available via >>> on a signed operand.

Why does a rotate use an OR of two shifts?

Bits that leave one end must re-enter the other. Combining d << n with d >> (WIDTH - n) puts the departing bits back at the opposite side, which a single shift cannot do.

Have questions about this topic?
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
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