---
title: "Memory Elements: Latches, Flip-Flops, and Clocking"
module: Digital Logic
moduleNumber: 3
lessonNumber: 4
order: 304
summary: >
  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.
topics: [Digital Logic]
sources:
  - book: Bryant & O'Hallaron
    ref: "CS:APP — §4.2 Logic Design and the Hardware Control Language"
  - book: Bistriceanu
    ref: "Computer Architecture Notes — §2 Basic Organization of a Computer"
---

Every block in the [previous lesson](/computer-architecture/digital-logic/multiplexers-decoders-and-the-alu)
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 $0$ feeding output $1$ feeding back $0$, 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.

$$
% caption: An SR latch from two cross-coupled NOR gates. S=1 forces Q to 1 (set);
% caption: R=1 forces Q to 0 (reset); S=R=0 holds the stored bit. S=R=1 is
% caption: disallowed. Q and Qbar are complementary.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  g/.style={draw, fill=acc!8, minimum width=14mm, minimum height=11mm,
            inner sep=1pt}]
  \definecolor{acc}{HTML}{2348F2}
  \node[g] (n1) at (0,1.2) {NOR};
  \node[g] (n2) at (0,-1.2) {NOR};
  % R into the top NOR (whose output is Q), S into the bottom (output Qbar)
  \draw (-2.6,1.5) node[anchor=east] {$R$} -- (-0.7,1.5);
  \draw (-2.6,-1.5) node[anchor=east] {$S$} -- (-0.7,-1.5);
  % outputs
  \draw (n1.east) -- (2.0,1.2) node[anchor=west,text=acc] {$Q$};
  \draw (n2.east) -- (2.0,-1.2) node[anchor=west,text=acc] {$\overline{Q}$};
  % cross-coupling: Q feeds bottom NOR, Qbar feeds top NOR (routed around)
  \draw (1.3,1.2) -- (1.3,0.2) -- (-1.6,0.2) -- (-1.6,-0.9) -- (-0.7,-0.9);
  \draw (1.3,-1.2) -- (1.3,-0.2) -- (-1.3,-0.2) -- (-1.3,0.9) -- (-0.7,0.9);
  \fill (1.3,1.2) circle (1.1pt); \fill (1.3,-1.2) circle (1.1pt);
\end{tikzpicture}
$$

Walk the four input cases. With $S = 1, R = 0$: the bottom NOR sees the $1$ on
$S$ and outputs $0$, so $\overline{Q} = 0$; the top NOR then sees two $0$s
($R = 0$ and $\overline{Q} = 0$) and outputs $1$. $Q = 1$: the latch is **set**,
and the loop holds that state even after $S$ drops back to $0$. With
$S = 0, R = 1$ the mirror argument runs through the top gate and $Q$ becomes $0$
(reset). With $S = R = 0$: each NOR just passes the loop's current state, so the
latch **holds** whatever it last stored: this is the memory. The fourth case
$S = R = 1$ is **disallowed**: it drives both outputs to $0$, violating the
$Q / \overline{Q}$ 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 $Q^{+}$ as a function of the inputs and the
_current_ state $Q$ — not the plain truth table a combinational gate has:

| $S$ | $R$ | $Q$ | $Q^{+}$ | action |
| --- | --- | --- | --- | --- |
| $0$ | $0$ | $0$ | $0$ | hold |
| $0$ | $0$ | $1$ | $1$ | hold |
| $0$ | $1$ | $\phantom{0}\times$ | $0$ | reset |
| $1$ | $0$ | $\phantom{0}\times$ | $1$ | set |
| $1$ | $1$ | $\phantom{0}\times$ | — | disallowed |

The two hold rows are the whole point: with $S = R = 0$ the next state equals the
current one, which is memory written as a table. Set and reset override the stored
value regardless of $Q$ (hence the $\times$), and the last row is the forbidden
input. This dependence on $Q$ — a variable that is also an output — is the formal
signature of **sequential** logic, the very thing the acyclic rule of the
[previous lesson](/computer-architecture/digital-logic/multiplexers-decoders-and-the-alu)
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 $D$ giving the bit to store, and an
**enable** input $C$ saying when to store it. The **D latch** wraps the SR latch
with a little logic so that, while $C = 1$, the output $Q$ simply **follows** $D$,
and while $C = 0$, the latch **holds**. Internally $D$ and $\overline{D}$ are gated
by $C$ into the latch's set and reset, so the illegal combination can never arise.

