SV知识点-随机约束

随机约束

  1. 随机变量与方法

rand,randc:对于randc来说,变量中有三个元素,那么经过三次随机化后变量会被遍历

随机方法(参见随机函数):virtual function int randomize();randomize()方法是一个虚函数(注意由于class不再具有像module的端口,因此声明接口的指针是当作变量声明,在接口指针声明时必须加virtual否则会报错;注意只有定义了rand或者randc的变量才会随机化,randomize()随机化只会随机化()中的变量,如果()中有变量,但是该变量不是rand或者randc,那么实际上该变量是不参与随机化的,也就是保持默认值。并且需要注意的是,无论是否真正的参与随机化过程,均要满足约束条件)

  1. 约束

dist操作(权重分布)::=每一个值的权重是相同的和:/权重会平均分配到取值范围内的每一个值 eg:constraint a {A dist {[0:1]:=10 [2:3]:/10}} 其中a是自己定义的名称,A是变量名,前者是每个都有十份的可能性,后者是十份的可能性被2和3分(可以在使用dist操作之前,先定义一个枚举类型,再用定义的枚举类型中的变量定义权重分布中的参数,在此后可以动态修改枚举类型中变量的值实现对权重的动态修改,例6.8)

inside运算符:A inside {[a:b]},其中A是变量,a和b是数值范围,另外可以用$来表示取值范围中的最大值与最小值p141,在整个A inside {[a:b]}加上()和!表示对范围的取反

