约束问题:在具有特定数字匹配的数组中选择数字

Constraint issue: pick number within array with specific number match

这是我上次面试的问题如下:

问。 (约束随机化)考虑这个page

的彩票规则

以下是我的代码link to EDA playground:

测试台:

module tb;
    initial begin
      Pick    p = new();
      p.randomize();

      $display("\nPicked result:");
      for (int i=0; i<`NUM_JACKPOT; i++)
        $write("%0d ", p.jackpot_result[i]);
      $write("\n");
      
    end
endmodule

设计代码:

`define NUM_JACKPOT  6

class Lottery;
  randc int six_jackpot_nums[`NUM_JACKPOT];
  
  constraint rand_jackpot {
    foreach (six_jackpot_nums[i])
      six_jackpot_nums[i] inside {[1:49]};
  }
endclass

class Pick;

  randc int six_jackpot_nums[`NUM_JACKPOT];
  randc int jackpot_result  [`NUM_JACKPOT];
        int award_2nd_hi = `NUM_JACKPOT -1;
 
  function pre_randomize();
    Lottery l = new();
    l.randomize();
    $display("Jackpot bingo:");
    for (int i=0; i<`NUM_JACKPOT; i++) begin
      six_jackpot_nums[i] = l.six_jackpot_nums[i];
      $write("%0d ", l.six_jackpot_nums[i]);
    end
  endfunction 
  
  constraint pick_jackpot{
    foreach (jackpot_result[i])
      jackpot_result[i] inside {[1:49]};      
    award_2nd_hi == (match(jackpot_result[0])+match(jackpot_result[1])+match(jackpot_result[2])+match(jackpot_result[3])+match(jackpot_result[4])+match(jackpot_result[5]));
  }
  
  function int match(int v);
    int tmp[$];
    tmp = six_jackpot_nums.find(x) with (x == v);
    if(tmp.size != 0) return 1;
    return 0;
  endfunction
  
  
endclass

以目前的状态,我可以成功创建六号头奖。然而,当我创建第二高的数字对时,我遇到了冲突。请指教

结果:

xmsim: *W,RNDOCS: These constraints contribute to the set of conflicting constraints:

    award_2nd_hi == (match(jackpot_result[0])+match(jackpot_result[1])+match(jackpot_result[2])+match(jackpot_result[3])+match(jackpot_result[4])+match(jackpot_result[5])); (./design.sv,31)

xmsim: *W,RNDOCS: These variables contribute to the set of conflicting constraints:


Var_Name                          Type   Status        Current_Value          Source                 
-----------------------------------------------------------------------------------------------------
award_2nd_hi                      (S32)  STATE VAR     5 (0x5)                ./design.sv ; line 16
jackpot_result[0]                 (S32)  SOLVED EARLY  32 (0x20)              ./design.sv ; line 15
jackpot_result[1]                 (S32)  SOLVED EARLY  47 (0x2f)              ./design.sv ; line 15
jackpot_result[2]                 (S32)  SOLVED EARLY  21 (0x15)              ./design.sv ; line 15
jackpot_result[3]                 (S32)  SOLVED EARLY  40 (0x28)              ./design.sv ; line 15
jackpot_result[4]                 (S32)  SOLVED EARLY  1 (0x1)                ./design.sv ; line 15
jackpot_result[5]                 (S32)  SOLVED EARLY  27 (0x1b)              ./design.sv ; line 15
match( .v( jackpot_result[0] ) )  (S32)  SOLVED EARLY  0 (0x0)                ./design.sv ; line 31
match( .v( jackpot_result[1] ) )  (S32)  SOLVED EARLY  1 (0x1)                ./design.sv ; line 31
match( .v( jackpot_result[2] ) )  (S32)  SOLVED EARLY  0 (0x0)                ./design.sv ; line 31
match( .v( jackpot_result[3] ) )  (S32)  SOLVED EARLY  0 (0x0)                ./design.sv ; line 31
match( .v( jackpot_result[4] ) )  (S32)  SOLVED EARLY  0 (0x0)                ./design.sv ; line 31
match( .v( jackpot_result[5] ) )  (S32)  SOLVED EARLY  0 (0x0)                ./design.sv ; line 31


Jackpot bingo:
31 49 43 24 47 8
Picked result:
0 0 0 0 0 0 

这是一种更简单的方法,可以避免所有警告(以及其他模拟器上的错误)。随机生成一组 6 个获胜者。此外,随机选择一个获胜者,用失败的号码代替。使用 post_randomize,创建一组失败者,然后随机选择其中一个并替换其中一个获胜者。

`define NUM_JACKPOT  6

class Lottery;
    rand  int six_jackpot_nums[`NUM_JACKPOT];
          int jackpot_result  [`NUM_JACKPOT];
          int losers          [$];
    rand int unsigned idx;

    function void post_randomize;
        for (int i=1; i<50; i++) begin
            if (!(i inside {six_jackpot_nums})) losers.push_back(i);
        end
        losers.shuffle();
        for (int i=0; i<`NUM_JACKPOT; i++) begin
            jackpot_result[i] = (i == idx) ? losers[0] : six_jackpot_nums[i];
        end
    endfunction 

    constraint rand_jackpot {
        unique {six_jackpot_nums};
        foreach (six_jackpot_nums[i]) six_jackpot_nums[i] inside {[1:49]};
        idx inside {[1:`NUM_JACKPOT]};
    }
endclass

module tb;
    Lottery lot;
    initial begin
        lot = new();
        void'(lot.randomize());
        $display("\nPicked result:");
        for (int i=0; i<`NUM_JACKPOT; i++) $write("%0d ", lot.six_jackpot_nums[i]);
        $display("\nJackpot bingo:");
        for (int i=0; i<`NUM_JACKPOT; i++) $write("%0d ", lot.jackpot_result  [i]);
        $display;
    end
endmodule

示例输出:

Picked result:
48 4 46 3 17 16 
Jackpot bingo:
48 4 21 3 17 16 

这里,46被21代替了。


要解决 中提到的 randc 问题,请使用 unique 约束关键字。

声明 randc 不能保证数组元素在单一随机化中是唯一的。所以我添加了一个约束 unique_cons 来解决这个问题。

`define NUM_JACKPOT  6

class Lottery;
  rand int six_jackpot_nums[`NUM_JACKPOT];
  rand int jackpot_result  [`NUM_JACKPOT];
  rand int missed;
  
  constraint unique_cons {
    foreach (six_jackpot_nums[i])
      foreach(six_jackpot_nums[j])  
        if(i!=j) six_jackpot_nums[i]!=six_jackpot_nums[j];      
  }
  
  constraint valid_cons {
    foreach (six_jackpot_nums[i]){
      six_jackpot_nums[i] inside {[1:49]};
      jackpot_result[i] inside {[1:49]};
    }
  }
  constraint missed_cons {
    missed inside {[0:`NUM_JACKPOT-1]} ;    
       
  }
  constraint rand_jackpot {
    foreach (six_jackpot_nums[i])
      if(i==missed) 
        ~(jackpot_result[i] inside {six_jackpot_nums});
      else 
        jackpot_result[i] == six_jackpot_nums[i];
  } 
  
