44. Population Count

Design a combinational module that counts how many bits in an 8-bit input are 1. Use a synthesizable for loop (constant bounds).

Requirements

  • Module: popcount8
  • Inputs: in[7:0]
  • Outputs: count[3:0] (range 0–8)
  • Implement in one always @* using a for loop and an integer loop variable.
  • Provide a default/initialization for count inside the block (avoid latches).
  • No delays/timing controls in the design.

Behavior

  • in = 8'b0000_0000count = 0
  • in = 8'b1111_1111count = 8
  • Works for any 8-bit input.

Testbench Code

`timescale 1ns/1ps

module tb_popcount8;
    // 1) Inputs
    reg  [7:0] in;

    // 2) DUT outputs
    wire [3:0] count;

    // 3) Expected (prefixed expected_)
    reg  [3:0] expected_count;

    // 4) Mismatch (HIGH on fail)
    reg  mismatch;
    wire mismatch_w = (count !== expected_count);

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

    // VCD control
    integer VCD_MAX_CASES = 32;

    // Random seed (change to vary randomized cases)
    integer seed;
    initial seed = 32'hA1B2_C3D4 ^ $time;

    // DUT
    popcount8 dut(.in(in), .count(count));

    // ---------- Golden model (popcount in TB) ----------
    function [3:0] f_popcount8(input [7:0] x);
        integer i;
        begin
            f_popcount8 = 4'd0;
            for (i = 0; i < 8; i = i + 1)
                f_popcount8 = f_popcount8 + x[i];
        end
    endfunction

    // VCD dump (Inputs -> Outputs -> Expected -> Mismatch)
    initial begin
        $dumpfile("tb_popcount8.vcd");
        $dumpvars(0,
            tb_popcount8.in,                // Inputs
            tb_popcount8.count,             // Outputs
            tb_popcount8.expected_count,    // Expected
            tb_popcount8.mismatch           // Mismatch
        );
        $dumpon; // start at #0
    end

    // Init + (short) table header
    initial begin
        in = 8'h00; expected_count = 4'd0; mismatch = 1'b0;
        $display("  in    | count | expected_count | mismatch");
        $display("-------------------------------------------");
    end

    // Apply vector, compute expected, compare
    task apply_and_check;
        input [7:0] t_in;
        input       print_row; // 1 = print this case, 0 = silent
        begin
            in = t_in;

            // Compute expected FIRST to avoid mismatch glitches in VCD
            expected_count = f_popcount8(t_in);

            #1; // let DUT settle

            mismatch = mismatch_w;

            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;

            if (print_row) begin
                $display("0x%02h  |  0x%01h  |       0x%01h      |    %0d",
                         in, count, expected_count, mismatch);
            end

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

    // Stimulus
    integer i;
    initial begin
        // Directed: full small truth table (0..15)
        for (i = 0; i < 16; i = i + 1)
            apply_and_check(i[7:0], 1'b1);

        // More directed edges (printed)
        apply_and_check(8'h00, 1'b1); // all 0s
        apply_and_check(8'hFF, 1'b1); // all 1s
        apply_and_check(8'h0F, 1'b1); // lower half ones
        apply_and_check(8'hF0, 1'b1); // upper half ones

        // Randomized tests (silent to avoid long tables)
        repeat (40) apply_and_check($random(seed), 1'b0);

        // Summary logs
        $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