$$
% caption: A D latch. While the enable C is high the output Q follows the data D
% caption: (transparent); while C is low the latch holds its last value. One data
% caption: input, one enable — no illegal combination.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  g/.style={draw, fill=acc!8, minimum width=22mm, minimum height=20mm,
            inner sep=2pt, align=center}]
  \definecolor{acc}{HTML}{2348F2}
  \node[g] (d) at (0,0) {D latc\/h};
  \draw (-2.6,0.5) node[anchor=east] {$D$} -- (d.west |- 0,0.5);
  \draw (-2.6,-0.5) node[anchor=east] {$C$ (enable)} -- (d.west |- 0,-0.5);
  \draw (d.east |- 0,0.5) -- ++(1.8,0) node[anchor=west,text=acc] {$Q$};
  \draw (d.east |- 0,-0.5) -- ++(1.8,0) node[anchor=west] {$\overline{Q}$};
  \node[anchor=west, align=left] at (3.6,0)
    {\footnotesize $C = 1$: $Q$ trac\/ks $D$\\$C = 0$: $Q$ held};
\end{tikzpicture}
$$

The D latch is **level-sensitive** (or **transparent**): it is a window that is
open the whole time $C$ 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
$Q$ changes only at, say, the **rising** edge of the clock, taking on whatever $D$
was at that edge, and is otherwise frozen.

$$
% caption: Inside an edge-triggered D flip-flop: a master and a slave D latch on
% caption: opposite clock phases. While clk = 0 the master tracks D and the slave
% caption: holds; at the rising edge the master freezes and the slave opens, passing
% caption: the frozen value to Q. At no instant are both latches transparent.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  l/.style={draw, fill=acc!8, minimum width=18mm, minimum height=14mm,
            inner sep=2pt, align=center}]
  \definecolor{acc}{HTML}{2348F2}
  \node[l] (m) at (0,0) {master\\D latc\/h};
  \node[l] (s) at (3.4,0) {slave\\D latc\/h};
  \node[anchor=south] at (0,0.85) {open while clk $=0$};
  \node[anchor=south] at (3.4,0.85) {open while clk $=1$};
  \draw (-2.4,0.25) node[anchor=east] {$D$} -- (-0.9,0.25);
  \draw (0.9,0.25) -- (2.5,0.25);
  \draw (4.3,0.25) -- (5.5,0.25) node[anchor=west, text=acc] {$Q$};
  % clock trunk below, inverted into the master's enable
  \draw (-2.4,-1.7) node[anchor=east] {clk} -- (3.4,-1.7);
  \draw (3.4,-1.7) -- (3.4,-0.7);
  \draw (0,-1.7) -- (0,-1.34);
  \draw (0,-1.22) circle (0.12);
  \draw (0,-1.1) -- (0,-0.7);
  \fill (0,-1.7) circle (1.1pt);
\end{tikzpicture}
$$

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

$$
% caption: An edge-triggered D flip-flop. Q takes the value of D only at the rising
% caption: clock edge (marked by the small triangle on the clock input) and holds it
% caption: for the whole cycle. The wedge on the clock input denotes edge-triggering.
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  ff/.style={draw, fill=acc!8, minimum width=20mm, minimum height=22mm,
             inner sep=2pt}]
  \definecolor{acc}{HTML}{2348F2}
  \node[ff] (q) at (0,0) {D-FF};
  % D input
  \draw (-2.6,0.6) node[anchor=east] {$D$} -- (q.west |- 0,0.6);
  % clock input with edge-triangle marker
  \draw (-2.6,-0.6) node[anchor=east] {clk} -- (q.west |- 0,-0.6);
  \draw (q.west |- 0,-0.45) -- ++(0.35,0.15) -- (q.west |- 0,-0.75); % wedge
  % outputs
  \draw (q.east |- 0,0.6) -- ++(1.8,0) node[anchor=west,text=acc] {$Q$};
  \draw (q.east |- 0,-0.6) -- ++(1.8,0) node[anchor=west] {$\overline{Q}$};
  \node[anchor=west] at (3.4,0) {samples $D$ at the rising edge};
\end{tikzpicture}
$$

> **Definition (Edge-triggered D flip-flop).** A one-bit storage element whose
> output $Q$ copies the data input $D$ **only at the active clock edge** and holds
> that value for the remainder of the clock cycle. Unlike the level-sensitive
> latch, it is never transparent — $D$ at any other time has no effect.

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

