Beginner · Lesson 4 of 10

Registers, clocks and the idea of state

Flip-flops, clock edges, setup and hold explained intuitively, the synchronous design rules that keep a design predictable, and a register with synchronous reset and enable in Verilog and VHDL

Beginner30 minUpdated 13 Nov 2026

You will learn

  • Explain what a D flip-flop does at a clock edge and why a design needs state at all
  • Describe setup and hold time intuitively and say what happens when they are violated
  • State the synchronous design rules and give the reason behind each one
  • Write a register with synchronous reset and clock enable in Verilog and VHDL

Before this: combinational logic and luts

Lesson 03 covered logic without memory. This lesson adds the second half of every digital design: the register, which remembers a value from one clock edge to the next. Once you have registers you have state, and with state you can count, sequence, filter and communicate. You also inherit a set of rules about clocks and timing that every reliable FPGA design follows. This lesson gives you those rules and the reasons behind them.

Why a circuit needs state

A combinational circuit answers one question: given these inputs now, what is the output now. It cannot answer “how many pulses have arrived”, “what was the input a microsecond ago” or “which step of the procedure are we on”, because those questions depend on history. To hold history a circuit needs memory, and the simplest useful memory is one bit that can be told to take a new value at a chosen moment and otherwise keeps what it has.

That element is the D flip-flop. It has a data input d, a clock input clk and an output q. At each rising edge of the clock it copies d to q. Between edges q holds still, whatever d does. A register is a row of flip-flops sharing a clock, so an 8-bit register is eight flip-flops that all capture their inputs at the same instant.

The “chosen moment” is the point. By agreeing that values are captured only on clock edges, the whole design acquires a rhythm. Logic between registers can glitch, ripple and settle during the clock period, and none of that matters as long as it has finished by the next edge. The clock turns continuous, messy analogue reality into a sequence of clean discrete steps.

The D flip-flop in time

The timing diagram shows a flip-flop over four clock cycles. Read the d and q rows against the edges of clk.

A D flip-flop samples d on each rising edge of clk. d must be stable for the setup time before the edge and the hold time after it.clkdqt_setupt_holdabc
A D flip-flop samples d on each rising edge of clk. d must be stable for the setup time before the edge and the hold time after it.

At the first rising edge d is unknown, so q is unknown. Before the second edge d becomes 1, and at that edge q becomes 1. d then stays 1 for two cycles and q follows it, but notice that q does not change at the third edge because d has not changed. Before the fourth edge d falls to 0 and q falls at the edge, one clock after d. The output is always the input delayed to the next edge.

Two arrows on the diagram mark the timing requirements that make this work.

Setup time

A flip-flop is built from transistors, and the circuit that captures d needs the input to have been stable for a short time before the edge arrives. That interval is the setup time, written t_setup or t_su. In a modern FPGA it is a few tens of picoseconds. If d changes inside the setup window the flip-flop may capture the old value, the new value, or neither, as described below.

Hold time

Similarly, d must stay stable for a short time after the edge, the hold time, t_hold or t_h, while the capture circuit lets go of the input. It is also tens of picoseconds and can be zero or slightly negative in some devices. Hold violations are rarer than setup violations in FPGAs because the routing between flip-flops almost always adds more delay than the hold time requires, but they can occur on very short paths and the tools check for them.

What happens when the rules are broken

If d changes inside the setup or hold window, the flip-flop’s internal node may be left balanced between 0 and 1. It will eventually fall to one side, but the time it takes is unbounded in principle and random in practice. During that time q is neither a valid 0 nor a valid 1, and logic downstream that reads it may see different values on different paths. This condition is called metastability. It cannot be eliminated, only made rare, and every design that takes a signal from outside its clock domain has to deal with it. The timing and constraints topic and the glossary entry on metastability cover the standard remedy, a two-flip-flop synchroniser.

Inside a single clock domain, metastability never arises if the tools have done their job, because of the timing check described next.

Timing between registers

