【问题标题】:Constraining an entire object in SystemVerilog在 SystemVerilog 中约束整个对象
【发布时间】:2014-06-21 09:28:49
【问题描述】:

我正在尝试基于其他对象来约束整个对象(不仅仅是对象的字段)。这是我的生产代码的精简版:

我有以下课程:

class some_class;
  bit[7:0] some_field;
  bit[3:0] some_other_field;


  // this function would do some complex procedural
  // operations on the fields of the object
  function void do_some_op();
    bit[3:0] tmp = some_field[3:0];
    some_field[3:0] = some_other_field;
    some_other_field = some_field[7:4];
    some_field[7:4] = tmp;
  endfunction

  function some_class some_function(bit some_param);
    some_function = new this;
    $display("foo"); // this print here to see that method is executed

    if (some_param)
      some_function.do_some_op();
  endfunction

  function void print();
    $display("some_field = %x", some_field);
    $display("some_other_field = %x", some_other_field);
  endfunction
endclass // some_class

这个类包含一些完整的字段。它还有一个方法可以在该类的字段上执行一些复杂的程序。在示例中,我对其进行了简化。我还有另一个类,它返回一个已对其执行操作的新对象。

我有另一个使用some_class 实例的类。根据 Dave 的输入,我已使其首先创建对象(因为 randomize() 不创建对象)。

class some_shuffler;
  rand bit        params[];
  rand some_class objects[];

  constraint size_c {
    params.size() == objects.size() - 1;
    params.size() <= 10;
  };

  constraint shuffle_c {
    // not allowed by standard
    // foreach (params[i])
    //   objects[i+1].some_field == objects[i].some_function(params[i]);

    foreach (params[i])
      objects[i+1].some_field == 
        objects[i].some_function(params[i]).some_field &&
      objects[i+1].some_other_field ==  
        objects[i].some_function(params[i]).some_other_field;
  };

  function new();
    objects = new[10];  // create more objects than needed
    foreach (objects[i])
      objects[i] = new();

    // initialize first object
    objects[0].some_field = 8'hA5;
  endfunction // new

  function void post_randomize();
    foreach (objects[i]) begin
      $display("objects[%0d]:", i);
      objects[i].print();
      $display("");
    end
  endfunction

endclass

这个类有两个数组,一个是执行的操作,一个是中间状态。有一个初始对象。在这个上,some_function 被执行并产生下一个对象。

这就是我想要测试它的方式:

module top;
  import some_pkg::*;

  initial begin
    static some_shuffler shuffler = new();
    bit rand_ok;
    rand_ok = shuffler.randomize() with {
     params.size() == 1;
    };
    assert (rand_ok);
  end

endmodule

当试图直接约束对象时,我立即得到约束违规。模拟器似乎试图使 2 个句柄相等。无论如何,这都是标准所禁止的,我不再这样做了(尽管编译失败会很好)。我已经按照 Dave 和 Greg 的建议解开了约束(我认为 some_function().some_field 是非标准的,但它可以在 Questa 中编译)。

即使是现在,foo 打印也不会出现在命令行上(some_function() 没有被执行)。我看到的是 objects[1] 包含初始值(两个字段全为 0)。

我不能只生成参数列表,然后在程序上随机化每次迭代的对象,因为我希望能够将最后一个对象约束为具有特定值 - 基本上是为约束求解器提供开始和结束点,让它找出到达那里的方法。

【问题讨论】:

  • 这可能有助于解释显示您希望最终数据结构是什么样子的一些示例。然后你希望随机化如何在不尝试将其放入 SV 语法的情况下工作。
  • @dave_59 我正在尝试构建一个魔方求解器。我做了一个小例子,让问题更容易理解。这个想法是有一个动态的立方体状态数组和另一个移动数组。索引将代表时间步长。一个立方体在某个时间的状态取决于前一个立方体的移动和状态。我想看看约束求解器是否可以找到洗牌立方体的解决方案。
  • 我已经通过在我的对象中使用pack()unpack() 方法并使用比特流而不是对象来解决这个问题。类似于cube_stream[i+1] == turn_cube(cube_stream[i].pack, turn[i]),其中turn_cube() 将使用unpack() 创建一个立方体。
  • 无论如何都没有用,因为就像你说的,求解器将方法的输入视为状态变量。最后,它基本上只是在做愚蠢的猜测。它甚至无法解决仅洗牌 3 次的立方体。

标签: system-verilog


【解决方案1】:

在 SystemVerilog 中不允许对象与对象约束,因为它们不是整数类型。请参阅IEEE Std 1800-2012 § 18.3:

  • 约束可以是任何具有整型变量和常量的 SystemVerilog 表达式(例如,bitreglogicintegerenumpacked struct)。

如果组件是rand(例如obj[1].value == obj[0].value+1;),您可以约束类对象的整体组件。

约束中允许使用函数,但有限制。请参阅IEEE Std 1800-2012 § 18.5.12 约束中的函数了解完整的详细信息。限制包括:

  • 函数不能包含outputref 参数
  • 函数应该是自动的并且没有副作用
  • 函数参数具有隐式优先级(例如 x&lt;=F(y) 推断 solve y before x
  • 循环依赖会导致错误

更新:

看起来唯一真正被随机化的是paramssome_field 和 some_other_fieldare calculations. So it makes more sense to move the loop for shuffling into thepost_randomize 函数的值。

constraint size_c {
  params.size() == objects.size() - 1;
  params.size() <= 10;
};

function void postrand_shuffle();
  foreach (params[i])
    objects[i+1] = objects[i].some_function(params[i]);
endfunction

function void post_randomize();
  postrand_shuffle();
  // ... your other post_rand code...
endfunction

SystemVerilog 的随机约束求解器将在至少有一个解决方案时工作。但是,当解决方案空间较小且难以确定或链较长时,模拟器性能会下降。对于这些场景,最好将一对一的顺序计算移至post_randomize

【讨论】:

  • 我已经更新了问题以考虑到这一点,但它仍然不起作用。
  • 看起来object[i+1]object[i]param[i] 的函数,没有随机变化。在这种情况下,将计算移至post_randomize 会更适合您。我已经更新了我的答案。
  • 我希望求解器做一些回溯。例如,如果我已经对项目 2 有一个约束,它会返回并解析项目 1 和 2,以便链满足这个约束。然而,由于方法约束的单向性,它不会。我还不如直接使用post_randomize()
【解决方案2】:

您的示例代码存在一些问题。

  • 在调用randomize() 之前必须先构造对象。如果 您在调用 randomize 之前知道确切的大小(例如在您的 例如),只是new[n] 构造每个对象的动态数组 元素第一,并删除大小限制。如果尺寸是 随机,您需要对大小进行上限约束。构造最大值 调用randomize()之前的对象数量,随机化数组后,未使用的对象将被淘汰。
  • 约束表达式必须是整数。 objects[i+1].some_field == objects[i].some_field 可以,但求解器无法操作类句柄。
  • 函数的返回值被视为状态变量。将这些移至 post_randomize

【讨论】:

  • 很高兴看到 Questa 为 obj[i] == obj[i] 东西发出编译错误。
  • 展开约束以对对象的字段进行操作后,我看到 some_function() 不再被调用(添加了调试打印和整个对象列表的打印)。我也使用此信息更新了问题。
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-11
  • 1970-01-01
相关资源
最近更新 更多