Verilog Designs · Module 24

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)
0 x 0
1 0 0
1 1 1
no edge x x Q (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)
0 x x 0
1 0 0
1 1 1
1 no edge x Q (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 reset rst_n=0 → clock edge Q=0 (at edge) Q=0 (immediately)
2 — Capture D=1 rst_n=1, D=1 → clock edge Q=1 Q=1
3 — Capture D=0 D=0 → clock edge Q=0 Q=0
4 — Hold test D changes, no clock edge Q holds (0) Q holds (0)
5 — Mid-cycle reset ★rst_n=0 between edgesQ=1 (ignores!)Q=0 (responds!)
5b — Edge with reset Clock edge arrives, rst_n still 0Q=0 (now resets)Q=0 (still 0)
6 — Normal operation rst_n=1, D alternates Q follows D Q follows D
7 — Async instant clearrst_n=0, no clock needed Q=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)tSU D must be stable tSU before posedge clk Same as sync for data capture
Hold time (D)tH D must be stable tH after posedge clk Same as sync for data capture
Setup time (rst_n)tSU_RST rst_n must be stable tSU before posedge clk N/A — asserts async, no setup required
Recovery timetREC N/A — rst_n is synchronous rst_n must deassert tREC before posedge clk
Removal timetREM N/A rst_n must stay low tREM after posedge clk
Clock-to-QtCQ Q updates tCQ after posedge clk Same 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

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top