Barrel Rotator in Verilog: Rotate Left/Right with Code
A barrel rotator performs a circular rotation of a data word by a variable amount in a single clock cycle, with no state and no sequential shifting. Unlike a shift, bits that fall off one end wrap around to the other end, so no information is lost. This page gives clean, simulator-verified barrel rotator Verilog code built from the classic logarithmic mux-stage structure.
The key idea is that a rotate by any amount from 0 to N-1 can be decomposed into a cascade of fixed rotates by powers of two (1, 2, 4, …), each gated by one bit of the rotate amount. For an N-bit word this needs only log2(N) stages of 2:1 multiplexers, which is why the barrel rotator is a staple of ALUs, cryptographic datapaths, and interview questions.
This parameterized 8-bit rotator rotates din left by amt using three mux stages (rotate by 1, 2, and 4). Each stage is a single conditional assignment gated by one bit of amt, and the testbench checks every rotate amount against the reference (in<<amt)|(in>>(N-amt)).
module barrel_rotate_left #(
parameter N = 8,
parameter S = 3 // S = log2(N)
) (
input wire [N-1:0] din,
input wire [S-1:0] amt,
output wire [N-1:0] dout
);
wire [N-1:0] stage [0:S];
assign stage[0] = din;
genvar i;
generate
for (i = 0; i < S; i = i + 1) begin : rot_stage
// Each stage optionally rotates left by 2^i
assign stage[i+1] = amt[i]
? ((stage[i] << (1 << i)) | (stage[i] >> (N - (1 << i))))
: stage[i];
end
endgenerate
assign dout = stage[S];
endmodule
module tb;
localparam N = 8;
localparam S = 3;
reg [N-1:0] din;
reg [S-1:0] amt;
wire [N-1:0] dout;
reg [N-1:0] ref_val;
integer k;
integer errors;
barrel_rotate_left #(.N(N), .S(S)) dut (.din(din), .amt(amt), .dout(dout));
function [N-1:0] rotl;
input [N-1:0] v;
input integer a;
begin
if (a == 0) rotl = v;
else rotl = (v << a) | (v >> (N - a));
end
endfunction
initial begin
errors = 0;
din = 8'b1011_0001; // 0xB1
for (k = 0; k < N; k = k + 1) begin
amt = k[S-1:0];
#1;
ref_val = rotl(din, k);
if (dout !== ref_val) begin
$display("FAIL rotl amt=%0d din=%b got=%b exp=%b", k, din, dout, ref_val);
errors = errors + 1;
end else begin
$display("PASS rotl amt=%0d din=%b dout=%b", k, din, dout);
end
end
// second vector
din = 8'b0000_1111;
for (k = 0; k < N; k = k + 1) begin
amt = k[S-1:0];
#1;
ref_val = rotl(din, k);
if (dout !== ref_val) begin
$display("FAIL rotl amt=%0d din=%b got=%b exp=%b", k, din, dout, ref_val);
errors = errors + 1;
end else begin
$display("PASS rotl amt=%0d din=%b dout=%b", k, din, dout);
end
end
if (errors == 0) $display("ALL TESTS PASSED");
else $display("TESTS FAILED: %0d", errors);
$finish;
end
endmodule
PASS rotl amt=0 din=10110001 dout=10110001 PASS rotl amt=1 din=10110001 dout=01100011 PASS rotl amt=2 din=10110001 dout=11000110 PASS rotl amt=3 din=10110001 dout=10001101 PASS rotl amt=4 din=10110001 dout=00011011 PASS rotl amt=5 din=10110001 dout=00110110 PASS rotl amt=6 din=10110001 dout=01101100 PASS rotl amt=7 din=10110001 dout=11011000 PASS rotl amt=0 din=00001111 dout=00001111 PASS rotl amt=1 din=00001111 dout=00011110 PASS rotl amt=2 din=00001111 dout=00111100 PASS rotl amt=3 din=00001111 dout=01111000 PASS rotl amt=4 din=00001111 dout=11110000 PASS rotl amt=5 din=00001111 dout=11100001 PASS rotl amt=6 din=00001111 dout=11000011 PASS rotl amt=7 din=00001111 dout=10000111 ALL TESTS PASSEDThe log proves the staged-mux network matches the golden rotate for all eight amounts on two different input vectors: a sparse pattern (0xB1) and a block pattern (0x0F). Every bit wraps correctly, confirming it rotates rather than shifts.
This variant adds a
dircontrol. Because rotating right byamtequals rotating left byN-amt, a single left-rotate network can serve both directions: whendiris high the amount is converted to(N-amt) mod Nbefore entering the same three stages.module barrel_rotator #( parameter N = 8, parameter S = 3 // S = log2(N) ) ( input wire [N-1:0] din, input wire [S-1:0] amt, input wire dir, // 0 = rotate left, 1 = rotate right output wire [N-1:0] dout ); // Rotating right by amt == rotating left by (N - amt). // Convert a right amount to the equivalent left amount, then do // one staged left-rotate network. wire [S-1:0] eff; // effective left-rotate amount assign eff = dir ? ((~amt) + {{(S-1){1'b0}}, 1'b1}) : amt; // (N-amt) mod N wire [N-1:0] stage [0:S]; assign stage[0] = din; genvar i; generate for (i = 0; i < S; i = i + 1) begin : rot_stage assign stage[i+1] = eff[i] ? ((stage[i] << (1 << i)) | (stage[i] >> (N - (1 << i)))) : stage[i]; end endgenerate assign dout = stage[S]; endmodule module tb; localparam N = 8; localparam S = 3; reg [N-1:0] din; reg [S-1:0] amt; reg dir; wire [N-1:0] dout; reg [N-1:0] ref_val; integer k; integer errors; barrel_rotator #(.N(N), .S(S)) dut (.din(din), .amt(amt), .dir(dir), .dout(dout)); function [N-1:0] rotl; input [N-1:0] v; input integer a; begin if (a == 0) rotl = v; else rotl = (v << a) | (v >> (N - a)); end endfunction function [N-1:0] rotr; input [N-1:0] v; input integer a; begin if (a == 0) rotr = v; else rotr = (v >> a) | (v << (N - a)); end endfunction initial begin errors = 0; din = 8'b1101_0010; // 0xD2 // Left direction dir = 1'b0; for (k = 0; k < N; k = k + 1) begin amt = k[S-1:0]; #1; ref_val = rotl(din, k); if (dout !== ref_val) begin $display("FAIL LEFT amt=%0d din=%b got=%b exp=%b", k, din, dout, ref_val); errors = errors + 1; end else $display("PASS LEFT amt=%0d din=%b dout=%b", k, din, dout); end // Right direction dir = 1'b1; for (k = 0; k < N; k = k + 1) begin amt = k[S-1:0]; #1; ref_val = rotr(din, k); if (dout !== ref_val) begin $display("FAIL RIGHT amt=%0d din=%b got=%b exp=%b", k, din, dout, ref_val); errors = errors + 1; end else $display("PASS RIGHT amt=%0d din=%b dout=%b", k, din, dout); end if (errors == 0) $display("ALL TESTS PASSED"); else $display("TESTS FAILED: %0d", errors); $finish; end endmodulePASS LEFT amt=0 din=11010010 dout=11010010
PASS LEFT amt=1 din=11010010 dout=10100101
PASS LEFT amt=2 din=11010010 dout=01001011
PASS LEFT amt=3 din=11010010 dout=10010110
PASS LEFT amt=4 din=11010010 dout=00101101
PASS LEFT amt=5 din=11010010 dout=01011010
PASS LEFT amt=6 din=11010010 dout=10110100
PASS LEFT amt=7 din=11010010 dout=01101001
PASS RIGHT amt=0 din=11010010 dout=11010010
PASS RIGHT amt=1 din=11010010 dout=01101001
PASS RIGHT amt=2 din=11010010 dout=10110100
PASS RIGHT amt=3 din=11010010 dout=01011010
PASS RIGHT amt=4 din=11010010 dout=00101101
PASS RIGHT amt=5 din=11010010 dout=10010110
PASS RIGHT amt=6 din=11010010 dout=01001011
PASS RIGHT amt=7 din=11010010 dout=10100101
ALL TESTS PASSEDThe log sweeps all eight amounts in both directions. The left cases match
rotland the right cases matchrotr, verifying theN-amtconversion trick reuses one rotate network for both directions with no extra mux layers.How the staged-mux barrel rotator works
A barrel rotator exploits binary decomposition of the rotate amount. For an N-bit word, any rotate amount k in the range 0 to N-1 can be written in binary, and each set bit i contributes a fixed rotate by 2i. Cascading these conditional rotates produces the total rotate in one combinational pass.
- Stage 0 rotates by 1 if
amt[0]is set.- Stage 1 rotates by 2 if
amt[1]is set.- Stage 2 rotates by 4 if
amt[2]is set.Each stage is just a row of N 2:1 multiplexers choosing between the pass-through value and the pre-wired rotated-by-2i value. The wiring of each fixed rotate is free in hardware — it is only wires — so the cost is dominated by the muxes.
Rotate vs shift (logical and arithmetic)
These operations are easy to confuse. A barrel rotator wraps; a shifter fills.
- Rotate: bits leaving one end re-enter the other end. No bits are lost; the word is a permutation of itself. Used in cryptography (e.g. ROTL in SHA/ChaCha) and ALU rotate instructions.
- Logical shift: vacated positions are filled with zeros. Bits shifted out are discarded.
- Arithmetic shift right: vacated high bits are filled with copies of the sign bit to preserve signedness.
The same staged structure builds all three. A barrel shifter uses a constant fill (0 or sign) for the non-wrapped positions, while the barrel rotator feeds the wrapped bits back in. The mux-stage count — log2(N) stages — is identical; only the data feeding the muxes changes.
Area and timing: the log2(N) mux cost
The decisive advantage of the barrel structure is that it needs only log2(N) stages, not N. An 8-bit rotator uses 3 stages, a 32-bit rotator uses 5, a 64-bit rotator uses 6. Each stage is N 2:1 muxes, so total mux count is roughly N × log2(N) — for example 32 × 5 = 160 muxes for a 32-bit rotator.
Critical-path delay is log2(N) mux delays in series, which grows only logarithmically with width. This is far better than an iterative shift register (N cycles) or a naive N:1 mux per output bit. Because the amount decode is implicit in the per-stage gating, there is no separate wide decoder on the critical path.
Common mistakes
- Using a shift instead of a rotate. Writing
dout = din << amt;drops bits and zero-fills. You must OR in the wrapped part:(din << amt) | (din >> (N-amt)).- The amt==0 corner case. When the amount is zero,
din >> (N-0)is a shift by N, which is undefined/zero behavior. In a per-stage design this is harmless because every stage simply passes through when its bit is 0, but a single-expression reference model must special-case zero (as the testbench functions do).- Mismatched amount width. The amount bus must be exactly log2(N) bits. A wider amount lets the rotate exceed N-1 and the extra bits are ignored only if you mask; an under-wide amount cannot reach all rotations.
- Right-rotate sign extension. Rotate right is
(din >> amt) | (din << (N-amt)). Using an arithmetic shift here would corrupt the wrap for signed-looking data.Synthesis notes
The
generate-for staged description synthesizes directly into a balanced tree of 2:1 multiplexers; synthesis tools recognize the pattern and map it to the technology's mux cells or to LUTs on an FPGA. Keep the rotate amount as a dedicated control input so the tool can share the gating logic across all N bit-slices of a stage.For the left/right variant, performing the
N-amtconversion once in front of a single network (as in Example 2) is cheaper than instantiating two full rotate networks and selecting between them, since it adds only a small adder/complementer on the amount rather than another N × log2(N) mux array. This is the standard way ALUs implement a bidirectional barrel shifter/rotator.FAQ
Can N be non-power-of-two? The clean log2(N) staged structure assumes N is a power of two so that powers-of-two rotates compose exactly. For non-power-of-two widths you typically round the amount decode or use a different (often N:1 mux) structure.
Is it combinational or clocked? The rotator itself is purely combinational — it produces the result in one pass with no clock. You register its output if it sits on a timed datapath.
How do I make a barrel shifter instead? Replace the wrapped feedback term with a constant: zeros for a logical shift, or a sign-bit replica for an arithmetic right shift. The mux-stage skeleton is unchanged.
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