$$
% caption: Level-sensitive versus edge-triggered on the same inputs. While clk is
% caption: high the latch is transparent: Q follows every change of D. The
% caption: flip-flop copies D only at each rising edge (dashed) and ignores
% caption: everything in between.
\begin{tikzpicture}[font=\footnotesize,>=stealth]
  \definecolor{acc}{HTML}{2348F2}
  \node[anchor=east] at (-0.4,3.5) {clk};
  \draw (0,3.8) -- (1,3.8) -- (1,3.2) -- (2,3.2) -- (2,3.8) -- (3,3.8)
        -- (3,3.2) -- (4,3.2) -- (4,3.8) -- (5,3.8) -- (5,3.2) -- (6,3.2);
  \node[anchor=east] at (-0.4,2.3) {$D$};
  \draw (0,2.0) -- (0.6,2.0) -- (0.6,2.6) -- (1.4,2.6) -- (1.4,2.0)
        -- (1.8,2.0) -- (1.8,2.6) -- (2.9,2.6) -- (2.9,2.0) -- (4.3,2.0)
        -- (4.3,2.6) -- (6,2.6);
  \node[anchor=east] at (-0.4,1.1) {$Q$ (latc\/h)};
  \draw (0,0.8) -- (0.6,0.8) -- (0.6,1.4) -- (2.9,1.4) -- (2.9,0.8)
        -- (4.3,0.8) -- (4.3,1.4) -- (6,1.4);
  \node[anchor=east, text=acc] at (-0.4,-0.1) {$Q$ (FF)};
  \draw[acc, thick] (0,-0.4) -- (2,-0.4) -- (2,0.2) -- (4,0.2) -- (4,-0.4)
        -- (6,-0.4);
  \draw[dashed, black] (2,3.2) -- (2,-0.4);
  \draw[dashed, black] (4,3.2) -- (4,-0.4);
\end{tikzpicture}
$$

Compare the two output rows. Whenever $D$ 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
$k$" 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 $0$ and $1$ 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.

$$
% caption: A clock-edge timing diagram. The flip-flop samples D at each rising clock
% caption: edge (dashed lines) and Q jumps to that value, holding it until the next
% caption: edge. D's wiggles between edges are ignored.
\begin{tikzpicture}[font=\footnotesize,>=stealth]
  \definecolor{acc}{HTML}{2348F2}
  % clock waveform
  \node[anchor=east] at (-0.3,2.3) {clk};
  \draw (0,2.0) -- (0,2.6) -- (1,2.6) -- (1,2.0) -- (2,2.0) -- (2,2.6)
        -- (3,2.6) -- (3,2.0) -- (4,2.0) -- (4,2.6) -- (5,2.6) -- (5,2.0)
        -- (6,2.0);
  % rising edges at x=0,2,4 ; mark with dashed verticals
  \foreach \x in {0,2,4} \draw[dashed, black] (\x,2.0) -- (\x,-0.3);
  % D waveform (changes arbitrarily)
  \node[anchor=east] at (-0.3,1.1) {$D$};
  \draw (0,0.8) -- (0.6,0.8) -- (0.6,1.4) -- (2,1.4) -- (2,0.8)
        -- (3.4,0.8) -- (3.4,1.4) -- (6,1.4);
  % Q waveform: jumps only at rising edges to the value D had at that edge
  % at x=0 D=0 -> Q=0 ; at x=2 D=1 -> Q=1 ; at x=4 D=0 -> Q=0
  \node[anchor=east, text=acc] at (-0.3,0.1) {$Q$};
  \draw[acc, thick] (0,-0.2) -- (2,-0.2) -- (2,0.4) -- (4,0.4) -- (4,-0.2)
        -- (6,-0.2);
\end{tikzpicture}
$$

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**.

> **Definition (Setup and hold).** The **setup time** is the interval before the
> clock edge during which a flip-flop's data input must already be stable; the
> **hold time** is the interval after the edge during which it must remain stable.
> Violating either makes the captured value unpredictable.

$$
% caption: The setup/hold window (shaded). D must be stable from t_su before the
% caption: rising edge to t_h after it. Both of D's transitions here land outside
% caption: the window, so the flip-flop cleanly samples the stable 1 between them.
\begin{tikzpicture}[font=\footnotesize,>=stealth]
  \definecolor{acc}{HTML}{2348F2}
  \fill[acc!8] (2.2,0.7) rectangle (3.6,1.7);
  \node[anchor=east] at (-0.3,2.6) {clk};
  \draw (0,2.3) -- (3.0,2.3) -- (3.0,2.9) -- (6.2,2.9);
  \node[anchor=east] at (-0.3,1.2) {$D$};
  \draw (0,0.9) -- (1.4,0.9) -- (1.4,1.5) -- (4.6,1.5) -- (4.6,0.9) -- (6.2,0.9);
  \draw[dashed, black] (3.0,2.3) -- (3.0,0.15);
  \draw[dashed, black] (2.2,0.7) -- (2.2,0.15);
  \draw[dashed, black] (3.6,0.7) -- (3.6,0.15);
  \draw[<->] (2.2,0.45) -- (3.0,0.45);
  \draw[<->] (3.0,0.45) -- (3.6,0.45);
  \node[anchor=north] at (2.6,0.25) {$t_{su}$};
  \node[anchor=north] at (3.4,0.25) {$t_h$};
