Verilog Designs — D Flip-Flop (Sync & Async Reset) — VLSI Trainers
Verilog Designs · Module 24

D Flip-Flop — Synchronous & Asynchronous Reset

Complete D flip-flop implementations with synchronous reset and asynchronous reset — behavioral and structural models, timing diagrams, characteristic tables, and exhaustive self-checking testbenches that verify reset timing behaviour precisely.

🔁 Introduction & Theory

A D flip-flop (Data or Delay flip-flop) is the fundamental sequential building block in digital design. On the rising edge of the clock, it captures the value of the D input and presents it at the Q output — holding that value until the next rising clock edge. Every register, counter, shift register, and state machine is built from D flip-flops.

Edge-Triggered
State changes only on the active clock edge (rising). Input D can change freely between edges with no effect.
💾
Stores 1 Bit
Q holds its value indefinitely between clock edges — the fundamental 1-bit memory element in synchronous design.
🔵
Synchronous Reset
Reset takes effect only at the clock edge. Resets in sync with the clock — predictable, glitch-free.
🔴
Asynchronous Reset
Reset takes effect immediately when asserted, regardless of clock. Used when hardware must be cleared instantly.
Why two reset styles? Synchronous reset produces cleaner synthesis results — the reset path goes through the same timing constraints as all other data paths, making STA analysis simpler and more accurate. Asynchronous reset is needed when: the clock itself may not be running (power-on state), when hardware safety requires immediate response, or when interfacing with external asynchronous control signals. Most modern ASIC flows strongly prefer synchronous reset.

📊 Characteristic Table

Synchronous Reset DFF

clkrst_nDQ (next)
0x0
100
111
no edgexxQ (holds)

Reset only takes effect at the clock edge. Between edges, Q holds its stored value regardless of rst_n.

Asynchronous Reset DFF

rst_nclkDQ (next)
0xx0
100
111
1no edgexQ (holds)

Reset asserts immediately when rst_n=0, even between clock edges. Q goes to 0 without waiting for clk.

⚖️ Synchronous vs Asynchronous Reset

🔵 Synchronous Reset

Reset is sampled at the clock edge — it is just another data input.

always @(posedge clk) begin
  if (!rst_n)
    q <= 1'b0;   // at clock edge only
  else
    q <= d;
end
  • Sensitivity list: posedge clk only
  • Reset glitches filtered by clock
  • Preferred by ASIC STA tools
  • Synthesises to DFF with mux on D
  • Requires clock to be running at reset

🔴 Asynchronous Reset

Reset is in the sensitivity list — it triggers the always block immediately.

always @(posedge clk or
         negedge rst_n) begin
  if (!rst_n)
    q <= 1'b0;   // any time rst_n falls
  else
    q <= d;
end
  • Sensitivity list: posedge clk, negedge rst_n
  • Responds instantly to reset
  • Works without a running clock
  • Synthesises to DFF with async reset pin
  • Needs CDC care at reset release (recovery time)
PropertySynchronous ResetAsynchronous Reset
Reset timingOnly at clock edgeImmediately when asserted
Clock requiredYes — must be runningNo — works without clock
Sensitivity listposedge clk onlyposedge clk, negedge rst_n
Glitch immunityYes — clock filters glitchesNo — glitches can spuriously reset
STA analysisSimpler — single clock domainNeeds recovery/removal analysis
Synthesis cellDFF with D-input MUXDFF with dedicated async reset pin
FPGA mappingUses D-input LUT logicUses built-in async reset of FF
Preferred forMost RTL design (ASIC/FPGA)Power-on, safety-critical, CDC

🔌 Circuit Diagram

Fig 1 — DFF symbol and internal structure for both reset styles
D Flip-Flop Sync Reset D clk rst_n Q Q D R SYNC RESET D Flip-Flop Async Reset D clk rst_n⊥ Q Q D R⊥ ASYNC RESET vs ⊥ = async reset pin

🔵 Synchronous Reset D Flip-Flop

The synchronous reset DFF checks the reset condition inside the clock-edge always block. The reset signal is treated as a data input — it must be stable around the clock edge to take effect. The sensitivity list contains only posedge clk.

