29. 4-Input NAND Gate Primitive

module nand4_prim (
    input  a,
    input  b,
    input  c,
    input  d,
    output y
);
    nand g_nand (y, a, b, c, d);
endmodule

💡Remember

  • NAND is simply the negation of an AND.
  • The first port is always the output, followed by inputs.
  • Gate primitives support multiple inputs, and the logic follows the 4-state Verilog truth table.
  • With unknowns: nand(1,1,1,x)~x = x.

Testbench Code

`timescale 1ns/1ps

module tb_nand4_prim;
    // 1) Inputs
    reg a, b, c, d;

    // 2) DUT output
    wire y;

    // 3) Expected (prefixed expected_)
    reg expected_y;

    // 4) Mismatch (HIGH on fail) — wire so it never floats 'x'
    wire mismatch = (y !== expected_y);

    // Counters
    integer TOTAL_TEST_CASES        = 0;
    integer TOTAL_PASSED_TEST_CASES = 0;
    integer TOTAL_FAILED_TEST_CASES = 0;

    // VCD limit
    integer VCD_MAX_CASES = 32;

    // DUT
    nand4_prim dut(.a(a), .b(b), .c(c), .d(d), .y(y));

    // VCD dump (Inputs -> Outputs -> Expected -> Mismatch)
    initial begin
        $dumpfile("tb_nand4_prim.vcd");
        $dumpvars(0,
            tb_nand4_prim.a, tb_nand4_prim.b, tb_nand4_prim.c, tb_nand4_prim.d, // Inputs
            tb_nand4_prim.y,                                                   // Output
            tb_nand4_prim.expected_y,                                          // Expected
            tb_nand4_prim.mismatch                                             // Mismatch
        );
        $dumpon; // start at time 0
    end

    // Nice printing for 4-state values
    function [7*8-1:0] bit2s;
        input bitval;
        begin
            if      (bitval === 1'b0) bit2s = "0";
            else if (bitval === 1'b1) bit2s = "1";
            else if (bitval === 1'bx) bit2s = "x";
            else                      bit2s = "z";
        end
    endfunction

    // Header + init
    initial begin
        a=0; b=0; c=0; d=0; expected_y = ~(a & b & c & d);
        $display(" a b c d | y | expected | mismatch");
        $display("-----------------------------------");
    end

    // Apply + check (EXPECTED FIRST -> WAIT -> COMPARE)
    task apply_and_check;
        input ta, tb, tc, td;
        begin
            a = ta; b = tb; c = tc; d = td;

            // compute expected FIRST (avoids transient X on mismatch)
            expected_y = ~(ta & tb & tc & td);

            #1; // settle DUT

            TOTAL_TEST_CASES = TOTAL_TEST_CASES + 1;
            if (!mismatch) TOTAL_PASSED_TEST_CASES = TOTAL_PASSED_TEST_CASES + 1;
            else           TOTAL_FAILED_TEST_CASES = TOTAL_FAILED_TEST_CASES + 1;

            $display(" %s %s %s %s | %s |    %s    |    %0d",
                     bit2s(a), bit2s(b), bit2s(c), bit2s(d),
                     bit2s(y), bit2s(expected_y), mismatch);

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

    integer i;
    initial begin
        // Truth table for all 0/1 combos (16 rows)
        for (i=0; i<16; i=i+1)
            apply_and_check(i[0], i[1], i[2], i[3]);

        // A few X/Z cases (3 rows; total printed rows = 19)
        apply_and_check(1'b1,1'b1,1'b1,1'bx);
        apply_and_check(1'b0,1'bx,1'b1,1'b1);
        apply_and_check(1'bz,1'b1,1'b1,1'b1);

        // Summary
        $display("-----------------------------------");
        $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