Skip to main content

Registers & Shift Registers

A single D flip-flop stores one bit. Nearly everything a real digital system needs to remember — a byte, a 32-bit instruction, an address — is wider than that. This page covers how flip-flops combine into multi-bit storage, and the specific sub-family, shift registers, that move data sideways as well as store it.

Parallel registers​

A register is simply a bank of D flip-flops sharing a common clock, one flip-flop per bit, all updating together:

D[3:0] feeds a bank of four flip-flops (FF3, FF2, FF1, FF0) sharing one CLK, producing Q[3:0]

On every active clock edge, the entire D[3:0] value is captured into Q[3:0] simultaneously — this is the basic mechanism behind every pipeline stage, every CPU register file entry, and every intermediate value held between combinational stages in a synchronous design. Two refinements are almost universal in practice:

  • Enable: a register that updates on every clock edge is rarely useful on its own — real registers add an EN input that, when low, makes the register hold its current value regardless of D, by feeding D_effective = EN ? D : Q back into each flip-flop (a MUX in front of each D input, choosing between new data and the flip-flop's own current output).
  • Reset: an initialization mechanism that forces the register to a known value (usually all-0) independent of D and CLK — either synchronous (takes effect only on the next clock edge, keeping all state changes tied to the clock) or asynchronous (takes effect immediately, useful for guaranteeing a known power-up state but riskier if it can assert briefly at an inconvenient moment relative to the clock).

Shift registers​

A shift register connects flip-flops in a chain instead of in parallel — each flip-flop's Q output feeds directly into the next flip-flop's D input. Every clock edge, data shifts one position down the chain rather than each bit staying put:

SerialIn feeds FF0, which feeds FF1, then FF2, then FF3, producing SerialOut; all four flip-flops share one CLK

Shift registers are classified by how data gets in and out, which gives four standard configurations:

  • SISO (Serial-In, Serial-Out) — data enters one bit per clock at SerialIn and exits one bit per clock at SerialOut, exactly the chain above. Used as a pure delay line — an n-stage SISO register delays a serial stream by exactly n clock cycles.
  • SIPO (Serial-In, Parallel-Out) — same serial input, but every flip-flop's Q is also broken out as an output, so after n clock cycles an n-bit value that arrived one bit at a time is now available all at once, in parallel. This is the standard serial-to-parallel converter — exactly what a UART receiver uses to reassemble a byte from a serial bit stream.
  • PISO (Parallel-In, Serial-Out) — the reverse: an n-bit value is loaded into all flip-flops simultaneously (via a parallel-load path that bypasses the normal shift-input MUXes, using the same enable/MUX trick as the parallel register above), then shifted out one bit per clock. This is the standard parallel-to-serial converter — how a UART transmitter turns a byte into a serial bit stream, one bit per clock, for transmission.
  • PIPO (Parallel-In, Parallel-Out) — data loads in parallel and reads out in parallel; the "shift register" here doesn't actually need to shift for its primary function, but the same flip-flop chain can typically still shift as a secondary mode. This is functionally just the parallel register from the section above, framed as a degenerate case of the shift-register family.

The universal shift register​

A universal shift register combines all four modes into a single reconfigurable block, selecting its behavior with a mode-select input feeding a MUX in front of every flip-flop's D input:

Mode | Operation
00 | Hold (no change)
01 | Shift right (toward SerialOut)
10 | Shift left (toward SerialIn, reversed direction)
11 | Parallel load

Each flip-flop's actual D input is a 4-to-1 MUX output, selecting between its own current Q (hold), the previous stage's Q (shift right), the next stage's Q (shift left), or the corresponding parallel-input bit (load) — directly reusing the MUX-as-selector idea from Multiplexers, Decoders & Comparators, just with flip-flop outputs and a parallel data bus as the MUX's data inputs instead of plain combinational signals. The 74194 family of ICs is the classic real-world example of exactly this circuit, and the same select-per-flip-flop structure is the template for any register file or pipeline stage in a real processor that needs to conditionally hold, shift, or reload its contents based on control logic elsewhere in the design.

What's next​

Registers hold and move data, but they don't produce new values on their own — the next page covers counters, which use flip-flops together with feedback logic to generate a repeating sequence of values entirely on their own, driven by nothing but the clock.