Digital Logic/Memory Elements: Latches, Flip-Flops, and Clocking

Lesson 4.42,375 words

Memory Elements: Latches, Flip-Flops, and Clocking

A combinational circuit holds no state; feeding a circuit's output back to its input creates memory. We build the SR latch from cross-coupled gates, the level-sensitive D latch, and the master/slave edge-triggered D flip-flop, then introduce the clock and the synchronous design discipline, the setup/hold timing window, clock skew, metastability, and the register as n flip-flops sharing one clock.

╌╌╌╌

Every block in the previous lesson was combinational: its output was a function of its current inputs, and the instant the inputs changed the output followed. Such a circuit cannot remember anything — and a computer is mostly memory. This lesson breaks the one rule that kept circuits combinational, the ban on feedback, and discovers that feedback is what stores a bit. From a single cross-coupled pair we build up to the edge-triggered flip-flop and the clocked register that holds a processor's state.

Feedback creates memory

Combinational logic forbade cycles because a path from a gate's output back to its own input creates a loop with no fixed answer — or rather, with a remembered answer. Connect two inverters in a ring and the loop is bistable: it has two stable states, output feeding output feeding back , and the other way around. Left alone it stays in whichever state it is in. That is one bit of storage. The trouble is there is no way to set it; the useful versions add inputs that can flip the loop on demand.

The SR latch

The SR latch is the simplest controllable memory: two cross-coupled NOR gates with inputs S (set) and R (reset). Each gate's output feeds the other's input, closing the loop.

An SR latch from two cross-coupled NOR gates. S=1 forces Q to 1 (set); R=1 forces Q to 0 (reset); S=R=0 holds the stored bit. S=R=1 is disallowed. Q and Qbar are complementary.

Walk the four input cases. With : the bottom NOR sees the on and outputs , so ; the top NOR then sees two s ( and ) and outputs . : the latch is set, and the loop holds that state even after drops back to . With the mirror argument runs through the top gate and becomes (reset). With : each NOR just passes the loop's current state, so the latch holds whatever it last stored: this is the memory. The fourth case is disallowed: it drives both outputs to , violating the complement, and worse, when both inputs then fall the loop's next state depends on which gate happens to win the race.

Because the output depends on the stored state, an SR latch has a characteristic table — next state as a function of the inputs and the current state — not the plain truth table a combinational gate has:

action
hold
hold
reset
set
disallowed

The two hold rows are the whole point: with the next state equals the current one, which is memory written as a table. Set and reset override the stored value regardless of (hence the ), and the last row is the forbidden input. This dependence on — a variable that is also an output — is the formal signature of sequential logic, the very thing the acyclic rule of the previous lesson ruled out. The SR latch stores a bit but with an awkward two-wire, illegal-combination interface; the D latch fixes that.

The D latch: level-sensitive storage

We want a cleaner interface: one data input giving the bit to store, and an enable input saying when to store it. The D latch wraps the SR latch with a little logic so that, while , the output simply follows , and while , the latch holds. Internally and are gated by into the latch's set and reset, so the illegal combination can never arise.

A D latch. While the enable C is high the output Q follows the data D (transparent); while C is low the latch holds its last value. One data input, one enable — no illegal combination.

The D latch is level-sensitive (or transparent): it is a window that is open the whole time is high. That transparency is a problem in a feedback system. If a latch's output feeds combinational logic that feeds back to the same latch's input while the window is open, the value can race around the loop more than once in a single enable pulse. We want to capture a value at one instant, not during a whole interval. That is the flip-flop.

The edge-triggered D flip-flop

A D flip-flop samples its data input only at the edge of the clock — the instant the clock transitions — and holds that value for the entire cycle until the next edge. It is built from two D latches in series (a master and a slave) driven by opposite clock phases, so at most one is ever transparent: the value passes through on one phase and is captured on the other. The net effect is that changes only at, say, the rising edge of the clock, taking on whatever was at that edge, and is otherwise frozen.

Inside an edge-triggered D flip-flop: a master and a slave D latch on opposite clock phases. While clk = 0 the master tracks D and the slave holds; at the rising edge the master freezes and the slave opens, passing the frozen value to Q. At no instant are both latches transparent.