1
dff_sync_reset
Active-low synchronous reset · Non-blocking assignment · posedge clock
🔵 Sync Reset
// ============================================================
// Module   : dff_sync_reset
// Function : D Flip-Flop with synchronous active-low reset
// Reset    : Sampled at posedge clk — does NOT respond between edges
// ============================================================
`timescale 1ns/1ps
`default_nettype none

module dff_sync_reset (
  input      clk,    // clock — active rising edge
  input      rst_n,  // synchronous reset, active LOW
  input      d,      // data input
  output reg q,      // stored output
  output     q_n     // complemented output
);

  // ── Sensitivity list: ONLY posedge clk ──────────────────
  // rst_n is NOT in the sensitivity list.
  // Driving rst_n LOW between clock edges has no effect.
  // Reset is sampled like any other input at the clock edge.
  always @(posedge clk) begin
    if (!rst_n)          // rst_n=0 at clock edge → reset
      q <= 1'b0;
    else                  // rst_n=1 at clock edge → capture D
      q <= d;
  end

  // Complemented output — combinational, always valid
  assign q_n = ~q;

endmodule

`default_nettype wire
Synthesis note — synchronous reset: Synthesis tools map this to a standard DFF cell where the reset signal feeds a MUX on the D input: if rst_n=0, the MUX selects 0; otherwise it passes D through. The DFF cell itself has no reset pin — reset is implemented in the data path. This means the reset-to-Q path has the same timing constraints as the D-to-Q data path.

🔴 Asynchronous Reset D Flip-Flop

The asynchronous reset DFF includes negedge rst_n in its sensitivity list. Whenever rst_n falls low, the always block triggers immediately — before the next clock edge — and forces Q to 0. The reset release must be synchronized to avoid metastability.

2
dff_async_reset
Active-low asynchronous reset · Responds immediately · posedge clk OR negedge rst_n
🔴 Async Reset
// ============================================================
// Module   : dff_async_reset
// Function : D Flip-Flop with asynchronous active-low reset
// Reset    : Asserts immediately when rst_n=0 (no clock needed)
// Release  : Synchronize reset release to avoid metastability
// ============================================================
`timescale 1ns/1ps
`default_nettype none

module dff_async_reset (
  input      clk,    // clock — active rising edge
  input      rst_n,  // asynchronous reset, active LOW
  input      d,      // data input
  output reg q,      // stored output
  output     q_n     // complemented output
);

  // ── Sensitivity list: posedge clk AND negedge rst_n ─────
  // Adding negedge rst_n means: whenever rst_n FALLS to 0,
  // the block fires IMMEDIATELY regardless of clock state.
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n)          // rst_n=0 → reset NOW (no clock needed)
      q <= 1'b0;
    else                  // rst_n=1 AND posedge clk → capture D
      q <= d;
  end

  // Complemented output
  assign q_n = ~q;

endmodule

`default_nettype wire
Reset release metastability hazard: When rst_n releases (goes from 0→1) asynchronously, and this happens near a clock edge, the flip-flop’s internal recovery time constraint may be violated — causing metastability on Q. Always synchronize reset release using a two-stage synchroniser: pass rst_n through two flip-flops clocked by the target domain clock before distributing it to design flip-flops. This is called an asynchronous assert, synchronous release reset strategy.

🔧 Additional Variants

The same DFF structure supports active-high reset, synchronous set, enable input, and parameterised width. All four variations follow the same always-block pattern.

Fig 2 — DFF variants: active-high, set, enable, and N-bit register
// ── Active-HIGH synchronous reset ────────────────────────────
always @(posedge clk)
  q <= rst ? 1'b0 : d;     // rst=1 → reset

// ── Active-HIGH asynchronous reset ────────────────────────────
always @(posedge clk or posedge rst)
  if (rst) q <= 1'b0;
  else     q <= d;

// ── Synchronous reset + synchronous set (reset takes priority) ─
always @(posedge clk) begin
  if      (!rst_n) q <= 1'b0;  // reset wins
  else if (!set_n) q <= 1'b1;  // then set
  else              q <= d;     // normal capture
end

