veryl-std 0.20.1

A modern hardware description language
Documentation
pub module onehot #(
    param W: u32 = 16,
) (
    i_data: input logic<W>,
    /// 1'b1 iff i_data contains exactly one set bit
    o_onehot: output logic,
    /// 1'b1 iff i_data is zero
    o_zero: output logic,
) {
    var o_gt_one: logic;

    inst u_onehot: _onehot #( W: W ) ( i_data, o_zero, o_onehot, o_gt_one );
}

module _onehot #(
    param W: u32 = 16,
) (
    i_data  : input  logic<W>,
    o_onehot: output logic   ,
    o_zero  : output logic   ,
    o_gt_one: output logic   ,
) {
    if (W == 1) :gen_base_case {
        assign o_onehot = i_data;
        assign o_zero   = ~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];
        var   onehot_top: logic      ;
        var   onehot_bot: logic      ;
        var   zero_top  : logic      ;
        var   zero_bot  : logic      ;
        var   gt_one_top: logic      ;
        var   gt_one_bot: logic      ;

        inst u_bot: _onehot #(
            W: WBOT,
        ) (
            i_data  : data_bot  ,
            o_onehot: onehot_bot,
            o_zero  : zero_bot  ,
            o_gt_one: gt_one_bot,
        );
        inst u_top: _onehot #(
            W: WTOP,
        ) (
            i_data  : data_top  ,
            o_onehot: onehot_top,
            o_zero  : zero_top  ,
            o_gt_one: gt_one_top,
        );
        assign o_zero   = zero_top & zero_bot;
        assign o_onehot = (onehot_top ^ onehot_bot) & ~gt_one_top & ~gt_one_bot;
        assign o_gt_one = gt_one_top | gt_one_bot | (onehot_top & onehot_bot);
    }

}

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

  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 o_onehot, o_zero;
    std_onehot #(i) u_dut(.*);

    initial begin
      done[i] = 1'b0;
      for (int j = 0; j < (1 << i); ++j) begin
        i_data = j;
        #1;
        assert(o_onehot == $onehot(i_data)) else begin
          $display("$onehot(%b) == %b of len %d", i_data, o_onehot, i);
        end
        assert(o_zero == (i_data == '0)) else begin
          $display("zero(%b) == %b of len %d", i_data, o_zero, i_data, i);
        end
      end
      $display("Done verifying onehot#(%2d)", i);
      done[i] = 1'b1;
    end
  end

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

endmodule
}}}