A D latch is a level-sensitive storage element. While its enable input is high, the output follows the data input; when the enable goes low, the output holds its last value. In Verilog, a D latch is described with an always block that assigns the output only when the enable is active.
10 min read | Beginner Level
What You'll Learn
- How a D latch behaves in its transparent and hold states
- Write a D latch with an asynchronous reset in Verilog
- What synthesis builds from latch code, and how unintended latches get inferred
- How a latch differs from a flip-flop, and how to verify one with a testbench
What is a D Latch?
A D latch has a data input (d), an enable input (en) and an output (q). The design in this article also has an active-low reset (rstn). The latch works in two states:
- Transparent (en = 1): q follows d. Any change on d appears on q after a short propagation delay.
- Hold (en = 0): q keeps the value d had at the moment en went low. Changes on d are ignored.
| rstn | en | d | q (next) | State |
|---|---|---|---|---|
| 0 | x | x | 0 | Reset |
| 1 | 1 | 0 | 0 | Transparent |
| 1 | 1 | 1 | 1 | Transparent |
| 1 | 0 | x | q (no change) | Hold |
The key word is level-sensitive. A latch responds for the whole time the enable is high, not just at one instant. A flip-flop is edge-triggered and samples its input only at a clock edge.
Syntax
Verilog has no latch keyword. Synthesis infers a latch when an always block assigns a signal under some conditions but not others, and the block is not edge-triggered. The signal must then keep its old value in the unassigned cases, which requires storage.
Basic Form:
always @(*) // Level-sensitive: no posedge or negedge
if (en) // Assign q only when en is high...
q <= d; // ...so q must hold its value when en is low
Components:
always @(*)- Level-sensitive block; must includedandensoqtracksdwhile transparent (required)if (en)- The enable condition, with noelsebranch forq(required)q- Declared asregbecause it is assigned in a procedural block (required)
Variations:
// 1. With asynchronous active-low reset (used in this article)
always @(*)
if (!rstn) q <= 0;
else if (en) q <= d;
// 2. Negative-level latch: transparent while en is low
always @(*)
if (!en) q <= d;
Design
This D latch adds an active-low reset to the basic form. Reset is checked first, so it clears q regardless of en.
module d_latch (
input d, // Data input
input en, // Enable: 1 = transparent, 0 = hold
input rstn, // Active-low asynchronous reset
output reg q // Latched output; reg because it is assigned in always
);
// Level-sensitive block: re-evaluates whenever en, rstn or d changes
always @(*)
if (!rstn) // Reset has top priority and works even when en = 0
q <= 0;
else if (en) // Transparent: q follows d
q <= d;
// No final else: when rstn = 1 and en = 0, q is not assigned,
// so it keeps its value. This missing branch is what creates the latch.
endmodule
Synthesis result: Synthesis sees that q is not assigned when rstn = 1 and en = 0, so it infers a level-sensitive latch with en as its gate and rstn as an asynchronous clear. On an ASIC, this maps to a D-latch standard cell with a clear input. On an FPGA, the storage elements in each logic slice can usually be configured as latches, and the tool reports the inferred latch in its log.