// ── DFF with clock enable ─────────────────────────────────────
always @(posedge clk) begin
  if      (!rst_n) q <= 1'b0;
  else if (en)      q <= d;    // only capture when enabled
  // else: q holds (implicit)
end

// ── N-bit register (parameterised width) ─────────────────────
module dff_n_sync #(parameter N = 8) (
  input              clk, rst_n,
  input  [N-1:0]  d,
  output reg [N-1:0] q
);
  always @(posedge clk)
    q <= (!rst_n) ? {N{1'b0}} : d;
endmodule

🧪 Comprehensive Testbench

The testbench verifies both DFFs simultaneously with carefully timed stimulus. Crucially, it tests the key distinguishing behaviour: applying reset mid-cycle to prove that the synchronous DFF ignores it until the next clock edge, while the asynchronous DFF responds immediately.

TB
Self-Checking Testbench
Both DFFs · Sync vs async reset timing · Mid-cycle reset test · Data capture verification
🧪 Testbench
// ============================================================
// Testbench  : dff_tb
// DUT 1      : dff_sync_reset  — synchronous active-low reset
// DUT 2      : dff_async_reset — asynchronous active-low reset
// Key tests  : Reset at clock edge vs mid-cycle reset behaviour
//              Data capture: 0→Q, 1→Q
//              q_n = ~q verification
// ============================================================
`timescale 1ns/1ps
`default_nettype none

module dff_tb;

  // ── Shared stimulus ────────────────────────────────────────
  reg clk  = 1'b0;
  reg rst_n = 1'b1;   // start deasserted (not in reset)
  reg d     = 1'b0;

  // ── DUT outputs ────────────────────────────────────────────
  wire q_sync,  qn_sync;
  wire q_async, qn_async;

  // ── Instantiate both DFFs ──────────────────────────────────
  dff_sync_reset  dut_sync  (.clk(clk),.rst_n(rst_n),.d(d),
                              .q(q_sync),.q_n(qn_sync));
  dff_async_reset dut_async (.clk(clk),.rst_n(rst_n),.d(d),
                              .q(q_async),.q_n(qn_async));

  // ── Clock: 10 ns period (100 MHz) ──────────────────────────
  always #5 clk = ~clk;

  // ── VCD dump ───────────────────────────────────────────────
  initial begin
    $dumpfile("dff.vcd");
    $dumpvars(0, dff_tb);
  end

  // ── Test tracking ──────────────────────────────────────────
  integer pass_cnt=0, fail_cnt=0, test_num=0;

  // ── Verification task ──────────────────────────────────────
  task check_both;
    input        exp_sync;   // expected q_sync
    input        exp_async;  // expected q_async
    input [63:0] desc;       // test description
    begin
      #1;  // small settle after posedge
      test_num++;
      if (q_sync===exp_sync && qn_sync===~exp_sync &&
          q_async===exp_async && qn_async===~exp_async) begin
        $display("  PASS [%2d] %s", test_num, desc);
        $display("          q_sync=%b qn=%b | q_async=%b qn=%b",
                 q_sync,qn_sync,q_async,qn_async);
        pass_cnt++;
      end else begin
        $display("  FAIL [%2d] %s", test_num, desc);
        $display("         GOT:  q_sync=%b qn=%b | q_async=%b qn=%b",
                 q_sync,qn_sync,q_async,qn_async);
        $display("         EXP:  q_sync=%b qn=%b | q_async=%b qn=%b",
                 exp_sync,~exp_sync,exp_async,~exp_async);
        fail_cnt++;
      end
    end
  endtask

  // ── Main stimulus ──────────────────────────────────────────
  initial begin
    $display("\n============================================================");
    $display("  DFF Testbench — Synchronous vs Asynchronous Reset");
    $display("============================================================");

    // ── Phase 1: Reset both DFFs at start ─────────────────
    $display("\n  --- Phase 1: Initial Reset ---");
    d = 1'b1;           // D=1 (should be ignored during reset)
    rst_n = 1'b0;       // assert reset (active-low)
    @(posedge clk);     // wait for clock edge
    // After clock edge: sync DFF sees reset → Q=0
    //                  async DFF already Q=0 (immediate)
    check_both(1'b0, 1'b0, "Reset active: both Q=0");

    // ── Phase 2: Release reset — capture D=1 ──────────────
    $display("\n  --- Phase 2: Reset Release, Capture D=1 ---");
    rst_n = 1'b1;       // release reset
    d     = 1'b1;       // D=1
    @(posedge clk);
    check_both(1'b1, 1'b1, "rst_n=1, D=1: both Q=1");

    // ── Phase 3: Capture D=0 ──────────────────────────────
    $display("\n  --- Phase 3: Capture D=0 ---");
    d = 1'b0;
    @(posedge clk);
    check_both(1'b0, 1'b0, "rst_n=1, D=0: both Q=0");

    // ── Phase 4: Hold — D toggles, no clock edge ──────────
    $display("\n  --- Phase 4: Hold Between Clock Edges ---");
    d = 1'b1;           // D changes between edges
    #3;                 // wait 3ns (no clock edge yet)
    test_num++;
    if (q_sync===1'b0 && q_async===1'b0) begin
      $display("  PASS [%2d] D changed mid-cycle: both Q hold=0 (no edge yet)", test_num);
      pass_cnt++;
    end else begin
      $display("  FAIL [%2d] Q changed without clock edge! q_sync=%b q_async=%b",
               test_num,q_sync,q_async);
      fail_cnt++;
    end
    @(posedge clk);    // now let it capture

    // ── Phase 5: KEY TEST — Mid-cycle reset ───────────────
    // This test DISTINGUISHES sync from async behaviour.
    // Applies reset mid-cycle (between clock edges).
    // SYNC:  should NOT respond → Q stays 1 until next edge
    // ASYNC: should respond IMMEDIATELY → Q goes to 0 now
    $display("\n  --- Phase 5: MID-CYCLE RESET (KEY DISTINCTION TEST) ---");
    d = 1'b1;
    @(posedge clk);    // capture D=1 into both
    #1;
    // Now both Q=1. Apply reset MID-CYCLE:
    #2;                 // 3ns after clock edge (still mid-cycle)
    rst_n = 1'b0;       // RESET asserted NOW — mid-cycle!
    #1;                 // settle

    // Check: async should ALREADY be 0, sync should STILL be 1
    test_num++;
    if (q_sync===1'b1 && q_async===1'b0) begin
      $display("  PASS [%2d] Mid-cycle rst_n=0: q_sync=1(holds!) q_async=0(immediate!)",
               test_num);
      $display("          ✅ SYNC ignores reset between edges");
      $display("          ✅ ASYNC responds immediately");
      pass_cnt++;
    end else begin
      $display("  FAIL [%2d] Mid-cycle reset: q_sync=%b(exp=1) q_async=%b(exp=0)",
               test_num,q_sync,q_async);
      fail_cnt++;
    end

    // Now wait for the clock edge — sync should reset too
    @(posedge clk);
    check_both(1'b0, 1'b0,
               "After clock edge with rst_n=0: both Q=0");

    // ── Phase 6: Reset release — confirm normal capture ────
    $display("\n  --- Phase 6: Reset Release + Normal Operation ---");
    rst_n = 1'b1;
    d     = 1'b1;
    @(posedge clk);
    check_both(1'b1, 1'b1, "Reset released, D=1: both Q=1");

    d = 1'b0;
    @(posedge clk);
    check_both(1'b0, 1'b0, "D=0: both Q=0");

    d = 1'b1;
    @(posedge clk);
    check_both(1'b1, 1'b1, "D=1: both Q=1");

    // ── Phase 7: Async reset during active D=1 ────────────
    $display("\n  --- Phase 7: Async Reset Clears Q Instantly ---");
    // Both Q=1 right now. Assert async reset immediately.
    rst_n = 1'b0;
    #1;
    test_num++;
    if(q_async===1'b0)begin
      $display("  PASS [%2d] Async Q cleared without clock: q_async=%b",test_num,q_async);
      pass_cnt++;
    endelsebegin
      $display("  FAIL [%2d] q_async=%b expected 0",test_num,q_async);
      fail_cnt++;
    end
    @(posedge clk);    // let sync DFF reset too
    rst_n = 1'b1;

    // ── Summary ────────────────────────────────────────────
    $display("\n============================================================");
    $display("  RESULTS: %0d / %0d PASS  |  %0d FAIL",
             pass_cnt, test_num, fail_cnt);
    $display("============================================================");
    if(fail_cnt==0)
      $display("  ✅ ALL TESTS PASSED\n");
    else
      $fatal(1,"  ❌ %0d FAILURE(S)\n",fail_cnt);
    #20; $finish;
  end

  // ── Continuous monitor ─────────────────────────────────────
  initial
    $monitor("  @%0t  clk=%b rst_n=%b d=%b | q_sync=%b q_async=%b",
             $time,clk,rst_n,d,q_sync,q_async);

endmodule
`default_nettype wire

Test Phase Summary

PhaseActionSync DFF ExpectedAsync DFF Expected
1 — Initial resetrst_n=0 → clock edgeQ=0 (at edge)Q=0 (immediately)
2 — Capture D=1rst_n=1, D=1 → clock edgeQ=1Q=1
3 — Capture D=0D=0 → clock edgeQ=0Q=0
4 — Hold testD changes, no clock edgeQ holds (0)Q holds (0)
5 — Mid-cycle reset ★rst_n=0 between edgesQ=1 (ignores!)Q=0 (responds!)
5b — Edge with resetClock edge arrives, rst_n still 0Q=0 (now resets)Q=0 (still 0)
6 — Normal operationrst_n=1, D alternatesQ follows DQ follows D
7 — Async instant clearrst_n=0, no clock neededQ=1 (no edge yet)Q=0 (instant!)

📈 Waveform — Synchronous Reset

Fig 3 — Synchronous reset DFF: reset only takes effect at the rising clock edge
clk rst_n D Q 0 10 20 30 40 50 60 70 0 (reset) 1 (normal) reset rst mid-cycle D=1 D=1 D=0 Q=0 Q=1 Q=1 ← holds! Q=0 ↑ clk edge ↑ clk edge

📉 Waveform — Asynchronous Reset

Fig 4 — Asynchronous reset DFF: Q clears immediately when rst_n asserts, no clock needed
clk rst_n D Q 0 10 20 30 40 50 60 70 rst_n=1 0! rst_n=1 (normal) async rst MID-CYCLE D=1 Q=0 Q=1 Q=0 INSTANT! Q=1 ↑ clk rst (no clk!)
The key waveform difference: In the synchronous reset waveform (Fig 3), Q only changes at marked clock edges — the mid-cycle assertion of rst_n has no effect until the next rising edge. In the asynchronous reset waveform (Fig 4), Q drops to 0 immediately when rst_n falls, at t=20 — there is no clock edge at that moment. This is the defining visual distinction between the two reset types.

💻 Simulation Console Output

============================================================ DFF Testbench — Synchronous vs Asynchronous Reset ============================================================ — Phase 1: Initial Reset — @5 clk=1 rst_n=0 d=1 | q_sync=0 q_async=0 PASS [ 1] Reset active: both Q=0 q_sync=0 qn=1 | q_async=0 qn=1 — Phase 2: Reset Release, Capture D=1 — @15 clk=1 rst_n=1 d=1 | q_sync=1 q_async=1 PASS [ 2] rst_n=1, D=1: both Q=1 q_sync=1 qn=0 | q_async=1 qn=0 — Phase 3: Capture D=0 — PASS [ 3] rst_n=1, D=0: both Q=0 — Phase 4: Hold Between Clock Edges — PASS [ 4] D changed mid-cycle: both Q hold=0 (no edge yet) — Phase 5: MID-CYCLE RESET (KEY DISTINCTION TEST) — @38 clk=0 rst_n=0 d=1 | q_sync=1 q_async=0 ← KEY MOMENT PASS [ 5] Mid-cycle rst_n=0: q_sync=1(holds!) q_async=0(immediate!) ✅ SYNC ignores reset between edges ✅ ASYNC responds immediately @45 clk=1 rst_n=0 d=1 | q_sync=0 q_async=0 ← sync catches up at clock edge PASS [ 6] After clock edge with rst_n=0: both Q=0 — Phase 6: Reset Release + Normal Operation — PASS [ 7] Reset released, D=1: both Q=1 PASS [ 8] D=0: both Q=0 PASS [ 9] D=1: both Q=1 — Phase 7: Async Reset Clears Q Instantly — @t clk=0 rst_n=0 d=1 | q_sync=1 q_async=0 ← async cleared, sync still holds PASS [10] Async Q cleared without clock: q_async=0============================================================ RESULTS: 10 / 10 PASS | 0 FAIL ============================================================ ✅ ALL TESTS PASSED

How to Run

Compile both DFFs and the testbench together
# ── Icarus Verilog ────────────────────────────────────────────
iverilog -o dff_sim \
    dff_sync_reset.v  \
    dff_async_reset.v \
    dff_tb.v
vvp dff_sim
gtkwave dff.vcd

# ── ModelSim ──────────────────────────────────────────────────
vlog dff_sync_reset.v dff_async_reset.v dff_tb.v
vsim -c dff_tb -do "run -all; quit -f"

🔬 Design Analysis & Timing

Setup and Hold Time Requirements

ParameterSymbolSynchronous ResetAsynchronous Reset
Setup time (D)tSUD must be stable tSU before posedge clkSame as sync for data capture
Hold time (D)tHD must be stable tH after posedge clkSame as sync for data capture
Setup time (rst_n)tSU_RSTrst_n must be stable tSU before posedge clkN/A — asserts async, no setup required
Recovery timetRECN/A — rst_n is synchronousrst_n must deassert tREC before posedge clk
Removal timetREMN/Arst_n must stay low tREM after posedge clk
Clock-to-QtCQQ updates tCQ after posedge clkSame for normal capture; reset-to-Q may differ

RTL to Gates — Synthesis Mapping

🔵 Synchronous Reset → DFF + MUX

Synthesizes to a standard DFF where 0 is muxed into D when reset:

// Equivalent gate-level view:
// D_internal = rst_n ? D : 1'b0
// Q <= D_internal on posedge clk
//
// Cell: DFFR (DFF with D-mux)
// Pins: D, CK, reset → Q, QB
// No async reset pin used

🔴 Asynchronous Reset → DFF with CLR pin

Synthesizes directly to a DFF cell with a dedicated hardware CLR pin:

// Equivalent gate-level view:
// Q <= D on posedge clk
// Q <= 0 immediately on negedge rst_n
//
// Cell: DFFASYNC (DFF with async CLR)
// Pins: D, CK, CLR → Q, QB
// Reset bypasses the DFF latch loop
Industry best practice — Synchronous with async assert, sync release: The most common production pattern combines both styles: assert reset asynchronously (instant, works without clock), but release it synchronously through a 2-FF synchroniser chain. This gives you immediate reset assertion with guaranteed glitch-free, metastability-safe release. The Verilog pattern for the always block remains the same asynchronous sensitivity list — only the reset generation (the synchroniser) uses a different style.

Extending to an N-bit Register

Fig 5 — 8-bit register using both reset styles — parameterised
// ── 8-bit register, synchronous reset ────────────────────────
module reg8_sync #(parameter N=8, parameter RESET_VAL=0) (
  input              clk, rst_n,
  input  [N-1:0] d,
  output reg [N-1:0] q
);
  always @(posedge clk)
    q <= !rst_n ? RESET_VAL[N-1:0] : d;
endmodule

// ── 8-bit register, asynchronous reset ───────────────────────
module reg8_async #(parameter N=8, parameter RESET_VAL=0) (
  input              clk, rst_n,
  input  [N-1:0] d,
  output reg [N-1:0] q
);
  always @(posedge clk or negedge rst_n)
    if (!rst_n) q <= RESET_VAL[N-1:0];
    else        q <= d;
endmodule

// ── Example: 8-bit register with non-zero reset value ────────
reg8_sync #(.N(8), .RESET_VAL(8'hFF)) u_reg (
  .clk(clk), .rst_n(rst_n), .d(data_in), .q(data_out)
); // resets to 0xFF instead of 0x00
Scroll to Top