endclass

结果:

Jackpot bingo:
30 44 12 37 1 22 
Picked result:
30 44 12 37 1 9 
Jackpot bingo:
40 12 20 46 8 2 
Picked result:
40 12 20 5 8 2 
Jackpot bingo:
29 23 13 41 48 28 
Picked result:
29 39 13 41 48 28 
Jackpot bingo:
8 14 35 19 28 39 
Picked result:
8 20 35 19 28 39 

第一个答案的好电话,unique 约束关键字已在 systemverilog-2012 中启用。

您应该尽可能寻找避免 pre/post_randomize() 的解决方案。这使得在一次解决所有约束和随机变量时更容易覆盖或添加更多约束。

parameter int JACKPOT_NUM = 6;

class Lottery;
  rand int six_jackpot_nums[JACKPOT_NUM];
  rand int pick_result_nums[JACKPOT_NUM];
  
  constraint jack_rand {
    unique {six_jackpot_nums};
    foreach(six_jackpot_nums[i]) six_jackpot_nums[i] inside {[1:49]};
    unique {pick_result_nums};
    foreach(pick_result_nums[i]) pick_result_nums[i] inside {[1:49]};
  }
  constraint pick5 {
    pick_result_nums.sum() with (int'(item == six_jackpot_nums[item.index])) == 5;
  }
 
endclass

module tb;
    initial begin
      static Lottery l = new();
      repeat(3) begin
        assert(l.randomize());
        $display("\nBingo result:");
        foreach(l.six_jackpot_nums[i])
          $write("%0d ", l.six_jackpot_nums[i]);
        $display("\nPicked result:");
        foreach(l.six_jackpot_nums[i])
          $write("%0d ", l.pick_result_nums[i]);
        $write("\n");
      end
      
    end
endmodule

这样做可以让您添加更多限制条件,例如“不匹配的所选号码必须比中奖号码大一”。这当然使 49 不会被选为错过的累积奖金号码,但它也不会错过任何两个连续累积奖金号码中的第一个。