In short: A bidirectional shift register places a 2-to-1 multiplexer in front of every flip-flop's D input so that a single DIR pin chooses whether each bit is loaded from its left or its right neighbour on the next clock edge.
Why one direction is not enough
A plain shift register moves data one way only. That is fine for delaying a signal or turning serial data into parallel, but many real blocks need to run the same storage in either direction. A serial multiplier shifts the multiplicand left while the multiplier shifts right. A CRC engine may need to process bits MSB-first or LSB-first depending on the protocol. A keypad scanner or an LED sweeper bounces a lit bit back and forth. Building two registers and muxing outputs would double the flip-flop count. The bidirectional design reuses the same flops and pays only for one small mux per bit.
The architecture in one picture
Take a 4-bit register with outputs Q3 Q2 Q1 Q0, where Q0 is the least significant bit. Define DIR = 1 as shift right (data moves toward Q0) and DIR = 0 as shift left (data moves toward Q3). Each flip-flop gets a 2:1 mux on its D pin:
- D[i] = DIR ? Q[i+1] : Q[i-1] for the interior bits;
- D[3] = DIR ? SIR : Q[2], where SIR is the serial input for right shifts;
- D[0] = DIR ? Q[1] : SIL, where SIL is the serial input for left shifts.
Key fact: An N-bit bidirectional register needs N flip-flops, N 2:1 muxes and two serial inputs. The mux cost is roughly one transmission-gate or AOI22 cell per bit, a small fraction of the flop area.
Walking through real clock edges
Start with 0001 (Q3 Q2 Q1 Q0). Hold DIR = 0 with SIL = 0. After clock one the pattern is 0010, after clock two it is 0100. Now flip DIR to 1 and present SIR = 1. On the next edge every bit loads from its right neighbour, so Q3 takes SIR and the register becomes 1010. With SIR = 0 the following edge gives 0101. Notice that the information is not lost on a reversal; bits that were not yet pushed out simply start travelling the other way, while the bit that falls off the end is gone.
Writing it in RTL
In Verilog you never instantiate muxes by hand. A conditional on the direction input is enough, and synthesis in Synopsys Design Compiler or Cadence Genus maps it to MUX2 cells or AOI structures, depending on the library.
always @(posedge clk or negedge rst_n)
if (!rst_n) q <= 4'b0000;
else if (dir) q <= {sir, q[3:1]}; // shift right
else q <= {q[2:0], sil}; // shift left
Two points interviewers like. First, use non-blocking assignments so every bit samples the old value of its neighbour; a blocking version would ripple a bit through the whole register in one cycle. Second, add a hold or load option and you have moved on to the full universal shift register, which adds parallel load as a third and fourth mux input.
Timing: the mux is now in the data path
A plain shift register has just clock-to-Q feeding the next D pin. Here a mux sits in between, so the setup check becomes: Tclk ≥ tcq + tmux + tsetup + skew. With illustrative 45 nm numbers of 0.35 ns, 0.20 ns and 0.10 ns that is 0.65 ns before skew, so roughly 1.4 GHz is the ceiling without margin. Tools such as Synopsys PrimeTime or Cadence Tempus report this as a plain reg-to-reg path.
The bigger risk is hold. The shortest path, Q to mux to neighbouring D, has very little delay, and if clock skew between adjacent flops exceeds tcq + tmux − thold the bit races through two stages. Physical design fixes this with delay buffers, which is why hold fixing is routine in shift-register-heavy blocks such as scan chains.
Key fact: DIR is a synchronous control signal. Change it right after a clock edge from a flop in the same domain. If DIR comes from an asynchronous pin, it must pass through a two-flop synchroniser, or half the muxes may switch in time and half may not, corrupting the stored word.
Variations and comparison
| Feature | Unidirectional | Bidirectional | Universal |
|---|---|---|---|
| Mux per bit | None | 2:1 | 4:1 |
| Control pins | None | DIR | S1, S0 |
| Parallel load | No | No | Yes |
| Critical path | tcq + tsetup | + one mux | + larger mux |
The same idea appears in scan design. A scan flip-flop is a D flop with a 2:1 mux selecting functional data or the scan input, and DFT tools like Siemens Tessent or Synopsys DFT Compiler stitch thousands of them into shift paths. If the topic is new, read our primer on SIPO and PIPO registers first.
Common mistakes
- Swapping the mux inputs, so DIR = 1 shifts left while the documentation says right. Always draw the table.
- Forgetting that SIL and SIR feed different ends; tying both to one pin merges the edge behaviour.
- Using a latch-based mux or a combinational loop through two stages, which creates a transparent path.
- Not resetting the register, leaving X values to circulate in simulation.
Design teams that prototype blocks like this often work with training and design partners; ChipXpert's VLSI training programmes cover the full RTL-to-GDS flow around such building blocks.
Want to build, simulate and time circuits like this yourself? Explore the hands-on digital design modules in the CourseTron courses and practise with guided labs.
FAQ
How many gates does a 4-bit bidirectional shift register need?
Four D flip-flops and four 2:1 multiplexers, plus the two serial input pins. Each 2:1 mux is about three to four basic gates if built from AND-OR logic.
What happens if DIR changes mid-operation?
The next clock edge simply uses the new direction. Stored bits are kept; only the movement reverses, so one end bit is lost and a new serial bit enters at the other end.
How is it different from a universal shift register?
A universal register adds parallel load and hold, which needs a 4:1 mux per bit and two select lines instead of one.
Can it be used as a multiplier building block?
Yes. Left shifts double the value and right shifts halve it, so shift-and-add multiplication and division use exactly this structure.