// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain
// SPDX-FileCopyrightText: 2026 Matthew Ballance
// SPDX-License-Identifier: CC0-1.0

// Test default bins - catch-all for values not in other bins

// verilog_format: off
`define stop $stop
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d:  got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on

// Non-covergroup class in the same module - must not interfere with covergroup processing
class DataHelper;
  bit [7:0] val;
  function new(bit [7:0] v); val = v; endfunction
endclass

module t;
  bit [7:0] data;
  logic [1:0] idx;
  logic [63:0] data64;
  logic [64:0] data65;
  DataHelper helper;

  // Signals for the unlabeled-coverpoint covergroups below
  logic [1:0] a;
  logic [1:0] b;
  typedef struct packed {
    logic [1:0] hi;
    logic [1:0] lo;
  } pair_t;
  pair_t p;

  covergroup cg;
    coverpoint data {
      bins low = {[0:3]};
      bins high = {[12:15]};
      bins other = default;  // Catches everything else (4-11, 16+)
    }
  endgroup

  // Covergroup with default as the only bin - catches all sampled values
  covergroup cg2;
    cp_only_default: coverpoint data {
      bins all = default;
    }
  endgroup

  // Covergroup with default + ignore + illegal bins - excluded values must not count toward coverage
  covergroup cg3;
    coverpoint data {
      ignore_bins  bad = {255};  // excluded from coverage
      illegal_bins err = {254};  // illegal value, excluded from coverage
      bins normal = {[1:10]};
      bins other = default;
    }
  endgroup

  // Auto-bins on a small range with one value excluded by ignore_bins -
  // when the range is small enough, one auto-bin per valid value is created; the excluded value is skipped.
  covergroup cg4;
    cp_idx: coverpoint idx {
      ignore_bins skip = {2};  // value 2 excluded; auto-bins created for 0,1,3
    }
  endgroup

  // 64-bit signal with auto_bin_max=4
  covergroup cg5;
    cp_data64: coverpoint data64 { bins auto[4]; }
  endgroup

  // 65-bit signal with explicit range bins
  covergroup cg6;
    cp_data65: coverpoint data65 { bins lo = {[0:15]}; bins hi = {[100:200]}; }
  endgroup

  // Unlabeled coverpoint - the signal name is used as the coverpoint name
  covergroup cg7;
    coverpoint data { bins lo = {[0:7]}; bins hi = {[8:15]}; }
  endgroup

  // Multiple unlabeled coverpoints: each gets a unique deterministic name (the variable
  // name for a single identifier).  Previously two unlabeled coverpoints in one covergroup
  // collided on the generated bin-variable name (e.g. duplicate '__Vcov__auto_0').
  covergroup cg_plain;
    option.auto_bin_max = 2;
    coverpoint a;
    coverpoint b;
  endgroup

  // Unlabeled coverpoints with compound (member-select) expressions get synthesized names.
  covergroup cg_member;
    option.auto_bin_max = 2;
    coverpoint p.lo;
    coverpoint p.hi;
  endgroup

  // A cross referencing unlabeled coverpoints by their derived names.
  covergroup cg_cross;
    option.auto_bin_max = 2;
    coverpoint a;
    coverpoint b;
    ab: cross a, b;
  endgroup

  initial begin
    cg  cg_inst;
    cg2 cg2_inst;
    cg3 cg3_inst;
    cg4 cg4_inst;
    cg5 cg5_inst;
    cg6 cg6_inst;
    cg7 cg7_inst;
    cg_plain  cg_plain_inst;
    cg_member cg_member_inst;
    cg_cross  cg_cross_inst;

    cg_inst = new();
    cg2_inst = new();
    cg3_inst = new();
    cg4_inst = new();
    cg5_inst = new();
    cg6_inst = new();
    cg7_inst = new();
    cg_plain_inst = new();
    cg_member_inst = new();
    cg_cross_inst = new();
    helper = new(8'h42);
    data = helper.val;  // Use helper to avoid optimization

    // Hit low bin
    data = 2;
    cg_inst.sample();
    cg2_inst.sample();
    `checkr(cg2_inst.get_inst_coverage(), 100.0);  // cg2 has 1 bin (default) -> 100% after first sample

    // Hit high bin
    data = 14;
    cg_inst.sample();
    cg2_inst.sample();

    // Hit default bin with value 7 (not in low or high)
    data = 7;
    cg_inst.sample();
    cg2_inst.sample();
    `checkr(cg_inst.get_inst_coverage(), 100.0);  // all 3 bins (low, high, other) hit

    // Hit another default value (should not increase coverage)
    data = 20;
    cg_inst.sample();
    cg2_inst.sample();
    `checkr(cg_inst.get_inst_coverage(), 100.0);
    `checkr(cg2_inst.get_inst_coverage(), 100.0);

    // Sample cg3: verify ignore/illegal bins do not contribute to coverage
    data = 2;
    cg3_inst.sample();  // hits normal bin
    `checkr(cg3_inst.get_inst_coverage(), 100.0);  // 1/1: only 'normal' counts (default/ignore/illegal excluded, LRM 19.5)
    data = 7;
    cg3_inst.sample();  // hits normal bin again
    `checkr(cg3_inst.get_inst_coverage(), 100.0);  // no new normal bins
    data = 255;
    cg3_inst.sample();  // ignore_bins value; recorded but excluded from coverage
    `checkr(cg3_inst.get_inst_coverage(), 100.0);
    // note: do not sample 254 (illegal_bins would cause runtime assertion)
    data = 100;
    cg3_inst.sample();  // hits default (other) bin; recorded but excluded from coverage
    `checkr(cg3_inst.get_inst_coverage(), 100.0);

    // Sample cg4: auto-bins with one excluded value
    // idx=2 is in ignore_bins, so auto-bins cover 0, 1, 3 only (3 bins total)
    idx = 0; cg4_inst.sample();
    idx = 1; cg4_inst.sample();
    idx = 3; cg4_inst.sample();
    `checkr(cg4_inst.get_inst_coverage(), 100.0);

    // Sample cg5: 64-bit signal, 4 auto bins; values 0 and 5 both fall in first bin
    data64 = 0; cg5_inst.sample();
    `checkr(cg5_inst.get_inst_coverage(), 25.0);  // 1/4 bins hit
    data64 = 5; cg5_inst.sample();
    `checkr(cg5_inst.get_inst_coverage(), 25.0);  // same bin, no increase

    // Sample cg6: 65-bit signal with range bins
    data65 = 5;
    cg6_inst.sample();  // hits bin lo=[0:15]
    `checkr(cg6_inst.get_inst_coverage(), 50.0);
    data65 = 150;
    cg6_inst.sample();  // hits bin hi=[100:200]
    `checkr(cg6_inst.get_inst_coverage(), 100.0);

    // Sample cg7: unlabeled coverpoint
    data = 3;
    cg7_inst.sample();  // hits bin lo
    `checkr(cg7_inst.get_inst_coverage(), 50.0);
    data = 10;
    cg7_inst.sample();  // hits bin hi
    `checkr(cg7_inst.get_inst_coverage(), 100.0);

    // cg_plain: two unlabeled coverpoints (a, b), 2 auto bins each -> distinct names
    a = 0; b = 3; cg_plain_inst.sample();
    `checkr(cg_plain_inst.get_inst_coverage(), 50.0);
    // cg_member: unlabeled member-select coverpoints (synthesized names)
    p.lo = 0; p.hi = 3; cg_member_inst.sample();
    `checkr(cg_member_inst.get_inst_coverage(), 50.0);
    // cg_cross: cross of unlabeled coverpoints referenced by derived name
    a = 0; b = 0; cg_cross_inst.sample();
    a = 3; b = 3; cg_cross_inst.sample();

    $write("*-* All Finished *-*\n");
    $finish;
  end
endmodule
