A shift register is a chain of flip-flops in which the output of each flip-flop drives the data input of the next. All flip-flops share the same clock, so on every clock edge the stored bits move one position along the chain, and a new bit enters at one end. A bidirectional shift register can move its bits either left or right, selected by a control input.
12 min read | Beginner Level
What You'll Learn
- How a shift register moves bits one position per clock, and the four basic shift register types
- Write an n-bit bidirectional shift register with enable and reset in Verilog
- What synthesis builds for each bit, and how concatenation sets the shift direction
- Verify the design with a testbench and avoid common shift register mistakes
How a Shift Register Works
Consider a 5-bit register holding 10110 that shifts right, with its serial input tied to 0. On each clock edge, every bit moves one position to the right, the rightmost bit is shifted out, and a 0 enters on the left:
Start : 10110 1st clock : 01011 2nd clock : 00101
Shift registers are grouped by how data enters and leaves them:
| Type | Data in | Data out | Typical use |
|---|---|---|---|
| SISO (serial in, serial out) | 1 bit per clock | 1 bit per clock | Delay lines |
| SIPO (serial in, parallel out) | 1 bit per clock | All bits at once | Receiving serial data |
| PISO (parallel in, serial out) | All bits at once | 1 bit per clock | Transmitting serial data |
| PIPO (parallel in, parallel out) | All bits at once | All bits at once | Storage registers, bit manipulation |
The design in this article takes one serial input bit and makes all of its bits available as a parallel output, so it is a SIPO shift register, with the added choice of shift direction.
Design
The module has five inputs and one output:
d- Serial data bit that enters the register on each shiftclk- Clock shared by all flip-flopsen- Enable: shift when 1, hold the current value when 0dir- Direction: 0 shifts left (denters at bit 0), 1 shifts right (denters at the MSB)rstn- Active-low synchronous reset that clears the registerout- The current value of all flip-flops
The parameter MSB sets the number of bits in the register, for example 4, 8 or 16. Despite its name, it is the register width, so out is declared [MSB-1:0].
module shift_reg #(parameter MSB=8) ( input d, // Declare input for data to the first flop in the shift register
input clk, // Declare input for clock to all flops in the shift register
input en, // Declare input for enable to switch the shift register on/off
input dir, // Declare input to shift in either left or right direction
input rstn, // Declare input to reset the register to a default value
output reg [MSB-1:0] out); // Declare output to read out the current value of all flops in this register
// This always block will "always" be triggered on the rising edge of clock
// Once it enters the block, it will first check to see if reset is 0 and if yes then reset register
// If no, then check to see if the shift register is enabled
// If no => maintain previous output. If yes, then shift based on the requested direction
always @ (posedge clk)
if (!rstn)
out <= 0;
else begin
if (en)
case (dir)
0 : out <= {out[MSB-2:0], d}; // Shift left: drop the MSB, d enters at bit 0
1 : out <= {d, out[MSB-1:1]}; // Shift right: drop bit 0, d enters at the MSB
endcase
else
out <= out; // Hold
end
endmodule
Each shift is written as a single concatenation. For a left shift, {out[MSB-2:0], d} takes every bit except the MSB, moves it one position up, and places d in bit 0. For a right shift, {d, out[MSB-1:1]} takes every bit except bit 0, moves it one position down, and places d in the MSB.
Synthesis result: The tool builds MSB flip-flops. In front of each one is a small mux that selects its next value: its left neighbor, its right neighbor (or d at the ends), or its own current value when en is 0. The hold path is often implemented as a clock enable on the flip-flops instead of a mux input. Reset gating forces each D input to 0 when rstn is low. There is no arithmetic, so each flip-flop's input depends on only a few signals and the register runs at high clock speeds.
Quick Check
Q: An 8-bit shift_reg is reset, then enabled with dir = 0. On three consecutive clock edges, d is 1, 0 and 1. What is out?
Show Answer
8'b0000_0101. With a left shift, each new bit enters at bit 0 and pushes the earlier bits up, so the first bit received ends up highest: 1, then 10, then 101.
Where are Shift Registers Used?
An SPI or UART receiver is a SIPO shift register: it shifts in one bit from the serial line on each bit time, and after 8 bits the parallel output holds a full byte for the rest of the chip. The transmitter is the reverse, a PISO register that is loaded with a byte and shifts it out one bit at a time. The direction setting decides whether the most or the least significant bit travels first, which differs between protocols.
Hardware Schematic