The design uses non-blocking assignments (<=) because a latch is a storage element, like a flip-flop. This is the common coding guideline for latches; see Verilog Blocking & Non-Blocking.
Where is a D Latch Used?
Clock gating turns off the clock to idle blocks to save dynamic power. An integrated clock gating (ICG) cell uses a latch that is transparent while the clock is low to capture the enable signal, then ANDs the latched enable with the clock. Because the latch holds the enable steady while the clock is high, the gated clock cannot glitch. Synthesis tools insert thousands of these cells into a typical SoC.
Quick Check
Q: The latch is transparent with d = 1. Then en goes low, and d changes to 0. What is q?
Show Answer
q = 1. When en goes low, the latch holds the value d had at that moment. Later changes on d are ignored until en goes high again.
D Latch vs D Flip-Flop
Both store one bit, but they capture data differently. A flip-flop is effectively two latches in series that are enabled on opposite clock levels, which is why it responds only at the edge between them. See D Flip-Flop Async Reset for the edge-triggered version.
| D Latch | D Flip-Flop | |
|---|---|---|
| Triggered by | Level of en | Edge of clk |
| Output changes | Any time while en is high | Only at the active clock edge |
| Verilog form | always @(*) with incomplete assignment | always @(posedge clk) |
| Glitches on d | Pass through to q while transparent | Ignored between clock edges |
| Area | Smaller, roughly half a flip-flop | Larger |
| Timing analysis | More complex (time borrowing) | Straightforward |
Latch-Based Pipelines
Some high-performance processor pipelines use latches instead of flip-flops between stages. Because a latch is transparent for half the clock period, a slow logic stage can borrow time from the next stage, a technique called time borrowing. This helps the design meet a higher clock frequency, at the cost of more complex timing analysis.
Unintended Latch Inference
The same rule that creates the D latch above also creates latches by accident. In a block meant to be combinational, if any path leaves an output unassigned, synthesis infers a latch to hold its value.
// Intended: combinational logic. Actual: a latch on y.
always @(*)
if (sel)
y = a; // y is not assigned when sel = 0, so a latch holds it
// Fixed: every path assigns y, so this is a plain 2 to 1 mux
always @(*)
if (sel)
y = a;
else
y = b;
Unintended latches cause timing problems, because static timing analysis treats them differently from combinational paths, and they make the design hard to test. Most synthesis tools print a warning such as "Latch inferred for signal y". Treat that warning as an error unless the latch is intentional. Other causes are a case statement with no default and an output that is assigned in only some branches. See Combinational Logic with always for coding patterns that avoid them.
Assign a default value to every output at the top of a combinational always block, such as y = 0;. Every path then assigns the output, and no latch can be inferred.
Testbench
The testbench releases reset at 10 ns, then toggles en and changes d after random delays. This exercises both states: q should follow d while en is 1 and hold while en is 0. See Verilog Testbench for testbench structure.
module tb_latch;
// Testbench regs drive the design inputs; a wire collects the output
reg d;
reg en;
reg rstn;
reg [2:0] delay; // Random delay before each d change (0 to 7)
reg [1:0] delay2; // Random delay before each en toggle (0 to 3)
integer i;
wire q;
// Instantiate the design and connect its ports to testbench signals
d_latch dl0 ( .d (d),
.en (en),
.rstn (rstn),
.q (q));
initial begin
// Print a line whenever en, d or q changes
$monitor ("[%0t] en=%0b d=%0b q=%0b", $time, en, d, q);
// 1. Start with reset asserted and the latch closed
d <= 0;
en <= 0;
rstn <= 0;
// 2. Release reset after 10 time units
#10 rstn <= 1;
// 3. Toggle en and change d after random delays
// d is 1 bit wide, so d <= i keeps only bit 0 of i
for (i = 0; i < 5; i=i+1) begin
delay = $random;
delay2 = $random;
#(delay2) en <= ~en;
#(delay) d <= i;
end
end
endmodule
ncsim> run [0] en=0 d=0 q=0 [11] en=1 d=0 q=0 [18] en=0 d=0 q=0 [19] en=0 d=1 q=0 [20] en=1 d=1 q=1 [25] en=1 d=0 q=0 [27] en=0 d=0 q=0 [32] en=0 d=1 q=0 [33] en=1 d=1 q=1 [34] en=1 d=0 q=0 ncsim: *W,RNQUIE: Simulation is complete.
Reading the log, both states are visible:
- Hold: At 19 ns, d changes to 1 while en is 0, and q stays 0. The same happens at 32 ns.
- Transparent: At 20 ns, en goes high and q immediately takes the value of d (1). At 25 ns, d drops to 0 while en is still 1, and q follows it in the same time step. A flip-flop would not respond until its next clock edge.
Latch-Based Register Files
Low-power and area-sensitive designs, such as small microcontrollers and sensor-node processors, sometimes build register files from latches instead of flip-flops. Since a latch is roughly half the size of a flip-flop, this can noticeably reduce the area and power of a register file that holds dozens of words.
Common Beginner Mistakes
Mistake #1: Adding an edge to the sensitivity list
Wrong: always @(posedge en) if (en) q <= d;
Right: always @(*) if (en) q <= d;
Why? posedge makes the block edge-triggered, so synthesis builds a flip-flop clocked by en. q captures d only at the rising edge of en and ignores later changes, which removes the transparent behavior.
Mistake #2: Leaving d out of the sensitivity list
Wrong: always @(en or rstn)
Right: always @(*) or always @(en or rstn or d)
Why? In simulation, the block runs only when en or rstn changes, so q does not follow d while the latch is transparent. Synthesis ignores the sensitivity list and builds a correct latch, so the RTL simulation and the gate-level netlist disagree.
Mistake #3: Checking enable before reset
Wrong: if (en) q <= d; else if (!rstn) q <= 0;
Right: if (!rstn) q <= 0; else if (en) q <= d;
Why? The first true condition wins. With enable checked first, reset is ignored while en is high, so the latch cannot be cleared during transparent operation. Reset must come first to work at all times.
Mistake #4: Creating a latch by accident in combinational code
Wrong: always @(*) if (sel) y = a; in logic meant to be combinational
Right: always @(*) begin y = b; if (sel) y = a; end
Why? Any path that leaves y unassigned makes synthesis add a latch. Check the synthesis log for "latch inferred" warnings after every run, and make sure each reported latch is one you wrote on purpose.
Practice Exercise
Challenge: Negative-Level D Latch
Write a module d_latch_low that is transparent while en is low and holds while en is high. Keep the active-low asynchronous reset. This is the type of latch used inside a clock gating cell, where it captures the enable while the clock is low.
Hint
Only the enable condition changes. Keep reset as the first check, then invert the enable test.
Solution
module d_latch_low (
input d, // Data input
input en, // Enable: 0 = transparent, 1 = hold
input rstn, // Active-low asynchronous reset
output reg q
);
always @(*)
if (!rstn) // Reset still has top priority
q <= 0;
else if (!en) // Transparent while en is low
q <= d;
// No else: q holds while en is high
endmodule
Synthesis infers a latch with an active-low gate. You can verify it with the same testbench: q should now follow d in the intervals where the log shows en=0.
Summary
In this tutorial, you learned:
- A D latch is level-sensitive: transparent while enable is high, holding while enable is low
- A latch is inferred when a non-edge-triggered
alwaysblock leaves an output unassigned on some path - Reset should be checked before enable so it works in every state
- Synthesis maps the design to a latch cell with an asynchronous clear
- A flip-flop is edge-triggered and is built from two latches enabled on opposite clock levels
- Latches are used intentionally in clock gating cells, latch-based pipelines and compact register files
- Unintended latches come from missing
elseordefaultbranches; assign defaults to prevent them