Every path in a synchronous design has the same shape: a flip-flop launches a value at one edge, the value passes through some combinational logic and routing, and another flip-flop captures it at the next edge.

FF 1dqcombinationalLUTs + carry, 1 to 6 levelsFF 2dqclkt_clk_to_qt_logict_routet_setupmust fit inside one clock period
A register-to-register path. The clock period must be long enough for the launch flip-flop's clock-to-output delay, the logic delay, the routing delay and the capture flip-flop's setup time.

The arithmetic is simple. If the clock period is 10 ns (100 MHz), the launch flip-flop takes about 0.4 ns to drive its output after the edge, the capture flip-flop needs about 0.1 ns of setup, and the logic and routing between them may use whatever is left, about 9.5 ns. Three or four LUT levels with their routing fit comfortably. Twenty levels do not. Place and route checks this for every path in the design and reports the worst one as the critical path. If its delay is under the budget the design has positive slack and will work at that clock rate on every device of that speed grade, at every temperature and voltage in the datasheet range.

This is the reward for keeping to synchronous design. A single number, the clock period, constrains every path, and a single automated check tells you whether the design is correct in time. Nothing else in digital design gives you that guarantee so cheaply.

The synchronous design rules

The guarantee holds only if the design follows a short set of rules. Each has a reason and each is broken regularly by beginners.

  1. One clock, distributed by the dedicated clock network. Every flip-flop in a block of logic should be clocked by the same clock, delivered through the device’s low-skew global clock tree so that all of them see the edge within a few tens of picoseconds of each other. If two flip-flops saw the edge 2 ns apart, the timing budget above would be wrong by 2 ns in a direction the tool cannot predict. Designs do use multiple clocks, but every crossing between them is a special case with its own lesson.
  2. Never generate a clock from logic. A LUT output used as a clock will glitch, as lesson 03 explained, and each glitch is an extra edge. It will also be routed on ordinary wires with unpredictable skew. If you need a slower rate, keep the fast clock and use a clock enable, as the register below shows. If you need a different frequency, use a PLL.
  3. Use synchronous resets, and apply them through the data path. A reset that takes effect at the clock edge, like the one in the example below, is a normal timed path and the tools can check it. An asynchronous reset is released at some arbitrary moment and, if that moment is near a clock edge, causes metastability across the whole design at once. There are good reasons to use asynchronous resets in some situations, and the reset design lesson in the intermediate track covers them, but the default is synchronous.
  4. Register every input from outside and every output to outside. Signals from pins, buttons and other clock domains are not aligned to your clock. Pass them through two flip-flops before using them. Drive outputs from flip-flops so that their timing relative to the clock is exact.
  5. Do not read a signal before the edge that writes it and expect the new value. Every flip-flop updates at the edge and the new value is visible after it. Logic that uses q sees the old value for the whole cycle. This is not a limitation. It is what makes the timing analysis possible.

A register with synchronous reset and enable

Here is the register that most real designs are made of. It has a clock, a synchronous reset that forces the output to zero, an enable that gates whether a new value is loaded, and a data input and output of configurable width. When en is 0 the register holds its value, which is how you make part of a design run at a slower rate without a second clock.

