第六章:随机化

随着设计变得越来越复杂,要想产生一个完整的激励集来测试设计的功能也变得越来越困难。采用受约束的随机测试法(CRT)自动产生测试集是目前的一种主要的方法。CRT由两部分组成:使用随机的数据流为DUT产生输入的测试代码,以及伪随机数发生器的种子。

6.1 什么需要随机化

在产生随机化的激励时,我们最容易想到的就是使用$random函数。但是这种方法找bug的能力是十分有限的,它只能找到数据路径的问题,或者是bit级别的错误。从某种意义上讲,这种方法还是基于定向测试。那些具有挑战性的bug大都在控制路径里面。因此,必须对DUT里所有关键点都采用随机化技术。随机化使控制路径里每一个分支都可能被测试。你需要考虑设计输入下列的各个方面。

  • 器件配置
  • 环境配置
  • 原始输入数据
  • 封装后的输入数据
  • 协议异常
  • 延时
  • 事务状态
  • 错误和违规

6.2 SystemVerilog中的随机化

基于OOP使用SystemVerilog中的随机激励产生是最有效的。首先,建立一个具有一组相关的随机变量的类,然后用随机函数为这些变量赋随机值,你可以用约束来限制这些随机值的范围,使他们是有效的值,也可以某些专用的功能。
简单的随机类

  • rand:每次随机化这个类,这些变量都会赋一个值。就好像掷骰子,每掷一次就产生一个新的数字。
  • randc:表示周期性随机。就好像从一副牌里一张一张地、随机抽出所有的牌,洗牌后再按另一个顺序随机地抽出牌。
  • constraint:约束的条件放在{}里面,而不是begin---end里面。
  • randomize():函数遇到约束方面的问题时,返回0.如果随机化成功则返回1.
  • assert:判断随机化有没有成功。
  • $fatal:用来结束仿真。
    注意:
    1、不能在类的构造函数里随机化对象。
    2、constraint中受到约束的变量必须是声明成rand或者randc类型。
6.2.1 简单的表达式

在一个表达式中最多只能使用一个关系操作符。

      class order;
             rand bit[7:0] lo,med,hi;
             constraint bad {lo<med<hi;}
      endclass

lo<med<hi会被划分成(lo<med)<hi,(lo<med)会得到一个布尔函数值0或1,然后与hi相比较。显然结果并不是我们想要的。正确的写法如下:

     class order;
             rand bit[7:0] lo,med,hi;
             constraint good {lo<med;
                              med<hi;}
    endclass
6.2.2 权重分布

dist操作符允许产生权重分布,这样的话某些值得选取机会就会比其他值大一些。

  • :=表示值范围内的每一个值得权重是相同的。

  • :/表示权重要均分到值范围内的每一个值。

  • 值可以是一个值,也可以是一个范围,例如[lo:hi]

       class test;
          rand int src,dst;
          constraint c {
                         src dist {0:=40,[1:3]:=60;}
                         dst dist {0:/40,[1,3]:/60;}
                              }
        endclass
    

src=0 40/220
src=1 60/220
src=2 60/220
src=3 60/220
dst=0 40/100
dst=1 20/100
dst=2 20/100
dst=3 20/100

6.2.3 集合成员和inside运算符

可以用inside运算符产生一个值的集合。

     class test;
        rand int src;
        constraint c {
                       src inside {[0:3]};
                            }
     endclass
  • inside {lo:hi};lo<hi,否则的话为空集;
  • $,可以代表取值范围的最大值和最小值;
  • !取反操作符可以选取集合范围之外的数据;
6.2.4 在集合里使用数组

集合里面使用数组
TT.PNG

  • 对数组里面的每一个值的取值的概率都相等。
6.2.5 条件约束

通常约束块里所有的约束表达式都是有效的,但怎样才能只让一个表达式在某些情况下有效呢?SystemVerilog支持两种关系操作符:->和if-else。

    class BusOp;
           ......
    constraint c {(io_space_mode) ->
                 addr[31]==1'b1;
                }

if-else并不是包含在begin-end块中,而是放在constraint的{}中。

6.2.6双向约束

约束块并不想自上而下执行的程序性代码,它们是声明性代码,是并行的,所有的约束表达式同时有效。
就算是在条件约束中,if-else语句中,并不是if中的语句成立才执行才执行下一条语句,而是所有的语句事先都已经知道。

6.3 解的概率

提到随机,那么概率必然与之相随。SystemVerilog并不能保证求解器能够给出确定的解,但是我们可以干预解得概率分布。

6.4 控制多个约束块

在一个类中可以包含多个约束块。那么我们应该如何去控制这些约束呢?
在运行期间,可以使用constraint_mode()函数来打开或者关闭约束。

     class Test;
        rand int src;
        constraint c {
                       src inside {[0:3]};
                            }
       constraint c_1 {
                       dst inside {[0:3]};
                            }
      endclass

   Test t;
     initial begin
       t=new();
      t.c.constraint_mode(0);//关闭c
      assert(t.randomize());
      t.constraint_mode(0); //关闭所有的限制c和dst
      t.c_1.constraint_mode(1);//打开c_1这个约束
  • t.c.constraint_mode(0);//关闭c
  • t.constraint_mode(0); //关闭所有的限制c和dst
  • t.c_1.constraint_mode(1);//打开c_1这个约束

6.5 内嵌约束

SystemVerilog允许使用randomize()with来增加额外的约束,这和在类里增加约束是等效的。

   class Test;
        rand int src;
        constraint c {
                       src inside {[0:3]};
                            }
     endclass

  Test t;
   initial begin
      t=new();
   assert(randomize() with {src>2});
  end

注意:在此处,with{}语句里面类似于作用域,但是使用了变量src而不是t.src.

原文地址:https://www.cnblogs.com/xuqing125/p/9550567.html