第六章:随机方法

激励产生有三种办法:直接测试(directed test,DT)、随机测试(random test,RT)

、直接随机测试(direct random test,DRT)

随机测试的验证平台通常更加复杂,需要激励产生器、监控器、检查器等验证组件。

随机生成机制共有四种:内置系统函数、randcase、randsequence结构、基于对象的随机生成   、标准随机函数std::randomize()

随机系统函数

$random:   random_function::=$random [(seed)];

           该函数返回32位,有符号的,伪随机数。

$urandom: function int unsigned $urandom[(int seed)];

          该函数返回32位,无符号整数。

$urandom_range():function int unsigned_range(int unsigned maxval,int unsigned minval);    该函数返回一个在(maxval,minval)之间的无符号整数。

标准概率分布函数:dist_uniform, dist_normal, dist_exponential, dist_poisson, dist_t, dist_erlang, dist_chi_square. 每个系统函数将返回一个伪随机数,其遵从函数名所表示的随机分布。

randcase/randsequence

随机分支选择randcase

根据分支权重来随机的选择执行某一条分支

randcase

 3:x=1;

 1:x=2;       权重和为3+1+4=8,所以第一支被选中的概率为:3/8=0.375

 4:x=3;

endcase  //注意过程块结尾是endcase

若权重为0,则该分支不会被执行,若所有分支权重都为0,则所有分支都不会被选中,仿真工具会发布警告信息。

此外,权重也可以是表达式(比如a+b、a|b)

随机序列生成:randsequence

用于随机的产生结构化的激励序列

randsequence(main)  //括号中的变量为顶层生成式,该式子决定了生成序列

  main : first second done;  //生成的序列由first second done构成

  first : add|dec;     //first生成式为add、dec二选一

  second : {$display(second);};  //second生成式为输出second

  done : add:3|dec:(1+1); //done生成式为选中add概率为60%,选中dec为40%

add : {$display(“add”);};

  dec : {$display(“dec”);};

 endsequence  //注意该过程块结尾是endsequence,注意与endcase区分。

以上代码所输出的结果共有四种:

add second add、dec second add、add second dec、dec second dec

此外,注意到randsequence关键字后还有一个括号,括号内表示的是顶层生成式,若一个随机生成序列没有指定顶层表达式,则默认块内第一个生成式为顶层生成式。

基于对象的随机生成

基于对象的随机生成一共包括三个步骤:1.定义随机变量。2.指定约束条件(可选)。3.通过调用内置方法randomize()产生随机。

定义随机变量

1.rand关键字声明的变量

rand bit [2:0]y;  //声明了y是一个3位的无符号整数,其值在0到7的概率是相等的。

2.ranc关键字声明的变量

Randc bit [2:0]y;  //声明了y是一个3位无符号整数,随机化过程为:先在取值范围内计算一个初始的随机排列(洗牌),然后再连续的调用中按顺序返回这些值(发牌)。当返回该排列的最后一个元素时,会重新计算一个新的随机排列(重新洗牌)。

注意:数组被声明成rand或者randc的时候,意味着数组中所有元素都被随机化。此外,对象的句柄也可以用rand声明(但不能用randc),此时对象中所有变量和约束都被并发的求解。

指定约束条件

随机变量的值可以通过约束块中的约束表达式来约束,约束块的声明使用constrain 关键字:constrain constrain_identifier {{constrain_block_item}}

注意约束块结尾没有分号

约束快中常用的操作符inside,dist、条件->,if/else、循环语句foreach:

  1. inside集合操作

表达形式:expression inside {gather_range};

rand integer x,y,z;

constrain c1 {x inside { 3 , [9:15] , [y,2*y] }; } //x的取值在集合范围内,[9:15]是从9到15

iInteger fivers[0:3]={5,10,15,20}

constrain c2 { !( x inside fivers); }//x的取值在fivers表示的范围之外,注意取反操作

所有可选值具有相同的概率,注意该操作符构成了一条语句,包括在约束块内要以分号结尾(如上代码标红部分)

2.dist分布操作

表达形式:expression dist {value_range1:= dist_whight,value_range2 :/ dist_whight};

                                          条目表达式1  操作符 权重      条目表达式2  操作符   权重

rand int x,y,z;

x!=8; //此处约束了x不等于8

constrain c3 {x dist {1:=1,8:=2,3:=5};}//由于x≠8,所有x只能=1、3,权重比为1:5

constrain c4 {y dist {[1:3]:=1,4:=2,5:=5};}//x的取值有1,2,3,4,5,权重比为1:1:1:2:5

constrain c5 {z dist {[1:3]:/1,4:=2,5:=5};}//x取值不变,权重比变为1/3:1/3:1/3:2:5

由上可知:当条目表达式为一个范围时,操作符:=和操作符:/表达的含义不同。其中:=表示范围中的每一个值都被指定权重

:/表示范围内的n个值的权重为指定权重,则范围内的每个值的权重为range_weight/n

注意:dist表达式不能应用的randc变量

同样的,该操作符也构成了一条语句,包括在约束块内要以分号结尾(如上代码标红部分)

