D Flip-Flop with Asynchronous Reset

Solving Approach

How do you plan to solve it?

The always block doesn't actually performs so you need to write code for it in case statement. Also, the changes based on the clock edge as well as the reset.

Code

module dff_async_reset (
    input  CLK,
    input  RST,
    input  D,
    output reg Q
);
    // async active-high reset with posedge sensitivity
    always @(posedge CLK or posedge RST) begin
        if(RST)
            Q = 1'b0;
        else
            Q <= D;
    end

endmodule

 

Upvote
Downvote

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