\end{tikzpicture}
$$

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 $T$ 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, $T \ge 20 + 800 + 40 = 860$ 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:

$$
T \;\ge\; t_{cq} + t_{pd}^{\max} + t_{su} - t_{skew},
$$

where $t_{cq}$ is clock-to-output, $t_{pd}^{\max}$ the longest combinational path,
and $t_{skew}$ the capture clock's lateness (which _helps_ setup — a late capture
edge gives the data more time). Plug in $t_{cq} = 20$, $t_{pd}^{\max} = 800$,
$t_{su} = 40$, and a $30$ ps late capture edge: $T \ge 20 + 800 + 40 - 30 = 830$
ps. Skew bought $30$ 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?):

$$
t_{cq} + t_{pd}^{\min} \;\ge\; t_h + t_{skew}.
$$

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 $t_{pd}^{\min} = 15$ ps, $t_{cq} = 20$, $t_h = 25$, and the same $30$ ps late
edge: is $20 + 15 = 35 \ge 25 + 30 = 55$? **No** — the hold check fails by 20 ps,
and the design is broken _at any clock frequency_, because hold has nothing to do
with $T$. 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 $0$ nor $1$, 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 $n$ flip-flops sharing a clock

A single flip-flop stores one bit. An $n$-bit **register** is just $n$ flip-flops
side by side, **all driven by the same clock**, storing an $n$-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.

$$
% caption: An n-bit register is n D flip-flops sharing one clock. On the rising edge
% caption: all bits load in parallel from D[n-1..0]; between edges the word is held
% caption: and presented on Q[n-1..0].
\begin{tikzpicture}[font=\footnotesize,>=stealth,
  ff/.style={draw, fill=acc!8, minimum width=13mm, minimum height=13mm,
             inner sep=1pt}]
  \definecolor{acc}{HTML}{2348F2}
  % f\/lip-f\/lops with D in from the top, Q out the bottom
  \foreach \i/\x/\dlab/\qlab in {0/0/{$D_0$}/{$Q_0$}, 1/2.2/{$D_1$}/{$Q_1$},
        2/4.4/{$D_2$}/{$Q_2$}, 3/6.6/{$D_{n\text{-}1}$}/{$Q_{n\text{-}1}$}}{
    \node[ff] (f\i) at (\x,0) {DFF};
    \draw (\x,1.7) node[anchor=south] {\dlab} -- (f\i.north);
    \draw (f\i.south) -- (\x,-1.7) node[anchor=north,text=acc] {\qlab};
  }
  % shared clock: a single horizontal trunk above the f\/lip-f\/lops, dropping
  % beside each FF and entering its west edge. No clock wire crosses a Q drop.
  \draw (-1.9,2.7) node[anchor=east] {clk} -- (5.65,2.7);
  \foreach \i/\x in {0/0, 1/2.2, 2/4.4, 3/6.6}{
    \draw (\x-0.95,2.7) -- (\x-0.95,0.0) -- (\x-0.65,0.0);
    % small edge-trigger wedge at the clock input
    \draw (\x-0.65,0.15) -- (\x-0.37,0.0) -- (\x-0.65,-0.15);
  }
  \foreach \x in {0, 2.2, 4.4}{
    \fill (\x-0.95,2.7) circle (1.0pt);
  }
\end{tikzpicture}
$$

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**, $\text{MTBF} \propto e^{t/\tau} / (f_{clk} f_{data})$, where
$t$ is the resolution time allowed, $\tau$ a device time constant, and the $f$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 $t$ 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.

> **Takeaway.** Feedback turns gates into memory: cross-coupled NORs make an SR
> latch, gating it with a data and enable input makes the level-sensitive D latch,
> and a master/slave pair makes the **edge-triggered D flip-flop** that samples $D$
> only at the clock edge. The synchronous discipline clocks all state from one
> clock, with the period covering clock-to-output, the critical path, and setup,
> minus whatever skew steals, and asynchronous inputs synchronized against
> metastability. An $n$-bit register is $n$ flip-flops sharing that clock.

The next lesson assembles many registers into a [register file](/computer-architecture/digital-logic/register-files-and-random-access-memory)
and contrasts it with the SRAM and DRAM cells that make up main memory.
