Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
    • Flip-Flops and Registers
    • Counters and Timers
    • Shift Registers and LFSRs
      • Serial and Parallel Data Movement
      • Universal Shift Register
      • LFSR for PRBS Generation
    • Pipelining
    • Stalls, Bubbles and Hazards
    • Retiming
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Shift Registers and LFSRs
  1. Topics
  2. RTL Design
  3. Sequential Design
  4. Shift Registers and LFSRs
  5. Universal Shift Register

Part 3 · Sequential · Intermediate

Universal Shift Register

One register with hold, shift left, shift right and parallel load modes.

On this page

    Why this matters

    One register with a 4:1 mux in front of each flop can hold, shift left, shift right or load. It is the building block behind serialisers, deserialisers and shift-and-add arithmetic.

    After this lesson you can: build a four-mode universal shift register and tell it apart from a barrel shifter.

    One register, four modes

    A universal shift register is one W-bit register that can hold, shift right, shift left or load a whole word, chosen each clock by a 2-bit mode.

    mode[1:0]

    Operation

    Next value of the register

    00

    Hold

    q

    01

    Shift right

    {sin_r, q[W-1:1]}

    10

    Shift left

    {q[W-2:0], sin_l}

    11

    Parallel load

    d

    Each flip-flop takes its D input from a 4:1 multiplexer. The choices are its own output, each neighbour and the parallel input.

    One bit slice: a 4:1 mux selected by mode feeds flop i; its inputs are the flop's own output (00), the neighbour above (01), the neighbour below (10) and the parallel bit d[i] (11)

    Read the slice left to right: four candidates enter the mux, mode picks one, and the clock edge copies it into the flop. The whole register is W copies of this slice.

    • Shift right (01) takes the bit from the flop above, q[i+1]. The top flop has no neighbour above, so it takes sin_r.

    • Shift left (10) takes the bit from the flop below, q[i-1]. Flop 0 takes sin_l instead.

    • Hold (00) feeds the flop its own output, so nothing changes at the edge.

    The same block serves as a delay line, serializer, deserializer and bidirectional shifter.

    The case body

    In RTL the four mux inputs are the four branches of one case, inside the clocked block.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    // snippet
    unique case (mode)
      2'b00:   q <= q;                         // hold
      2'b01:   q <= {sin_r, q[W-1:1]};         // shift right: new bit enters at the MSB
      2'b10:   q <= {q[W-2:0], sin_l};         // shift left: new bit enters at the LSB
      2'b11:   q <= d;                         // parallel load
    endcase

    Tip

    Use unique case so the tool knows all four modes are covered, and so simulation warns if mode ever has an unexpected value. The 00 hold branch is explicit, which also avoids relying on an implicit hold.

    A four-cycle trace

    Start from q = 1001_0110 (W = 8) and apply one mode per edge. Each row is the value after that edge.

    Edge

    mode

    Serial or parallel input

    q after the edge

    1

    00 hold

    —

    1001_0110

    2

    10 shift left

    sin_l = 1

    0010_1101

    3

    01 shift right

    sin_r = 0

    0001_0110

    4

    11 load

    d = 1010_0101

    1010_0101

    At edge 2 the top bit 1 falls off the left end and sin_l enters at bit 0. At edge 3 bit 0 falls off the right end and sin_r enters at bit 7. A load ignores the old value completely.

    Where you meet it

    The shift-add multiplier uses exactly two of these modes: it loads its operands once, then shifts the multiplier right one bit per step so the bit under test is always bit 0.

    • Bidirectional shifters in arithmetic units (shift-and-add multiply, shift-and-subtract divide).

    • Scan registers and test logic.

    • Small serializers where one block must both send and receive.

    Common mistakes

    Common pitfall

    Do not confuse this multiplexed-flop design with a barrel shifter. A universal shift register shifts by one position per clock; a barrel shifter shifts by any amount in a single cycle using log₂ N mux stages.

    Check yourself Starting from 8'b1001_0110, what do you get after one shift left with sin_l = 1, and after one shift right with sin_r = 0 applied to the *original* value?

    Shift left with sin_l = 1: 0010_1101. Shift right with sin_r = 0: 0100_1011.

    Testbench

    The test compares the register with an arithmetic reference over 1000 random mode trials. Each failure identifies the operation, previous reference value, inputs and expected/actual output, and any failure ends with $fatal. It sets 1 ns time units and 1 ps precision, drives inputs on falling edges, and checks updated Q 1 ns after each rising edge. The module requires W >= 2 (with W = 1 the selects become the reversed q[0:1] and the out of range q[-1:0], which are illegal); an elaboration-time guard reports a clear error, though some tools may still diagnose the invalid select.

    univ_shift.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    module univ_shift #(parameter int W = 8) (   // W >= 2
      input  logic         clk, rst_n,
      input  logic [1:0]   mode,
      input  logic         sin_l, sin_r,
      input  logic [W-1:0] d,
      output logic [W-1:0] q
    );
      if (W < 2) begin : g_w_check
        $error("univ_shift: W must be at least 2");
      end
      always_ff @(posedge clk or negedge rst_n)
        if (!rst_n) q <= '0;
        else begin
          unique case (mode)
            2'b00:   q <= q;
            2'b01:   q <= {sin_r, q[W-1:1]};       // shift right: new bit enters at the MSB
            2'b10:   q <= {q[W-2:0], sin_l};       // shift left: new bit enters at the LSB
            2'b11:   q <= d;
          endcase
        end
    endmodule
    

    Remember

    • Each flop picks its own output, a neighbour or the parallel input.

    • Make the hold mode explicit, and use unique case so all four modes are covered.

    • It shifts one position per clock; a barrel shifter shifts any amount in one cycle.

    Keep going

    • Practice: Shift register with parameterised depth and parallel load

    • Interview: run a mock interview on this topic

    Related topics

    • Barrel shifter

    Previous

    74 / 350

    Next: LFSR for PRBS Generation

    Up next

    Up nextLFSR for PRBS Generation

    Sign in to save progress

    Practice this lessonReport an error