System verilog 在SystemVerilog中约束整个对象

System verilog 在SystemVerilog中约束整个对象,system-verilog,System Verilog,我试图基于其他对象约束整个对象(不仅仅是对象的字段)。以下是我的生产代码的精简版本: 我有以下课程: 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();

我试图基于其他对象约束整个对象(不仅仅是对象的字段)。以下是我的生产代码的精简版本:

我有以下课程:

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
此类包含一些整型字段。它还有一个方法,可以对该类的字段执行一些复杂的过程。在这个例子中,我简化了它。我还有另一个类,它返回一个新对象,该对象上已经执行了操作

我有另一个类,它与
一些\u类
实例一起运行。根据Dave的输入,我让它先创建对象(因为
randomize()
不创建对象)

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

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


我不能只生成参数列表,然后在每次迭代中按程序随机化对象,因为我希望能够约束最后一个对象,使其具有特定的值—基本上是为约束解算器提供起点和终点,并让它找到到达该点的方法。

示例代码中有几个问题

  • 在调用
    randomize()
    之前,必须先构造对象。如果 在调用randomize之前,您知道确切的大小(如在 示例),只需
    new[n]
    构建每个对象的动态数组 元素,并删除大小约束。如果尺寸合适的话 “随机”,您需要对大小设置上限约束。构造最大值 调用randomize()之前和随机化数组之后的对象数,将消除未使用的对象
  • 约束表达式必须是整数。您可以执行
    对象[i+1]。某些\u字段==对象[i]。某些\u字段
    ,但解算器无法操纵类句柄
  • 函数的返回值被视为状态变量。将这些移动到post_随机化

SystemVerilog中不允许对象与对象约束,因为它们不是整数类型。见§18.3:

  • 约束可以是具有整数类型的变量和常量的任何SystemVerilog表达式(例如,
    reg
    逻辑
    整数
    枚举
    压缩结构
如果类对象的整体组件是
rand
(例如
obj[1]。value==obj[0]。value+1;
),则可以约束该类对象的整体组件

约束中允许使用函数,但存在限制。有关详细信息,请参见约束中的§18.5.12功能。限制包括:

  • 函数不能包含
    output
    ref
    参数
  • 功能应该是自动的,没有副作用

  • 函数参数具有隐式优先级(例如
    x如果看到Questa为
    obj[i]==obj[i]
    对象发出编译错误会很好。在展开约束以对对象字段进行操作后,我看到
    some_function()
    不再被调用(添加了调试打印和整个对象列表的打印)。我也用此信息更新了问题。我更新了问题以考虑到这一点,但仍然不起作用。看起来
    object[I+1]
    object[I]
    param[I]的函数
    ,没有随机变化。在这种情况下,将计算移动到
    后随机
    将更适合您。我已更新了我的答案。我希望解算器进行一些回溯。例如,如果我对项目2已有约束,它将返回并解析项目1和2,以便链满足此约束当然不是。但是,由于方法约束的单向性,我可能只使用
    post_randomize()
    。这可能有助于解释显示几个示例,说明您希望最终的数据结构是什么样子的。然后,您希望如何在不尝试将其放入SV语法的情况下进行随机化。@dave_59我正在尝试构建一个魔方解算器。我制作了一个小示例,以使问题更易于理解。其想法是要有一个动态arra多维数据集状态的y和另一个移动数组。索引将表示时间步。多维数据集在某个时间的状态取决于移动和上一个多维数据集的状态。我想看看约束求解器是否可以找到一个混乱多维数据集的解决方案。我已经使用
    pack()
    unpack()解决了这个问题
    方法在我的对象中,使用比特流而不是对象。类似于
    cube\u-stream[i+1]==turn\u-cube(cube\u-stream[i]。pack,turn[i])
    ,其中
    turn\u-cube()
    将使用
    unpack()创建一个立方体
    。它无论如何都不起作用,因为正如您所说,解算器将方法的输入视为状态变量。最后,它基本上只是做了愚蠢的猜测。它甚至无法解出一个只洗牌3次的立方体。
    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
    
    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
    
    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