聊聊Systemverilog中的function in constraints

有些情况下,constraint不能简单用一行来表达,而是需要复杂的计算,如果都写到constraint block内部就比较复杂,而且很乱,这时候可以调用functions来约束随机变量。在constraint内调用function就称为”function in constraints”。它的格式如下:

constraint constraint_name { rand_var == function_call(arguments...); }
  • function的定义写在constraint block之外,它内部包含了对arguments的处理。
  • 在调用randomize()的时候,function会先被求解,function的返回值将会作为state variables去参与接下来的求解。

不过在使用function in constraints有以下几点需要注意:

  • 在constraint内部调用的function不能包含output或ref类型的arguments,但是const ref是允许的;
  • 在constraint内部调用的function应该是automatic类型的;
  • 在constraint内部调用的function不能修改constraints,例如调用rand_mode或constraint_mode方法;
  • Function会先被求解,也就是它的返回值会被当作state variables。因此,function的arguments和其它rand variables会隐含建立求解order关系(有一点点类似solve…before…),arguments会先求解,解完之后作为传入function得到返回值作为state variables,最后再求解其它rand variables。另外,如果隐含约束关系会造成求解循环依赖,那么仿真器将会报错;

顺便提一下state variables的概念,它是constraint guards的一种,我们可以把它理解成常数(constants),也就是它的值是固定的了,不会发生变化,不会创建constraint。

接下来看个例子来加深印象。

代码1如下:

class packet;
  rand int length, size, add;
  
  constraint const_c { /*solve length before size;*/ length == calc(size, add); }
  constraint const_d { size inside {1, 2, 3, 4, 5, 6, 7, 8}; }
  constraint const_e { add inside {1, 0}; }
  
  function int calc(int _s, int _m);
    if ( _m )
      return ( 100 + 2**_s + _s);
    else
      return ( 100 - 2**_s - _s);
  endfunction: calc
  
endclass

module top;
  initial begin
    packet pkt;
    pkt = new();
    repeat(3) begin
      pkt.randomize();
      $display("length = %0d, size = %0d, add=%0d",pkt.length, pkt.size, pkt.add);
    end
  end
endmodule

使用Cadence Xcelium 20.09运行结果如下:

xcelium> run
length = 120, size = 4, add=1
length = -35, size = 7, add=0
length = 80, size = 4, add=0
xmsim: *W,RNQUIE: Simulation is complete.

结果分析:

上面例子在const_c constraint block里使用了函数calc,block给calc传递的实参是size和add,因此systemverilog会先求解size和add变量的值,然后再去计算calc的返回结果,这时size, add以及calc()函数的返回值都当作state variables,最终再去求解length变量的值。

但如果将代码1里第4行的/*solve length before size;*/注释打开,也就是如下代码2:

class packet;
  rand int length, size, add;
  
  constraint const_c { solve length before size; length == calc(size, add); }
  constraint const_d { size inside {1, 2, 3, 4, 5, 6, 7, 8}; }
  constraint const_e { add inside {1, 0}; }
  
  function int calc(int _s, int _m);
    if ( _m )
      return ( 100 + 2**_s + _s);
    else
      return ( 100 - 2**_s - _s);
  endfunction: calc
  
endclass

module top;
  initial begin
    packet pkt;
    pkt = new();
    repeat(3) begin
      pkt.randomize();
      $display("length = %0d, size = %0d, add=%0d",pkt.length, pkt.size, pkt.add);
    end
  end
endmodule

那么使用Cadence Xcelium 20.09运行结果变成如下所示:

xcelium> run
xmsim: *W,RNDSVB: These solve/before constraints are circular:
0.	length -> size
		  constraint const_c { solve length before size; length == calc(size, add); } (./testbench.sv,4)
1.	size -> length
		( because of an implicit solve..before for random function-call arguments ):   constraint const_c { solve length before size; length == calc(size, add); } (./testbench.sv,4)

      pkt.randomize();
                  |
xmsim: *W,SVRNDF (./testbench.sv,22|18): The randomize method call failed. The unique id of the failed randomize call is 0.
Observed simulation time : 0 FS + 0

结果分析:

这是因为solve length before size与cacl()函数创造的隐含求解order约束冲突了。(Circular dependencies)

 

SystemVerilog ,可以使用 constraints(约束)来实现 randc(random with count)行为。下面是一个示例,展示了如何使用 constraints 实现 randc 行为: ```systemverilog typedef enum {A, B, C} my_enum; class MyClass; randc my_enum my_value; constraint value_constraint { // 指定每个值的权重 weight = {1, 2, 3}; // 使用 randc 实现权重分布 my_value dist { [A] : weight[0], [B] : weight[1], [C] : weight[2] }; } endclass module MyModule; MyClass obj; initial begin // 创建随机值并打印 repeat (10) begin obj = new; obj.randomize(); $display("Random value: %s", obj.my_value.name()); end end endmodule ``` 在上面的示例,我们定义了一个名为 `my_enum` 的枚举类型,包含了三个值 A、B、C。然后,在 `MyClass` 类声明了一个 randc 类型的成员变量 `my_value`。 通过在 `value_constraint` 约束定义一个权重数组 `weight`,我们指定了每个值的权重。然后,使用 `dist` 语法将权重分配给每个可能的值,从而实现了 randc 行为。 在 `MyModule` 模块,我们创建了一个 `MyClass` 对象,并使用 `randomize()` 方法对其进行随机化。然后,我们重复执行这个过程 10 次,并打印生成的随机值。 通过使用 constraintsrandc 类型,我们可以实现从一组值随机选择的行为,并且每个值的出现次数是根据权重分布的。 请注意,randc 是 SystemVerilog 的特定功能,不是纯 Verilog 支持的。因此,在使用 randc 之前,请确保你的仿真工具支持 SystemVerilog
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谷公子的藏经阁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值