Follow one cycle around. While the clock is low the master is transparent (its output tracks every change of ) but the slave is opaque, so none of that reaches . When the clock rises, the two swap roles in the same instant: the master goes opaque, freezing whatever was at that moment, and the slave goes transparent, passing the frozen value out. Any change of after the edge finds the master closed and goes nowhere. The window of the level-sensitive latch has been squeezed to a point.

An edge-triggered D flip-flop. Q takes the value of D only at the rising clock edge (marked by the small triangle on the clock input) and holds it for the whole cycle. The wedge on the clock input denotes edge-triggering.

The difference is easiest to see on the same waveforms. Feed one D latch (enable clk) and one D flip-flop the same data:

Level-sensitive versus edge-triggered on the same inputs. While clk is high the latch is transparent: Q follows every change of D. The flip-flop copies D only at each rising edge (dashed) and ignores everything in between.

Compare the two output rows. Whenever changes during an open window (its fall in the second high phase, its rise in the third) the latch passes the change straight through, mid-cycle; the flip-flop holds the single value it sampled at the last edge until the next one. The latch leaks every wiggle of a busy input through to its output; the flip-flop reduces a whole cycle of activity to one decision per edge. That one-decision-per-edge behavior is what makes machine state countable: the register's value in cycle is a well-defined phrase for a flip-flop and a blurry one for a transparent latch.

The clock and the synchronous discipline

A clock is a square wave alternating and at a fixed frequency; its rising edges mark when every flip-flop updates. The synchronous design discipline organizes a whole machine around one clock: all state is held in edge-triggered flip-flops driven by the same clock, and between edges, combinational logic computes the next state from the current state. On each rising edge, every flip-flop simultaneously latches its next-state input, state advances by one step, and the cycle repeats.

A clock-edge timing diagram. The flip-flop samples D at each rising clock edge (dashed lines) and Q jumps to that value, holding it until the next edge. D's wiggles between edges are ignored.

The discipline buys a clean mental model: think one cycle at a time, the state now and the combinational logic deciding the state next. It also imposes a timing constraint. The data at a flip-flop's input must be stable for a short window around the clock edge: it must arrive at least a setup time before the edge and stay at least a hold time after it. If the combinational logic feeding the flip-flop is too slow to settle within one clock period minus the setup time, the flip-flop samples a half-formed value. This is why the clock period (and therefore the clock frequency) is bounded by the slowest combinational path between flip-flops, the critical path.

The setup/hold window (shaded). D must be stable from t_su before the rising edge to t_h after it. Both of D's transitions here land outside the window, so the flip-flop cleanly samples the stable 1 between them.

The window also completes the clock-period arithmetic the critical path began. For the flip-flop to capture good data every cycle, the clock period must cover everything between one edge and the next input's arrival: the flip-flop's own clock-to-output delay, then the critical path of the combinational logic between registers, then the setup time. With a 20 ps clock-to-output, an 800 ps critical path, and a 40 ps setup, ps: a hair under 1.2 GHz, and every extra gate on the worst path shaves that headroom.

Work the two timing checks a static timing tool actually runs, on a launch flip-flop feeding a capture flip-flop through combinational logic. The setup check (can the data arrive in time for the next edge?) is the slow-path constraint:

where is clock-to-output, the longest combinational path, and the capture clock's lateness (which helps setup — a late capture edge gives the data more time). Plug in , , , and a ps late capture edge: ps. Skew bought ps of margin here.

But the same skew endangers the hold check (does the fast path hold its value long enough at the current edge?):

The new data launched at this edge must not race through the shortest path and reach the capture flip-flop before its (now late) edge plus hold time. With a fast path ps, , , and the same ps late edge: is ? No — the hold check fails by 20 ps, and the design is broken at any clock frequency, because hold has nothing to do with . Fixing it means padding the fast path with buffer delay or reducing skew, not slowing the clock. This asymmetry — skew helps setup on the slow path but hurts hold on the fast path — is why clock trees are engineered so obsessively, and why just clock it slower cannot rescue a hold violation.

Clock skew and metastability

