veryl-std 0.20.1

A modern hardware description language
Documentation
pub module countones #(
    param W    : u32 = 16                           ,
    const CLOGW: u32 = if W >: 1 ? $clog2(W) + 1 : 1,
) (
    i_data: input  logic<W>    ,
    o_ones: output logic<CLOGW>,
) {
    if (W == 1) :gen_base_case {
        assign o_ones = i_data;
    } else :gen_rec_case {
        const WBOT    : u32         = W / 2;
        const WTOP    : u32         = W - WBOT;
        let   data_bot: logic<WBOT> = i_data[WBOT - 1:0];
        let   data_top: logic<WTOP> = i_data[W - 1:WBOT];

        const CLOGWBOT: u32             = if WBOT >: 1 ? $clog2(WBOT) + 1 : 1;
        const CLOGWTOP: u32             = if WTOP >: 1 ? $clog2(WTOP) + 1 : 1;
        var   ones_bot: logic<CLOGWBOT>;
        var   ones_top: logic<CLOGWTOP>;

        inst u_bot: countones #( W: WBOT ) ( i_data: data_bot, o_ones: ones_bot );
        inst u_top: countones #( W: WTOP ) ( i_data: data_top, o_ones: ones_top );
        assign o_ones = {1'b0 repeat (W - WTOP), ones_top} + {1'b0 repeat (W - WBOT), ones_bot};
        // initial {
        //     $monitor("i_data: %b, data_top: %b, data_bot: %b\n", i_data, data_top, data_bot, "o_ones: %d, ones_top: %d, ones_bot: %d\n", o_ones, ones_top, ones_bot);
        // }
    }
}

#[test(test_countones)]
embed (inline) sv{{{
module test_countones;

  parameter MIN = 1;
  parameter MAX = 20;
  logic [MAX:MIN] done;

  // initial begin $display("Hello, World!\n"); $finish; end
  for (genvar i = MIN; i <= MAX; ++i) begin : gen_duts
    bit [i-1:0] i_data;
    logic [((i > 1) ? $clog2(i) : 0):0] o_ones;
    std_countones #(i) u_dut(.*);

    initial begin
      done[i] = 1'b0;
      for (int j = 0; j < (1 << i); ++j) begin
        i_data = j;
        #1;
        assert(o_ones == $countones(i_data)) else begin
          $display("Expected %d, but got %d ones in %b of length %d", $countones(i_data), o_ones, i_data, i);
        end
      end
      $display("Done verifying countones#(%2d)", i);
      done[i] = 1'b1;
    end
  end

  always_comb begin
    if (done == '1)
      $finish;
  end

endmodule
}}}