module reg_en #(
  parameter WIDTH = 8
) (
  input  wire             clk,
  input  wire             rst,
  input  wire             en,
  input  wire [WIDTH-1:0] d,
  output reg  [WIDTH-1:0] q
);
  always @(posedge clk) begin
    if (rst)
      q <= {WIDTH{1'b0}};
    else if (en)
      q <= d;
  end
endmodule
library ieee;
use ieee.std_logic_1164.all;

entity reg_en is
  generic (
    WIDTH : positive := 8
  );
  port (
    clk : in  std_logic;
    rst : in  std_logic;
    en  : in  std_logic;
    d   : in  std_logic_vector(WIDTH-1 downto 0);
    q   : out std_logic_vector(WIDTH-1 downto 0)
  );
end entity;

architecture rtl of reg_en is
begin
  process (clk)
  begin
    if rising_edge(clk) then
      if rst = '1' then
        q <= (others => '0');
      elsif en = '1' then
        q <= d;
      end if;
    end if;
  end process;
end architecture;

The structure to learn by heart is the same in both languages. There is one block that is sensitive to the clock (always @(posedge clk) or process (clk) with rising_edge). Inside it, the reset is tested first so that it wins over everything else. Then the enable. Then the actual assignment. Everything written inside that block becomes a flip-flop, and everything that is not assigned in a given branch keeps its old value, which is how the hold-when-disabled behaviour arises without any extra code.

Synthesis maps this onto the flip-flop primitives directly. Every FPGA flip-flop has a dedicated clock enable pin and a dedicated synchronous reset pin, so the if statements cost nothing in LUTs. If you wrote the priority the other way round, with enable gating the reset, the tool would need a LUT to combine them and you would have a reset that did not work when the enable was low.

A short testbench exercises the three behaviours: held when disabled, loaded when enabled, held again when disabled.

`timescale 1ns/1ps
module reg_en_tb;
  reg        clk = 1'b0;
  reg        rst = 1'b1;
  reg        en  = 1'b0;
  reg  [7:0] d   = 8'h00;
  wire [7:0] q;

  reg_en #(.WIDTH(8)) dut (.clk(clk), .rst(rst), .en(en), .d(d), .q(q));

  always #5 clk = ~clk;   // 100 MHz

  initial begin
    repeat (2) @(posedge clk);
    rst <= 1'b0;
    d   <= 8'hA5;           // en still low: q must stay 0
    @(posedge clk); #1;
    if (q !== 8'h00) $display("FAIL: q changed while en was low");
    en  <= 1'b1;
    @(posedge clk); #1;
    if (q !== 8'hA5) $display("FAIL: q did not load, got %h", q);
    en  <= 1'b0;
    d   <= 8'h3C;
    @(posedge clk); #1;
    if (q !== 8'hA5) $display("FAIL: q changed after en dropped");
    $display("done");
    $finish;
  end
endmodule

Note the #1 after each @(posedge clk). The flip-flop updates at the edge, and checking q at exactly the same instant would be a race between the testbench and the design. Waiting 1 ns steps clear of the edge. Lesson 06 makes this precise.

State, in one sentence

A synchronous design is a set of registers holding the current state, plus combinational logic that computes the next state and the outputs from the current state and the inputs, with the clock advancing from one state to the next. Counters (lesson 08) are the simplest instance. Finite state machines (lesson 07) are the general one. Every processor, every protocol engine and every video pipeline is a large version of the same thing.

Exercise

  1. On the timing diagram at the top, d rises one full cycle before the edge that captures it. Redraw the diagram, on paper or in the WaveDrom online editor, so that d rises 0.5 cycles before the edge and falls 0.5 cycles after. Mark where the setup and hold windows now sit and say whether the design is still safe.
  2. A design runs at 200 MHz. The flip-flop clock-to-output delay is 0.45 ns and the setup time is 0.08 ns. Each LUT and its routing costs about 0.9 ns. What is the largest number of LUT levels that can sit between two registers, and what is the slack if the path uses three levels.
  3. Add a second enable to reg_en, called clr, that sets q to all ones at the next edge regardless of en but only when rst is low. Decide where it goes in the priority order, implement it in both languages, and extend the testbench to check it.

Summary

  • A D flip-flop copies d to q on each rising clock edge and holds q otherwise. A register is a row of them sharing a clock.
  • d must be stable for the setup time before the edge and the hold time after it. Violating either risks metastability, an unbounded delay in resolving to a valid level.
  • Every register-to-register path must fit clock-to-output, logic, routing and setup into one clock period. Place and route checks all of them and reports the worst as the critical path.
  • The synchronous rules are: one clock on the global network, no clocks from logic, synchronous resets, register inputs and outputs, and read old values for the whole cycle.
  • The standard register has reset first, enable second, assignment last, and both the reset and the enable map onto dedicated flip-flop pins at no cost.

Further reading