66. D Flip-Flop

Loading...

Testbench Code

`timescale 1ns/1ps

module tb_dff_posedge;
    // 1) Inputs
    reg CLK, D;
    // 2) Outputs
    wire Q;
    // 3) Expected outputs (prefixed "expected_")
    reg  expected_Q;
    // 4) Mismatch (HIGH when outputs != expected)
    wire mismatch;

    // DUT
    dff_posedge dut(.CLK(CLK), .D(D), .Q(Q));

    // Scoreboard: sample expected the same way as the DUT
    always @(posedge CLK) expected_Q <= D;

    // 4-state compare (case-inequality)
    assign mismatch = (Q !== expected_Q);

    // Counters / limits
    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 units period)
    initial begin
        CLK = 1'b0;
        forever #5 CLK = ~CLK;
    end

    // VCD — start at #0; dump only requested signals in order
    initial begin
        $dumpfile("tb_dff_posedge.vcd");
        // Order: Inputs -> Outputs -> Expected -> mismatch
        $dumpvars(0,
            tb_dff_posedge.CLK,
            tb_dff_posedge.D,
            tb_dff_posedge.Q,
            tb_dff_posedge.expected_Q,
            tb_dff_posedge.mismatch
        );
        $dumpon;
    end

    // Drive D on negedge, check after the next posedge
    task drive_and_check;
        input [127:0] tc_name;
        input d_val;
    begin
        @(negedge CLK);
        D = d_val;           // meet setup
        @(posedge CLK);      // capture edge for DUT and expected
        #1;                  // allow propagation

        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] %0s  D@edge=%b  Q=%b  expected_Q=%b  t=%0t",
                         tc_name, D, Q, expected_Q, $time);
        end

        if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
    end
    endtask

    // Between-edge data changes (Q must hold)
    task change_between_edges;
        input d_val;
    begin
        @(negedge CLK);
        D = d_val;
    end
    endtask

    // Compact edge table (2 rows)
    task print_edge_table;
        integer d;
    begin
        $display(" D | EXP_Q_after_↑CLK");
        $display("---------------------");
        for (d=0; d<2; d=d+1)
            $display(" %0d |        %0d", d[0], d[0]);
    end
    endtask

    initial begin
        // Explicitly start with unknown expected to match real flop power-up
        D = 1'b0;
        expected_Q = 1'bx;

        // Give one edge to establish a known state
        @(posedge CLK); #1;

        // Directed
        drive_and_check("cap_0", 1'b0);
        change_between_edges(1'b1);
        drive_and_check("cap_1", 1'b1);
        change_between_edges(1'b0);
        drive_and_check("cap_0_again", 1'b0);

        // Two-step sequences
        for (i=0; i<2; i=i+1) begin
            drive_and_check("prev_edge", i[0]);
            for (j=0; j<2; j=j+1)
                drive_and_check("next_edge", j[0]);
        end

        // Randomized sequences
        for (i=0; i<10; i=i+1) begin
            change_between_edges($random);
            drive_and_check("cap_rand", $random);
        end

        // Edge table
        print_edge_table();

        // 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