The schematic shows the 8-bit version. Each flip-flop's mux connects to its two neighbors, and the end flip-flops connect to d instead of a missing neighbor.
Testbench
The testbench instantiates a 16-bit version of the design and uses a 20 ns clock period (50 MHz). It applies and releases reset, enables the register, then:
- Toggles
dataon 7 clock edges while shifting left (dir = 0) - Switches to
dir = 1and togglesdataon 7 more edges while shifting right - Stops changing
datafor 7 edges, so the same value keeps shifting in
module tb_sr;
parameter MSB = 16; // [Optional] Declare a parameter to represent number of bits in shift register
reg data; // Declare a variable to drive d-input of design
reg clk; // Declare a variable to drive clock to the design
reg en; // Declare a variable to drive enable to the design
reg dir; // Declare a variable to drive direction of shift register
reg rstn; // Declare a variable to drive reset to the design
wire [MSB-1:0] out; // Declare a wire to capture output from the design
// Instantiate design (16-bit shift register) by passing MSB and connect with TB signals
shift_reg #(MSB) sr0 ( .d (data),
.clk (clk),
.en (en),
.dir (dir),
.rstn (rstn),
.out (out));
// Generate clock time period = 20ns, freq => 50MHz
always #10 clk = ~clk;
// Initialize variables to default values at time 0
initial begin
clk <= 0;
en <= 0;
dir <= 0;
rstn <= 0;
data <= 'h1;
end
// Drive main stimulus to the design to verify if this works
initial begin
// 1. Apply reset and deassert reset after some time
rstn <= 0;
#20 rstn <= 1;
en <= 1;
// 2. For 7 clocks, drive alternate values to data pin
repeat (7) @ (posedge clk)
data <= ~data;
// 3. Shift direction and drive alternate value to data pin for another 7 clocks
#10 dir <= 1;
repeat (7) @ (posedge clk)
data <= ~data;
// 4. Drive nothing for next 7 clocks, allow shift register to simply shift based on dir
repeat (7) @ (posedge clk);
// 5. Finish the simulation
$finish;
end
// Monitor values of these variables and print them into the logfile for debug
initial
$monitor ("rstn=%0b data=%b, en=%0b, dir=%0b, out=%b", rstn, data, en, dir, out);
endmodule
ncsim> run rstn=0 data=1, en=0, dir=0, out=xxxxxxxxxxxxxxxx rstn=0 data=1, en=0, dir=0, out=0000000000000000 rstn=1 data=1, en=1, dir=0, out=0000000000000000 rstn=1 data=0, en=1, dir=0, out=0000000000000001 rstn=1 data=1, en=1, dir=0, out=0000000000000010 rstn=1 data=0, en=1, dir=0, out=0000000000000101 rstn=1 data=1, en=1, dir=0, out=0000000000001010 rstn=1 data=0, en=1, dir=0, out=0000000000010101 rstn=1 data=1, en=1, dir=0, out=0000000000101010 rstn=1 data=0, en=1, dir=0, out=0000000001010101 rstn=1 data=0, en=1, dir=1, out=0000000001010101 rstn=1 data=1, en=1, dir=1, out=0000000000101010 rstn=1 data=0, en=1, dir=1, out=1000000000010101 rstn=1 data=1, en=1, dir=1, out=0100000000001010 rstn=1 data=0, en=1, dir=1, out=1010000000000101 rstn=1 data=1, en=1, dir=1, out=0101000000000010 rstn=1 data=0, en=1, dir=1, out=1010100000000001 rstn=1 data=1, en=1, dir=1, out=0101010000000000 rstn=1 data=1, en=1, dir=1, out=1010101000000000 rstn=1 data=1, en=1, dir=1, out=1101010100000000 rstn=1 data=1, en=1, dir=1, out=1110101010000000 rstn=1 data=1, en=1, dir=1, out=1111010101000000 rstn=1 data=1, en=1, dir=1, out=1111101010100000 rstn=1 data=1, en=1, dir=1, out=1111110101010000 Simulation complete via $finish(1) at time 430 NS + 0
Reading the log in three parts:
- Left shift (
dir=0): each newdatabit enters at bit 0, and the alternating pattern grows from the right:...0001,...0010,...0101, up to...01010101. - Right shift (
dir=1): the existing pattern moves back toward bit 0 and drops off the right end, while new bits enter at bit 15. The pattern now grows from the left:1000...,0100...,1010.... - Constant data:
datastays 1, so a 1 enters at bit 15 on every edge and a run of 1s fills the register from the left:1101...,1110...,1111....
CRC and Pseudo-Random Generators
Network and storage interfaces compute CRC checksums with a shift register whose input is the XOR of the incoming data bit and selected register bits. Built-in self-test logic and scramblers use a similar structure, a linear feedback shift register (LFSR), to generate long pseudo-random bit sequences from a handful of flip-flops and XOR gates.
Quick Check
Q: A 16-bit shift_reg is used as a serial receiver. How many enabled clock edges does it take before every bit of out holds received data?
Show Answer
16. Each enabled edge shifts in one bit, so the first bit received reaches the far end of the register after 16 edges. Before that, the bits that have not yet been filled still hold their reset value.
Delay Lines and Pipeline Alignment
When two signals take different numbers of pipeline stages to reach the same point, such as a data word and its valid flag, the shorter path is delayed with a shift register so both arrive in the same cycle. A shift register of length N delays its input by exactly N clock cycles.
Common Beginner Mistakes
Mistake #1: Mixing up left and right in the concatenation
Wrong: Labeling {out[MSB-2:0], d} as a right shift
Right: {out[MSB-2:0], d} shifts left; {d, out[MSB-1:1]} shifts right
Why? In a concatenation, the leftmost item becomes the most significant bits. Putting out[MSB-2:0] first moves every bit up by one position, which is a left shift. Check the direction by tracing where d ends up: bit 0 for a left shift, the MSB for a right shift.
Mistake #2: Using the shift operator and losing the serial input
Wrong: out <= out << 1;
Right: out <= {out[MSB-2:0], d};
Why? The << operator always fills the vacated bit with 0, so d never enters the register. It is correct for multiplying by 2, but a shift register needs the concatenation, or (out << 1) | d.
Mistake #3: Choosing the wrong part-select
Wrong: out <= {out[MSB-1:1], d};
Right: out <= {out[MSB-2:0], d};
Why? out[MSB-1:1] keeps the upper bits in their current positions and only replaces bit 0 with d. Nothing actually shifts. The width is still correct, so the compiler gives no warning.
Mistake #4: Writing the shift bit by bit with blocking assignments
Wrong: for (i = 1; i < MSB; i = i + 1) out[i] = out[i-1]; out[0] = d;
Right: Use non-blocking assignments, or the single concatenation shown in the design
Why? With blocking assignments, each bit is updated before the next iteration reads it. Counting upward, out[1] gets out[0], then out[2] gets the new out[1], which is also the old out[0], and so on, so the old bit 0 is copied into every position in one clock. Non-blocking assignments make every bit read its neighbor's value from before the clock edge, regardless of order. See Verilog Blocking & Non-Blocking.
Practice Exercise
Challenge: Universal Shift Register
Extend the design into a module univ_shift_reg with a parameter N for the width and a 2-bit mode input instead of en and dir:
2'b00- Hold2'b01- Shift right, with serial inputsr_inentering at the MSB2'b10- Shift left, with serial inputsl_inentering at bit 02'b11- Parallel load from an N-bit inputpin
Keep the active-low synchronous reset. This register can act as any of the four types from the table above.
Hint
Use a case statement on mode with one item per operation. The shift items are the same concatenations as in shift_reg. See Verilog case statement.
Solution
module univ_shift_reg #(parameter N = 8) (
input clk,
input rstn, // Active-low synchronous reset
input [1:0] mode, // 00 hold, 01 right, 10 left, 11 load
input sr_in, // Serial input for right shifts (enters at MSB)
input sl_in, // Serial input for left shifts (enters at bit 0)
input [N-1:0] pin, // Parallel load input
output reg [N-1:0] q
);
always @(posedge clk) begin
if (!rstn)
q <= {N{1'b0}};
else
case (mode)
2'b00 : q <= q; // Hold
2'b01 : q <= {sr_in, q[N-1:1]}; // Shift right
2'b10 : q <= {q[N-2:0], sl_in}; // Shift left
2'b11 : q <= pin; // Parallel load
endcase
end
endmodule
Synthesis builds N flip-flops, each preceded by a 4 to 1 mux selected by mode, with inputs from its own output, its two neighbors and its pin bit. Loading a word and then shifting right turns it into a PISO transmitter; shifting in serial bits and reading q makes it a SIPO receiver. This is the structure of classic 4-bit universal shift register chips.
Summary
In this tutorial, you learned:
- A shift register is a chain of flip-flops on a common clock that moves its bits one position per clock edge
- Shift registers are classified as SISO, SIPO, PISO or PIPO by how data enters and leaves
{out[MSB-2:0], d}shifts left withdentering at bit 0;{d, out[MSB-1:1]}shifts right withdentering at the MSB- Synthesis builds one flip-flop per bit with a small mux choosing between neighbors and the held value
- The
<<and>>operators fill with 0 and do not insert a serial input - Use non-blocking assignments, or a single concatenation, so every bit reads its neighbor's old value
- Shift registers are the core of serial interfaces, CRC generators and delay lines