3.条件操作

共有两种结构来声明条件操作分别是蕴含操作:->和if/else

蕴含操作:a->b表示若a为真,则b会被受到约束。

constrain c6 {mode==large->len<10;mode==small->len>10;}

注意该操作符构成一条语句,因此结尾要用分号分隔开,而不是用逗号

mode==large和mode==small相当于条件a,若mode==large成立,那么len<10。若mode==small成立,那么len>10。如果两个都不成立,那么len不受约束。

If/else

从上面对蕴含操作的解释可以发现,蕴含操作和if/else操作可以互相转换:

constrain c7 {

if(mode==large)

 len<10;

else if(mode==small)

len>10;}4

4.foreach迭代操作

该操作常与其他随机操作搭配使用,来对数组元素进行随机

rand byte a[];//动态数组a

constrain c8 {foreach(a[i]) a[i] inside {[2:5]};}//a中的每一个元素都在[2:5]之内

constrain c9 {foreach(a[j]) a[j]>2*j;}//a的每个元素大于索引值的两倍

constrain c10 {a.size inside {[]1:10};}//动态数组a的尺寸在[1:10]

constrain c11 {foreach(a[k]) (k<a.size)->(a[k+1]>a[k]);}//数组a降序排列

约束块c10属于数组的大小约束,约束块c11属于数组的迭代约束,如果一个数组即被大小约束又被迭代约束,那么大小约束先被解析。

5.slove...before操作

我们一般希望解析器能确保选择的有效值概率相等,然而在蕴含操作中:

rand bit s;rand bit[31:0]d;

constrain c12 {s->d==0;}  //s蕴含着d等于0,由于s和d是同时确定的,所以[s,d]共有223种组合,而该约束成立时的组合[1,0]的概率仅为1/223,非常低,趋向于0.

因此,为了解决这个问题,提出一种slove...before结构:slove a before b;意为a在求解b之前求解。于是上述代码再加一个约束语句后:

constrain c12 {s->d==0;}

constrain c13 {slove s before d;}//该约束条件存在,s先被解析。因此s为真的概率为50%,之后当d为真后再解析d,而d为0的概率也为50%,故[1,0]组合的的概率为1/4,与[0,0],[0,!==0],[1,!==0]的概率都相等。

注意:约束仅支持两态值,四态值(x,z)或四态操作符(===,!===)会导致错误

随机方法

对象中的变量使用randomize()方法进行随机化,它的原型是类的一个虚函数:virtual function in randomize();  //虚方法

如果调用该函数产生的随机变量符合约束,那么该函数返回1,否则返回0.因此需要检查函数返回状态来确定是否随机成功。该方法是类的内置方法,不可重写。

在调用类的内置方法randomize()之前会调用另一个内置方法:pre_randomize(),

该内置方法是一个函数,函数体中的内容可被重写,用于初始化和预处理。

function void pre_randomize;   //该方法不是虚方法

  if(super)

super.pre_randomize();

初始化程序   //可重写

endfunction

在调用类的内置方法randomize()之后会调用另一个内置方法:post_randomize(), 该内置方法是一个函数,函数内容可被重写,用于对象随机化之后清除、打印诊断及后处理。

function void post_randomize;  //该方法不是虚方法

  if(super)

super.post_randomize();

后处理程序    //可重写

endfunction

随机使能控制

以上①-③说明了基于对象的随机生成的步骤,一般定义的随机变量和约束默认都是被激活的,如果想要关闭对象中的某个变量的随机属性,则可以用随机变量使能控制rand_mode()和随机约束使能控制constrain_mode()

1.随机变量使能控制rand_mode()

该方法既可以是一个任务,又可以是一个方法;

做任务被调用时传入参数1,则激活随机变量,传入参数0则关闭随机属性。

做函数被调用时返回该变量的激活状态,1为激活,0为关闭

class packet;   rand int x,y;  ...   endclass

initial begin

  packet pk1=new;

  pk1.rand_mode(0); //关闭对象中的所有随机变量

  pk1.x.rand_mode(1); //使能对象中x变量的随机属性

  ret=pk1.y.rand_mode(); //将对象中y的激活状态赋值给ret变量。

end

2.随机约束使能控制constrain_mode()

该方法也是既可以是函数也可以是任务,使用方法类似rand_mode(),只不过rand_mode是对随机变量操作,而constrain_mode是对约束块名字进行操作。

约束的动态修改

如果在类中定义好了约束,在例化对象中使用时又有额外的约束怎么办?

常采用randomize...with结构来添加约束:

With后的约束块与类中声的约束块具有相同的格式。

标准随机函数

在类中可以在变量的前面添加上rand,同时加上constraint,在randomize的时候随机.但是,有时候在task或者function中需要对一个临时变量做随机,此时便可以借助于std::randomize(a,b,c)with实现对变量的随机.

function bit gen();

bit success,rd1,rd2;

success=std::randomize(rd1,rd2)with{rd1<rd2;}; //调用标准随机函数,将输入函数的变

return rd;                                                                量rd随机化,该函数也可以和with搭配

endfunction                               

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值