Home Articles

在SystemVerilog中约束整个对象

Asked
Viewed 1830 times
5

我试图基于其他一些对象约束整个对象(而不仅仅是对象的字段) . 这是我的 生产环境 代码的精简版:

我有以下课程:

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) .

我不能只生成参数列表然后在程序上随机化每个迭代的对象,因为我希望能够约束最后一个对象具有一定的值 - 基本上给予约束求解器起点和终点并让它找到了到达那里的方法 .

2 Answers

  • 4

    SystemVerilog中不允许使用对象与对象约束,因为它们不是整数类型 . 见IEEE Std 1800-2012§18.3:

    约束可以是具有变量和整数类型常量的任何SystemVerilog表达式(例如,bit,reg,logic,integer,enum,packed struct) .

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

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

    • 函数不能包含 outputref 参数

    • 功能应该是自动的,不会产生副作用

    • 函数参数具有隐式优先级(ex x<=F(y) infers solve y before x

    • 循环依赖将导致错误


    更新:

    看起来真正被随机化的唯一事情是 params . some_field 和some_other_field are calculations. So it makes more sense to move the loop for shuffling into the post_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 .

  • 3

    您的示例代码有几个问题 .

    • 必须在调用 randomize() 之前先构造对象 . 如果在调用randomize之前知道确切的大小(比如在你的例子中),那么首先只需构造每个对象元素的动态数组,然后删除大小约束 . 如果大小是随机的,则需要对大小设置上限 . 在调用randomize()之前构造最大对象数,并且在随机化数组之后,将消除未使用的对象 .

    • 约束表达式必须是整数 . 您可以执行 objects[i+1].some_field == objects[i].some_field 但解算器无法操作类句柄 .

    • 函数的返回值被视为状态变量 . 将它们移动到post_randomize

Related