VHDL · Chapter 7.3 · Sequential Logic Design
The D Flip-Flop
Everything stateful in a synchronous design is made of one element, the D flip-flop. On each clock edge it samples the value on its D input and presents it on Q, holding that value until the next edge. That is the whole behaviour, capture on the edge and hold in between, and from it you build registers, counters, shift registers, pipelines, and state machines. This lesson gives the canonical VHDL description of a flip-flop, introduces the setup and hold timing window the data must respect around the clock edge, explains why Q lags D by one clock, and frames the flip-flop as the atom every later sequential structure is composed from.
Foundation14 min readVHDLD Flip-FlopRegisterSetup HoldClockedRTL
1. Engineering intuition — sample and hold, once per clock
A D flip-flop is a one-bit memory with a strict rule: at the clock edge, look at D and copy it to Q; the rest of the time, ignore D and hold Q. It is a "sample and hold" that fires once per clock. Because it captures only at the edge, the value on Q is stable between edges — which is what makes synchronous design predictable: every flip-flop updates together at the edge, then the combinational logic between them settles before the next edge. The flip-flop is the smallest unit of "remembering" in hardware.
2. Formal explanation — the canonical description
library ieee; use ieee.std_logic_1164.all;
-- The canonical D flip-flop: capture d on the rising edge, hold otherwise.
dff : process (clk)
begin
if rising_edge(clk) then
q <= d; -- sample d at the edge; q holds between edges
end if;
end process;
-- With a synchronous reset to a known value (reset detail in Module 8).
dff_rst : process (clk)
begin
if rising_edge(clk) then
if rst = '1' then q <= '0'; -- defined start
else q <= d;
end if;
end if;
end process;A D flip-flop is exactly a single signal assigned under rising_edge(clk). The edge guard (lesson 7.2)
makes it edge-triggered; with no else, q simply holds when not assigned (a register's natural
behaviour). Adding a reset gives it a defined starting value. There is nothing more to a flip-flop —
every register is copies of this.
3. Production RTL — the flip-flop in context
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
-- A pipeline register: each stage is D flip-flops capturing the previous stage.
stage : process (clk)
begin
if rising_edge(clk) then
s1 <= din; -- stage 1 flops
s2 <= s1; -- stage 2 flops (captures the OLD s1 — one clock behind)
end if;
end process;What hardware does this become? Two ranks of D flip-flops in series — a 2-stage pipeline. Because
each <= captures the value present at the edge, s2 gets the previous s1, so data advances one
stage per clock. This "each <= is a flip-flop capturing the old value" behaviour (the scheduled-update
model from Module 5) is exactly how shift registers and pipelines work.
4. Hardware interpretation — capture, hold, and the timing window
5. Simulation interpretation — Q lags D by one clock
Q captures D at each rising edge and holds — Q is D delayed by one clock
8 cycles6. Debugging example — no flip-flop, or a one-cycle surprise
Expected: a register that stores d. Observed: either no storage (the value does not hold), or
a result that is unexpectedly one cycle late or early. Root cause: for no storage, the
rising_edge(clk) guard was missing (combinational, not a flip-flop). For the cycle surprise, a chain
of flip-flops captured old values (the scheduled-update rule), so data was delayed one stage more (or
less) than intended. Fix: ensure state is under rising_edge(clk); for a chain, count the flops —
each <= adds exactly one clock of latency. Engineering takeaway: a flip-flop only exists under an
edge guard, and each flip-flop in a path adds exactly one clock of delay — count them.
-- Each registered stage adds ONE clock of latency. Two stages → 2-clock delay.
process (clk) begin
if rising_edge(clk) then
a_d <= a; -- 1 clock
a_dd <= a_d; -- 2 clocks (a delayed by two)
end if;
end process;7. Common mistakes & what to watch for
- Missing the edge guard. Without
rising_edge(clk), there is no flip-flop — just combinational logic or a latch. - Miscounting pipeline latency. Each registered stage is one clock; a chain of N flip-flops delays by N clocks (the scheduled-update rule).
- Changing D in the setup/hold window. In real hardware this risks metastability; synchronous design and synchronisers (later) manage it.
- Expecting Q to follow D immediately. Q updates only at the edge and lags by one clock.
- Defaulting Q combinationally. A flip-flop holds when not assigned; do not give it a per-cycle combinational default.
8. Engineering insight & continuity
The D flip-flop is the irreducible unit of synchronous hardware: sample on the edge, hold between edges, one clock of latency. Everything stateful is built from it, and its setup/hold window is the foundation of timing closure — the entire job of meeting timing is guaranteeing each flip-flop's data is stable around the clock edge. Master the single-bit flip-flop and the rest of the module is composition: the next lesson, Registers and Register Banks, puts D flip-flops in parallel to store words, then Clock Enables, Counters, and Shift Registers combine and feed them to build the working elements of every datapath and controller.