67. D Flip-Flop with Asynchronous Reset

Design a positive-edge–triggered D flip-flop with an active-high asynchronous reset. When RST=1, the output clears to 0 immediately; otherwise, Q captures D on each rising edge of CLK.

Requirements

  • Module: dff_async_reset
  • Ports:
    • Inputs:
      • CLK
      • RST
      • D
    • Outputs:
      • Q
  • Functional behavior
    • RST=1Q=0 immediately.
    • On posedge CLK with RST=0Q=D.
    • Between events → hold.
  • Modeling constraints
    • Use always @(posedge CLK or posedge RST) with nonblocking assignments (<=).
    • Reset has priority over data capture.

Testbench Code

`timescale 1ns/1ps

module tb_dff_async_reset;
    // 1) Inputs
    reg CLK, RST, D;
    // 2) Outputs
    wire Q;
    // 3) Expected outputs (prefixed "expected_")
    reg  expected_Q;
    // 4) Mismatch
    wire mismatch;

    // DUT
    dff_async_reset dut(.CLK(CLK), .RST(RST), .D(D), .Q(Q));

    // Scoreboard: mirror DUT behavior exactly
    always @(posedge CLK or posedge RST) begin
        if (RST) expected_Q <= 1'b0;
        else     expected_Q <= D;
    end

    assign mismatch = (Q !== expected_Q);

    integer TOTAL_TEST_CASES        = 0;
    integer TOTAL_PASSED_TEST_CASES = 0;
    integer TOTAL_FAILED_TEST_CASES = 0;
    integer VCD_MAX_CASES           = 32;
    integer ERROR_MAX_CASES         = 32;

    integer i, j;

    // Free-running clock (10 time-unit period)
    initial begin
        CLK = 1'b0;
        forever #5 CLK = ~CLK;
    end

    // VCD: only Inputs -> Outputs -> Expected -> mismatch; start at #0
    initial begin
        $dumpfile("tb_dff_async_reset.vcd");
        $dumpvars(0,
            tb_dff_async_reset.CLK,
            tb_dff_async_reset.RST,
            tb_dff_async_reset.D,
            tb_dff_async_reset.Q,
            tb_dff_async_reset.expected_Q,
            tb_dff_async_reset.mismatch
        );
        $dumpon;
    end

    task log_case;
    begin
        TOTAL_TEST_CASES = TOTAL_TEST_CASES + 1;
        if (!mismatch) begin
            TOTAL_PASSED_TEST_CASES = TOTAL_PASSED_TEST_CASES + 1;
        end else begin
            TOTAL_FAILED_TEST_CASES = TOTAL_FAILED_TEST_CASES + 1;
            if (TOTAL_FAILED_TEST_CASES <= ERROR_MAX_CASES)
                $display("[FAIL] CLK=%b RST=%b D=%b  Q=%b expected_Q=%b  t=%0t",
                         CLK, RST, D, Q, expected_Q, $time);
        end
        if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
    end
    endtask

    // Assert reset asynchronously at any time
    task async_assert_reset;
    begin
        RST = 1'b0; #1;  // ensure a clean 0->1 edge
        RST = 1'b1;      // async clear
        #1;              // allow propagation
        log_case();
    end
    endtask

    // Deassert reset; Q should hold 0 until the next posedge CLK
    task async_release_reset;
    begin
        RST = 1'b0;
        #1;
        log_case();
    end
    endtask

    // Drive data on negedge, then check after next posedge
    task capture_cycle;
        input d_val;
    begin
        @(negedge CLK);
        D = d_val;
        @(posedge CLK);
        #1;
        log_case();
    end
    endtask

    initial begin
        // Start with unknown expected like real silicon; first reset will define it
        D = 1'b0; RST = 1'b0; expected_Q = 1'bx;
        @(negedge CLK);

        // Basic async reset behavior and captures
        async_assert_reset();
        async_release_reset();
        capture_cycle(1'b1);
        capture_cycle(1'b0);

        // Reset during different clock phases and around edges
        @(negedge CLK); async_assert_reset();
        capture_cycle(1'b1);      // clock edge while reset asserted -> Q stays 0
        async_release_reset();
        capture_cycle(1'b1);
        @(posedge CLK); #1; async_assert_reset(); // assert near/after edge
        async_release_reset();
        capture_cycle(1'b0);

        // Randomized sequences
        for (i=0; i<6; i=i+1) begin
            if ($random) async_assert_reset();
            if ($random) async_release_reset();
            capture_cycle($random);
        end

        // Summary
        $display("TOTAL_TEST_CASES=%0d",        TOTAL_TEST_CASES);
        $display("TOTAL_PASSED_TEST_CASES=%0d", TOTAL_PASSED_TEST_CASES);
        $display("TOTAL_FAILED_TEST_CASES=%0d", TOTAL_FAILED_TEST_CASES);
        $display("ALL_TEST_CASES_PASSED=%s",    (TOTAL_FAILED_TEST_CASES==0) ? "true" : "false");

        #2 $finish;
    end
endmodule