One clock is a useful fiction. The clock is itself a signal on wires, and it reaches different flip-flops at slightly different times; the difference between arrival times at two communicating flip-flops is clock skew. Skew eats the timing budget from both ends. If the receiving flip-flop's clock arrives early, the effective period shrinks and a slow path that met setup on paper now misses it. If it arrives late, a fast path becomes the hazard: the sender's new value can race through thin logic and reach the receiver before its delayed edge plus hold time has passed, overwriting the value it was still trying to capture. Designers attack skew physically, distributing the clock through balanced trees so every leaf sees the edge within a few picoseconds, and guard the fast-path case with minimum-delay constraints; a synchronous design's single instant is really a window a few picoseconds wide that the clock network keeps narrow.

Setup and hold can also be violated by something no design discipline controls: an input from outside the clock domain — a keypress, a network signal, another chip on a different clock. Sample such a signal at just the wrong moment and the flip-flop's internal loop is knocked to the unstable balance point between its two stable states, where it can linger, output at neither nor , for an unbounded time before falling to one side arbitrarily. This is metastability. It cannot be prevented, only made improbable: the probability of remaining metastable decays exponentially with waiting time, so designers pass asynchronous inputs through a chain of two (or more) flip-flops — a synchronizer — giving the first stage a full cycle to resolve before the next stage samples it. The cost is a cycle of latency; the alternative is a corrupted bit propagating through the machine.

A register is flip-flops sharing a clock

A single flip-flop stores one bit. An -bit register is just flip-flops side by side, all driven by the same clock, storing an -bit word. On each rising edge the whole word updates at once from the register's data input; between edges it holds, presenting the stored word at its output.

An n-bit register is n D flip-flops sharing one clock. On the rising edge all bits load in parallel from D[n-1..0]; between edges the word is held and presented on Q[n-1..0].

This clocked register is the unit of processor state: the program counter, the condition-code register, and — many of them at once — the register file of the next lesson are all built from exactly this structure. Y86-64's pipeline registers between stages are nothing more than wide D flip-flops that snapshot the whole datapath on each clock edge.

Clocking a real chip

CS:APP presents one storage element (the edge-triggered D flip-flop) and one timing rule. The public design literature adds the parts that make a real chip's clocking work.

Clock distribution dominates power. A modern processor spends a large fraction of its energy just distributing the clock — the balanced tree mentioned above toggles every cycle across the whole die. Clock gating is the standard defense: insert an AND (with a latch to avoid glitches) so a block's flip-flops see clock edges only when their state can actually change, and idle blocks fall silent. At the extreme, whole regions are power-gated off. None of this changes the flip-flop; it changes when the flip-flop is allowed to see an edge, and it is why typical and peak power differ so much.

Metastability has a number. The claim that metastability decays exponentially is quantitative: the failure rate is governed by the mean time between failures, , where is the resolution time allowed, a device time constant, and the s the clock and asynchronous-event rates (Kleeman and Cantoni's analyses in the 1980s formalized this). A two-flip-flop synchronizer works because giving the first stage a full cycle makes large enough that the MTBF stretches to years; safety- critical crossings add a third stage. Getting clock-domain crossing right — never letting a multi-bit bus cross unsynchronized, using handshakes or Gray-coded FIFO pointers so at most one bit changes per edge — is a whole sub-discipline, and the Gray code of lesson 1 reappears in it.

Latches did not disappear. CS:APP prefers flip-flops for their clean one-decision-per-edge model, but high-performance designs still use level-sensitive latches deliberately. Time borrowing lets a slow combinational stage push its lateness past a transparent latch into the next stage's slack, something a hard flip-flop edge forbids; and pulsed latches shrink the storage overhead on the critical path. The FPGA world, meanwhile, does not build flip-flops from gates at all — each logic cell ships with a dedicated D flip-flop next to its lookup table, so the register is a fixed silicon resource the mapper assigns, not something synthesized from NORs. The cross-coupled-pair story of this lesson is the physics underneath all of them.

The next lesson assembles many registers into a register file and contrasts it with the SRAM and DRAM cells that make up main memory.

╌╌ END ╌╌