Hello! In our last lesson, we built a synchronous up-counter by adding an incrementer to a basic register. We saw how a simple change in the data being loaded—count + 1 instead of an external input—creates entirely new functionality.
Today, we'll continue this theme by exploring another powerful variation of the register: the shift register. Instead of performing arithmetic, a shift register moves its stored data sideways. This capability is fundamental to digital design, enabling everything from data conversion between serial and parallel formats to simple data delays. Our goal is to implement a flexible, parameterized N-bit shift register in Verilog.
1. What is a Shift Register?
At its core, a shift register is a chain of flip-flops connected in series. The output of one flip-flop becomes the input to the next. All flip-flops share the same clock, so on every clock edge, the entire set of stored bits shifts one position down the line. A new bit enters one end of the chain, and the bit at the other end is shifted out.
The diagram below shows the structure of a 5-bit shift register made from five D-type flip-flops.

Shift registers have many practical uses. To get a feel for why they are so important, let's watch a short video.
30 - Describing Registers in Verilog
This video from Anas Salah Eddin provides a great introduction to the concept and applications of shift registers.
Watch the segment from the beginning to understand the basic functionality and see how shift registers are used for simple multiplication/division by two and for serial communication, a very common application in digital systems.
2. Implementing a Shift Register with Concatenation
The most common and efficient way to describe a shift in Verilog is by using the concatenation operator ({}). This operator allows us to join multiple signals or parts of signals together to form a new, wider vector.
For a left shift, we want to discard the most significant bit (MSB), move all other bits one position to the left, and insert a new bit at the least significant bit (LSB) position. If our register is shreg and our new input bit is serial_in, the operation looks like this:
shreg <= {shreg[N-2:0], serial_in};
Let's break this down for an 8-bit register (N=8):
shreg[6:0]: This selects the lower 7 bits of the register (from bit 6 down to bit 0).{shreg[6:0], serial_in}: This joins the 7 bits fromshregwith the 1-bitserial_in. The result is a new 8-bit vector whereserial_inis the new LSB.shreg <= ...: This new 8-bit vector is assigned to the register, completing the shift on the next positive clock edge. The old MSB (shreg[7]) is effectively dropped.
The following resource shows a clean example of this technique.
This AMD documentation provides a concise, industry-standard example of a shift register using concatenation.
Please read the code under the heading "8-Bit Shift Register Coding Example One (Verilog)". Notice how the line shreg = {shreg[WIDTH-2:0], SI}; implements the entire left shift operation in one statement.
3. A Parameterized Left-Shift Register
Now, let's write a complete, parameterized module for a left-shift register that follows the style we've established in this course, including a synchronous reset and an enable signal.
module shift_left_register #(
parameter N = 8 // Default width is 8 bits
) (
// Inputs
input wire clk,
input wire reset, // Synchronous, active-high reset
input wire enable, // Shift enable
input wire serial_in, // The new bit to shift in
// Output
output reg [N-1:0] shift_out
);
// This block describes the sequential logic for the shift register
always @(posedge clk) begin
if (reset) begin
// On reset, clear the register to zero
shift_out <= {N{1'b0}};
end else if (enable) begin
// If not reset and enabled, perform a left shift
// The new bit comes in at the LSB position
shift_out <= {shift_out[N-2:0], serial_in};
end
// If reset is 0 and enable is 0, 'shift_out' implicitly holds its value.
end
endmodule
This structure should look very familiar. It's almost identical to the counter from our last lesson, with the only change being the logic inside the else if (enable) block.
Quick Practice
Based on the left-shift example above, how would you write the line of code to perform a right shift? The new bit (serial_in) should enter at the MSB position.
Click for the solution
For a right shift, you want to take the upper N-1 bits of the register and place the new bit to their left (at the MSB position). The old LSB is discarded.
// For a right shift, the new bit becomes the MSB
shift_out <= {serial_in, shift_out[N-1:1]};
4. Building a Bidirectional Shift Register
A more versatile design would allow us to choose the direction of the shift. We can achieve this by adding a control input, let's call it dir, and using a case or if/else statement to select the operation.
The following article provides an excellent, complete example of a parameterized N-bit bidirectional shift register.
Verilog n-bit Bidirectional Shift Register
This article from ChipVerify details the design and implementation of a shift register that can shift both left and right.
First, read the "Design" section to understand the inputs and features of this more advanced register. Then, carefully study the Verilog code in the main section of the article. Pay close attention to how the case (dir) statement is used to select between a left shift (dir=1) and a right shift (dir=0).
As you can see from the article, combining behaviors is straightforward. By using control signals and conditional logic, you can create powerful, multi-functional components from simple building blocks.
An extension of this idea is the universal shift register, which can typically shift left, shift right, parallel load new data, or hold its current value, all selected by control inputs. It's a great example of how the register concepts we've learned (hold, load, shift) come together in one module. The video from the start of the lesson also covers this advanced component if you're curious.
Conclusion
In this lesson, you have learned how to implement another essential sequential logic element: the shift register. You've seen that it's a simple chain of flip-flops and that its behavior can be modeled concisely in Verilog using the concatenation operator.
Key Takeaways:
- A shift register moves data serially (one bit at a time) through a chain of flip-flops.
- The primary Verilog tool for this is the concatenation operator (
{}), which builds a new vector from smaller parts. shreg <= {shreg[N-2:0], serial_in};implements a left shift.shreg <= {serial_in, shreg[N-1:1]};implements a right shift.- By adding control signals and using
caseorifstatements, we can create more complex components like bidirectional or universal shift registers.
In the next module, we will begin our study of Finite State Machines (FSMs). The registers you have mastered over the last few lessons are the heart of an FSM—they are the elements that store the machine's "state." You are now perfectly equipped to see how we combine this state memory with combinational logic to create circuits that can implement complex sequential behaviors.