条件约束:(1)->,constrain a {(x)->A},其中条件语句x可以不用加();如果aabb均是bit类型,那么约束{(aa==1)->(bb==0);},那么aabb会出现三种情况:(110200301三种,如果再加上一个(bb==1)的限定,那么就仅为第三种情况。注意->的作用是同步的,另外需要注意的是由于约束仅仅指出二值逻辑所以===和!==是非法操作(2)if-else:constrain a {if(x) A;else B},这里的条件语句最好加上()

foreach和solve...before:(1)foreach:constrain c2 {foreach (a[i]) (i<a.size-1) -> a[i+1]>a[i];}c2数组的每一个值都大于前一个的值,降序排列;对于存在这种排序的时候一定要注意限定i的取值,采用i<a.size-1或者i<=a.size-2。注意;符号在{}内,外部不需要加;(2)solve...beforeconstrain c {s -> d==0}在这个限定中sd是同时确定的,假如sd均是bits是默认位宽,d32位位宽,那么一共有233次幂种可能,仅仅在{10}这种情况下才成立。如果在这个基础上增加constraint order {solve s before d};那么这种限定的顺序就会变为sd先后限定,也就是先限定s再限定d。那么s50%可能位真,接下来d根据s的值来选择,d0和不为0的概率各占50%

双向约束(所有的表达式操作符都被双向对待):(1)->,限定是同时确定的(2) inside:inside约束变量范围再[10:20],再用另一个表达式子约束变量大于15,那么实际的范围是15-20

约束中的其他问题:一个表达式子中最多只能使用一个关系操作符,不能连续使用。例6.4

  1. 继承中的约束

子类的约束与父类的约束有同名,那么子类的约束会改写父类的约束

  1. 约束块的控制

打开和关闭(随机使能控制):

(1) constraint_mode():p.constrain_mode(0);p.a.constraint_mode(1);第一句话关闭p中所有的约束,第二句话打开p中约束a

(2) rand_mode():rand_mode()是针对变量进行的,p.rand_mode(0);p.a.rand_mode(1);b=p.a.rand_mode()b变量设置为a的激活状态

(3)内嵌约束t.randomize() with{};在使用内嵌约束时,约束体中的变量名的查找顺序默认时从被随机化的对象开始查找的,但是如果调用randomzie()的函数句柄域中也存在相同的变量名,那么就需要使用local::来显示的声明该变量源自于外部函数,而非随机化的变量。

(4)外部约束:在一个文件(该文件名是packet.sv)中定义一个class Packet,这个class中包含constraint c_external;但是在该类中并没有定义约束c_external中的具体约束,可以在另一个文件(与packet.sv不是同一个文件)中定义约束的具体内容,采用语句include"packet.sv"constraint Packet::c_external{具体约束;}

 

(5)软约束和硬约束:对约束前限定soft使得其变为软约束,软约束的优先级较低

  1. 随机函数

randomize,pre_randomize,post_randomize(随机方法):randomize只能随机化二值逻辑,一般建议将变量定义为bitpre_randomize()和post_randomize()是randomize的回调函数,在类中定义这两类函数后会分别在randomzie()前后调用这两类函数;randomize()失败后约束是不可行的,变量保持默认值并且post_randomize不会执行;可以在任何类中重写pre_randomzie()和post_randomize()以实现在randomzie前后的操作,如果这些方法被重写,那么他们必须调用他们的父类方法,否则randomzie前后的处理步骤会被忽略

系统随机函数:(1)$random(平均分布,返回32位有符号的数字),$urandom(与前者类似,但是无符号),$urandom_range( , )在指定范围内平均分布,只有一个值的化就是从0到该值。(2)关于dist中的一些系统函数p153

  1. 数组约束

基本的点:(1)数组属性的约束:constraint d_size{d.size() inside {[1:10]};};constraint d_size{d.sum<1024;} d中所有元素的和小于1024;除此以外还有product(),and(),or(),xor()(2)数组中的元素:采用foreach对数组(特别是动态数组)中的每一个元素进行约束,此外还可以通过foreach产生元素单调变化的数组:foreach(d[i])  if (i>0)  d[i]>d[i-1]  注意这个操作没有限定i值与尺寸之间的关系,是因为只出现了i和i-1

产生唯一元素的数组:(1)采用条件约束和两个foreach语句(foreach ua[i]和foreach ua[j])。条件约束的内容是如果i!=j,那么ua[i]!=ua[j](2)借助pre_randomize()函数,也就是先定义一个类A,其中的变量类型是randc,在定义一个类B(B中定义一个动态数组),在类B中用类A例化一个新的对象a,对a进行随机化,由于A中变量类型是randc,所有其随机化的值是不会重复的,然后采用foreach对B中的数组进行约束,使得动态数组的每一个值都等于例化a中的那个randc变量值。最终实现产生唯一元素的数组。(3)采用UniqueArry类,直接定义UniqueArry ua(随后定义数组大小,ua=new(50)),那么此时该数组中的每个元素都是唯一的

module only_element1;//较为复杂的一种方式,第一次随机随机数组尺寸,通过post随机具体数值

class RandcRange;

  randc bit [15:0] value;

  int max_value;

  function new(int max_value = 10);

    this.max_value = max_value;

  endfunction

  constraint c_max_value {value < max_value;} 

endclass

class Uniquearry;

  int max_arry_size,max_value;

  rand bit [7:0] a[];

  constraint c_size {a.size()inside {[1:max_arry_size]};}

  function new(int max_arry_size = 2,max_value);

   this.max_arry_size = max_arry_size;

   if (max_value < max_arry_size)

     this.max_value = max_arry_size;

   else

     this.max_value = max_value;

  endfunction

 

  function void post_randomzie();

    RandcRange rr;

       rr = new(a.size());

       foreach (a[i]) begin

         assert(rr.randomize());

         a[i] = rr.value;

       end

  endfunction

 

  function void display();

    $write("size is %3d",a.size());

       foreach(a[i]) $write("%4d",a[i]);

       $display;

  endfunction

endclass

program automatic test;

  Uniquearry ua;

  initial begin

    ua = new(50,2);

       repeat(10) begin

    assert(ua.randomize());

       ua.display();

       end

  end

endprogram

endmodule

module only_element2;//在随机化前进行预随机实现唯一性

class randc8;

  randc bit [7:0] val;

endclass

class LittleUniquearry;

  bit [7:0] ua [64]; 

  function void pre_randomzie();

    randc8 rc8;

       rc8 = new();

       foreach (ua[i]) begin

         assert(rc8.randomize());

         ua[i] = rc8.val;

       end

  endfunction

endclass

endmodule

/* module only_element2;

class xu;

  randc bit [7:0] val;

endclass

class LittleUniquearry;

  rand bit [7:0] ua [8]; 

  xu hanquan;

 

  function void pre_randomzie();

    hanquan = new();

    foreach (ua[i]) begin

    assert(hanquan.randomize());

    ua[i] = hanquan.val;

    end

  endfunction

  function void display();

    //$write("size is %3d",ua.size());

    foreach(ua[i]) $write("%4d",ua[i]);

    $display;

  endfunction

endclass

program automatic test;

  LittleUniquearry aa;

  initial begin

    aa = new();

    repeat(10) begin

    assert(aa.randomize());

    aa.display();

    end

  end

endprogram

endmodule */

module only_element3;//通过约束进行预随机

  class uniqueslow;

  rand bit [7:0] ua [64];

  constraint c{

    foreach (ua[i])

         foreach (ua[j])

           if(i != j)

                ua[i] != ua[j]

  }

  endclass

endmodule

句柄数组的随机化:(1)通过动态句柄数组产生多个随机对象,在进行句柄数组的随机化过程中,随机函数会随机化数组中每一个句柄所指的对象(这一点很重要,有两个类,在B类中定义一个存放A类的句柄的动态数组,也就是该动态数组中存放的都是A的句柄,并加上rand修饰,那么在随机化过程中实际上是不仅要随机化该句柄数组(比如句柄数组的个数),也要随机化句柄所指代的对象,也就是A类中的成员,这时,如果A类中成员用rand进行限定了,那么可以随机化成功,如果没有用rand修饰,那么对对象的随机化会失败,其值会保持默认值)(2)在随机化前要进行function new()操作及后续操作,以保证句柄数组中的每一个句柄都是非悬空的。并且最好function new()使得动态数组中分配最大数量的元素(这一点也很重要,比如在上面的那个例子中,如果没有function new()的化,那么在随机化时句柄所指代的对象实际是空的,又因为加上了rand修饰,那么程序又会主动的去寻找对象,此时找不到,程序报错),在随后随机化的过程中元素数量可能保持不变或者减少,但不会增加;(3)总的来说随机化句柄需要注意:指向的对象是否是rand属性,句柄数组不能悬空(function new()函数保证不悬空)

在集合中使用数组:把集合里的值保存到数组里后就可以使用这些值,可以采用约束操作完成保存:constraint c={f inside fib;}其中f是集合,fib是数组,如果先前中定义了数组的值,那么就相当于集合里面有数组的这些值。另外需要注意的是,如果数组中有重复的值,采用inside以后集合中各个值的概率是相同的,而不会因为数组中有某个值重复就使该值的概率增加(例6.14)

从数组中取出随机值的类及从数组中取出随机值:取出整个类可以采用约束中的inside语句,从数组中取出随机值可以i采用::符号逐一取值(例6.16,6.17)

  1. 随机控制

randcase:(1)randcase 1:xx;8:yy;  endcase表示xxheyy执行的概率分别时1/9和8/9(2)采用randcase建立决策树 例6.67

randsequence(参见例6.64):(1)randsequence(A) A: a:=1|b:=1;表示a和b均有1/2的可能性执行(2)a:{task;}|{task} a;表示执行a时执行task或者执行task后再执行a的可能性分别有1/2


版权声明:本文为juvenilexhq原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。