65. D Latch with Enable-Synchronous Reset

Behavioral (recommended)

module d_latch_en_sync_reset (
    input  EN,
    input  RST,
    input  D,
    output reg Q
);
    always @(EN or RST or D) begin
        if (EN) begin
            if (RST) Q <= 1'b0;
            else     Q <= D;
        end else begin
            Q <= Q;
        end
    end
endmodule

💡Remember

  • Level-sensitive latch is inferred via incomplete assignment in the hold path.
  • Reset is honored only while EN=1.
  • Nonblocking assignments (<=) express storage semantics.
  • No power-up value is assumed; drive an initial vector in the testbench.

 

Data-flow (mux feedback)

module d_latch_en_sync_reset (
    input  EN,
    input  RST,
    input  D,
    output Q
);
    wire d_sel = RST ? 1'b0 : D;
    assign Q = EN ? d_sel : Q;
endmodule

💡Remember

  • Expresses Q = EN ? (RST ? 0 : D) : Q.
  • Functionally identical; some tools warn on feedback nets.
  • Preferred style for synthesis is the behavioral model.

Testbench Code

`timescale 1ns/1ps

module tb_d_latch_en_sync_reset;
    // 1) Inputs
    reg EN, RST, D;
    // 2) Outputs
    wire Q;
    // 3) Expected outputs
    reg  expected_Q;
    // 4) Mismatch
    wire mismatch;

    d_latch_en_sync_reset dut(.EN(EN), .RST(RST), .D(D), .Q(Q));

    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;

    initial begin
        $dumpfile("tb_d_latch_en_sync_reset.vcd");
        $dumpvars(0,
            tb_d_latch_en_sync_reset.EN,
            tb_d_latch_en_sync_reset.RST,
            tb_d_latch_en_sync_reset.D,
            tb_d_latch_en_sync_reset.Q,
            tb_d_latch_en_sync_reset.expected_Q,
            tb_d_latch_en_sync_reset.mismatch
        );
        $dumpon;
    end

    function next_q;
        input en_v, rst_v, d_v, cur_q;
        reg n;
    begin
        n = cur_q;
        if (en_v) begin
            if (rst_v) n = 1'b0;
            else       n = d_v;
        end
        next_q = n;
    end
    endfunction

    task apply_and_check;
        input [127:0] name;
        input en_v, rst_v, d_v;
        reg n;
    begin
        EN  = en_v; RST = rst_v; D = d_v;
        n = next_q(en_v, rst_v, d_v, expected_Q);
        expected_Q = n;
        #1;
        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 EN=%b RST=%b D=%b Q=%b expected_Q=%b t=%0t",
                         name, EN, RST, D, Q, expected_Q, $time);
        end
        if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
    end
    endtask

    task print_truth_table;
        integer e,r,dv;
        reg curQ, nxt;
    begin
        curQ = expected_Q;
        $display(" EN RST D | EXP_Q");
        $display("-----------------");
        for (e=0;e<2;e=e+1)
            for (r=0;r<2;r=r+1)
                for (dv=0;dv<2;dv=dv+1) begin
                    nxt = next_q(e[0], r[0], dv[0], curQ);
                    $display("  %0d  %0d  %0d |   %0d", e, r, dv, nxt);
                end
    end
    endtask

    initial begin
        EN=1'b1; RST=1'b1; D=1'b1; expected_Q=1'b0; #1;
        EN=1'b1; RST=1'b0; D=1'b0;                   #1;

        apply_and_check("reset_enabled" , 1'b1, 1'b1, 1'b1);
        apply_and_check("capture_one"   , 1'b1, 1'b0, 1'b1);
        apply_and_check("disabled_rst"  , 1'b0, 1'b1, 1'b0);
        apply_and_check("disabled_hold" , 1'b0, 1'b0, 1'b1);
        apply_and_check("reset_again"   , 1'b1, 1'b1, 1'b0);
        apply_and_check("capture_zero"  , 1'b1, 1'b0, 1'b0);

        for (i=0;i<8;i=i+1) begin
            apply_and_check("prev_vec", i[2], i[1], i[0]);
            for (j=0;j<8;j=j+1)
                apply_and_check("next_vec", j[2], j[1], j[0]);
        end

        for (i=0;i<100;i=i+1)
            apply_and_check("rand", $random, $random, $random);

        print_truth_table();

        $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