VHDL · Chapter 7.2 · Sequential Logic Design
Detecting the Clock Edge
A register exists because something happens on a clock edge, a transition rather than a level. In VHDL you express that with the rising-edge and falling-edge functions, which are true only at the instant the clock changes from 0 to 1 or from 1 to 0. That edge is precisely what makes synthesis infer a flip-flop instead of combinational logic or a latch. This lesson covers the edge-detection functions, why the rising-edge function is the modern form preferred over the older clock-event-and-equals-one style because it is metavalue-safe and states intent clearly, how to choose rising versus falling, and why a clocked process keys on exactly one edge of one clock. Getting this right is the foundation of every synchronous circuit you will design.
Foundation13 min readVHDLClock Edgerising_edgeFlip-FlopSynchronousRTL
1. Engineering intuition — capture on a transition, not a level
A flip-flop samples its input at the moment the clock transitions, then holds that value until the next transition. The key word is moment: it is the edge that matters, not whether the clock is high or low. A level-sensitive element (transparent while high) is a latch; an edge-sensitive element (captures at the transition) is a flip-flop. So detecting the clock edge — the 0-to-1 transition — is exactly what tells VHDL "build a flip-flop here," and it is the single ingredient that turns a process from combinational into sequential.
2. Formal explanation — rising_edge and why it is preferred
-- MODERN, preferred: a function from std_logic_1164, true only on the 0→1 transition.
if rising_edge(clk) then ... end if;
if falling_edge(clk) then ... end if; -- the 1→0 transition
-- OLDER form (still seen): clk changed AND its new value is '1'.
if clk'event and clk = '1' then ... end if; -- equivalent intent, but less saferising_edge(clk) is a function (from std_logic_1164) that returns true only for a genuine 0-to-1
transition of a std_logic clock. It is preferred over clk'event and clk = '1' because it is
metavalue-safe (it correctly ignores transitions involving 'U'/'X'/'Z', which the naive form
can misread) and it states intent plainly. Use rising_edge/falling_edge; reserve the
clk'event form for legacy code you are reading, not writing.
3. Production RTL — the edge makes the register
library ieee; use ieee.std_logic_1164.all;
-- The rising_edge guard is what infers a flip-flop for q.
ff : process (clk)
begin
if rising_edge(clk) then -- edge → register
q <= d;
end if;
end process;
-- Without the edge guard, the same assignment is combinational / a latch — NOT a register.
-- y <= d; -- combinational wire, no storageWhat hardware does this become? With the rising_edge(clk) guard, q is a flip-flop that captures
d on each rising edge. Remove the guard and there is no flip-flop — just a wire (or a latch if the
assignment is conditional and incomplete). The edge detection is the difference between a register and
no register.
4. Hardware interpretation — edge vs level
5. Simulation interpretation — capture only at the edge
rising_edge(clk): d is sampled only at the rising edges
8 cycles6. Debugging example — clk'event misread, or a level used
Expected: an edge-triggered register. Observed: a metavalue glitch at time zero produces a
spurious clock (with the clk'event form), or a latch appears (with a level test). Root cause:
clk'event and clk = '1' can react to transitions out of 'U'/'X' that are not real rising edges; a
plain clk = '1' level test is not an edge at all and infers a latch. Fix: use rising_edge(clk),
which is true only for a clean 0-to-1 transition. Engineering takeaway: for clocked logic always use
rising_edge/falling_edge — they are edge-correct and metavalue-safe, unlike level tests or the naive
event form.
-- RISKY: reacts to spurious transitions from 'U'/'X' at startup; or (level) infers a latch.
-- if clk'event and clk = '1' then ... ; -- prefer rising_edge
-- if clk = '1' then q <= d; end if; -- LEVEL → latch, not a flip-flop
-- CORRECT: clean, metavalue-safe edge detection.
if rising_edge(clk) then q <= d; end if;7. Common mistakes & what to watch for
- Using a level test for a register.
clk = '1'is level-sensitive → a latch. Userising_edge(clk)for an edge-triggered flip-flop. - Preferring
clk'event and clk = '1'. It is older and not metavalue-safe;rising_edgeis the modern, robust choice. - Detecting both edges in one process. A clocked process keys on one edge of one clock; dual-edge logic is special and rarely portable.
- Mixing clock domains. One clock per clocked process; crossing domains needs synchronisers (later).
- Putting combinational logic under the edge guard unnecessarily. Anything inside
rising_edgebecomes registered; keep purely combinational logic outside.
8. Engineering insight & continuity
Edge detection is the hinge of sequential design: rising_edge(clk) is what converts a process into a
flip-flop, because flip-flops are defined by capturing at a transition, not a level. Make
rising_edge/falling_edge your reflex — they are correct, safe, and self-documenting — and reserve a
single edge of a single clock per clocked process so all your registers update together in one timing
domain. With the edge understood, the next lesson builds the element it creates: The D Flip-Flop —
the atom of all stateful hardware — followed by Registers (D flip-flops in parallel) and the
enables, counters, and shift registers that compose them.