73. T Flip-Flop with Asynchronous Preset and Reset

Loading...

Testbench Code

`timescale 1ns/1ps

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

    // DUT
    t_ff_async_pr dut(.CLK(CLK), .RST(RST), .PRE(PRE), .T(T), .Q(Q));

    // Scoreboard: mirror DUT exactly (async + sync)
    always @(posedge CLK or posedge RST or posedge PRE) begin
        if (RST)      expected_Q <= 1'b0;
        else if (PRE) expected_Q <= 1'b1;
        else if (T)   expected_Q <= ~expected_Q;
        else          expected_Q <= expected_Q;
    end

    // 4-state compare
    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-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_t_ff_async_pr.vcd");
        $dumpvars(0,
            tb_t_ff_async_pr.CLK,
            tb_t_ff_async_pr.RST,
            tb_t_ff_async_pr.PRE,
            tb_t_ff_async_pr.T,
            tb_t_ff_async_pr.Q,
            tb_t_ff_async_pr.expected_Q,
            tb_t_ff_async_pr.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] RST=%b PRE=%b T=%b  Q=%b expected_Q=%b  t=%0t",
                         RST, PRE, T, Q, expected_Q, $time);
        end
        if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
    end
    endtask

    // Asynchronous controls (assert/deassert at arbitrary times)
    task async_assert_reset;  begin RST = 1'b1; PRE = 1'b0; #1; log_case(); end endtask
    task async_release_reset; begin RST = 1'b0;             #1; log_case(); end endtask
    task async_assert_preset; begin PRE = 1'b1; RST = 1'b0; #1; log_case(); end endtask
    task async_release_preset;begin PRE = 1'b0;             #1; log_case(); end endtask

    // Synchronous capture: drive T on negedge, check after posedge
    task capture_cycle;
        input t_val;
    begin
        @(negedge CLK);
        T = t_val;
        @(posedge CLK); #1;
        log_case();
    end
    endtask

    initial begin
        // Start with unknown like real silicon; first async event defines it
        RST = 1'b0; PRE = 1'b0; T = 1'b0; expected_Q = 1'bx;
        @(negedge CLK);

        // Bring to known state and exercise behavior
        async_assert_reset();        // Q -> 0 immediately
        async_release_reset();

        capture_cycle(1'b1);         // toggle to 1
        async_assert_preset();       // force 1 immediately
        async_release_preset();
        capture_cycle(1'b1);         // toggle to 0

        // Simultaneous asserts: reset must dominate preset
        RST = 1'b0; PRE = 1'b0; #1;
        RST = 1'b1; PRE = 1'b1; #1;  // both high -> Q must be 0
        log_case();
        async_release_reset();       // keep PRE=1
        async_release_preset();

        // More captures
        capture_cycle(1'b0);         // hold
        capture_cycle(1'b1);         // toggle

        // Exhaustive two-step over {RST,PRE,T} with RST/PRE low for captures
        RST = 1'b0; PRE = 1'b0;
        for (i=0; i<2; i=i+1) begin
            capture_cycle(i[0]);
            for (j=0; j<2; j=j+1)
                capture_cycle(j[0]);
        end

        // Randomized sequences mixing async and sync behavior
        for (i=0; i<6; i=i+1) begin
            if ($random) async_assert_reset();  else async_release_reset();
            if ($random) async_assert_preset(); else async_release_preset();
            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