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

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

// Test constraint with conditional dist operator

class DistScalar;
  rand bit [7:0] x;
  rand bit mode;  // 0: favor zeros (weight 3:1), 1: favor max (weight 1:3)
  constraint c {
    if (mode) {
      x dist { 8'd0 := 1, 8'd255 := 3 };  // Favor 255
    } else {
      x dist { 8'd0 := 3, 8'd255 := 1 };  // Favor 0
    }
  }

  function void display(int trial);
    $display("Trial %0d: mode=%b, x=%0d (0x%02x)", trial, mode, x, x);
  endfunction
endclass

module t;
  DistScalar obj;
  int mode1_zeros = 0;      // Count of zeros when mode=1 (favor 255)
  int mode1_maxes = 0;      // Count of 255s when mode=1 (favor 255)
  int mode0_zeros = 0;      // Count of zeros when mode=0 (favor 0)
  int mode0_maxes = 0;      // Count of 255s when mode=0 (favor 0)
  int mode1_trials = 0;     // Total trials with mode=1
  int mode0_trials = 0;     // Total trials with mode=0

  // Verify distribution ratio matches expected range
  function void check_distribution(int trials, int match_count, string match_name,
                                    int expected_pct, string mode_name);
    int actual_pct;
    int lower_bound;
    int upper_bound;

    if (trials <= 0) return;

    actual_pct = (match_count * 100) / trials;
    $display("  %s %s ratio: %0d/%0d = %0d%% (expected ~%0d%%)",
             mode_name, match_name, match_count, trials, actual_pct, expected_pct);

    // Allow +/-15% deviation from expected ratio
    lower_bound = expected_pct - 15;
    upper_bound = expected_pct + 15;

    if (actual_pct >= lower_bound && actual_pct <= upper_bound) begin
      $display("Distribution OK");
    end else begin
      $display("WARNING: Distribution appears off (expected %0d+/-15%%)", expected_pct);
      $stop;
    end
  endfunction

  initial begin
    int p;
    obj = new;

    // Run multiple trials to verify distribution
    for (int i = 0; i < 1000; i++) begin
      p = obj.randomize();
      `checkd(p, 1);

      if (i < 10) obj.display(i);

      // Track distribution based on mode value
      if (obj.mode) begin
        mode1_trials++;
        if (obj.x == 8'd0) mode1_zeros++;
        else if (obj.x == 8'd255) mode1_maxes++;
      end else begin
        mode0_trials++;
        if (obj.x == 8'd0) mode0_zeros++;
        else if (obj.x == 8'd255) mode0_maxes++;
      end
    end

    $display("");
    $display("Statistics after 1000 trials:");
    $display("  Mode 1 (favor 255): trials=%0d, zeros=%0d, maxes=%0d",
             mode1_trials, mode1_zeros, mode1_maxes);
    $display("  Mode 0 (favor 0):   trials=%0d, zeros=%0d, maxes=%0d",
             mode0_trials, mode0_zeros, mode0_maxes);

    $display("");
    $display("Distribution Verification:");
    // Mode 1: x dist { 0 := 1, 255 := 3 } means 25% for 0, 75% for 255
    check_distribution(mode1_trials, mode1_maxes, "maxes", 75, "Mode 1");

    // Mode 0: x dist { 0 := 3, 255 := 1 } means 75% for 0, 25% for 255
    check_distribution(mode0_trials, mode0_zeros, "zeros", 75, "Mode 0");

    $display("");
    $display("PASSED: Conditional dist constraint test");
    $write("*-* All Finished *-*\n");
    $finish;
  end
endmodule
