system verilog(六)随机化

定向测试集能够找到你认为可能存在的bug;而使用受约束的随机测试法(CRT)自动产生测试集,可以找到你都无法确定的bug
简单的定向测试集只需施加激励,然后人工检查输出结果(保存为标准日志文件.log文件),用来和今后的仿真结果进行比较,以判断仿真结果的正确性;CRT不仅需要产生激励,还需要通过参考模型、传输函数或其他方法预测输出结果。
(CRT由两部分组成:使用随机的数据流为DUT产生输入的测试代码;伪随机数发生器种子,只要改变种子的值,就可以改变CRT的行为)

什么需要随机化:
1、器件配置(随着时间的变化,DUT的配置越来越随机)
2、环境配置(器件在一个包含若干个期间的环境里工作,应该随机化整个环境,包括对象的数量和它们如何配置)
3、原始输入数据($random)
4、封装后的输入数据(需要处理激励的不同层次)
5、协议异常、错误和违规(测试平台应该能够产生正确的激励,然后通过翻转某一个配置位,在随机的时间间隔里产生随机的错误类型)
6、延时(测试平台应该在每一个测试里都使用随机的、有效的延时,以便发现设计中的bug;例如在周期级验证更低的级别,对时钟抖动很敏感,通过将时钟沿来回移动很小的步长,可以检查设计对时钟周期是否异常敏感;而时钟发生器位于测试平台之外,这样可以在有效区域active region 产生事件;但测试平台不应违反建立时间和保持时间的约束)

首先建立一个具有一组相关的随机变量的类,然后用随机函数为这些变量赋随机值,可以用约束来限制这些随机值的范围,使他们是有效的值。

class packet;
rand bit[31:0]src,dst,data[8];//使用rand修饰符,表示每次随机化这个类时,都会随机赋值
randc bit[7:0] kind;//randc类型,表示周期随机性,所有可能的值都赋值过随机值才可能重复
//约束
constraint c {src>10;src<15;}//约束是一组确定变量值范围的关系表达式,永远为真
endclass

packet p;
intial
begin
p=new();//产生一个包
assert(p.randomize());//使用断言来检查randomize函数的结果
else
$fatal (0,"packet::randomize failed");
transmit(p);
end

不能再类的构造函数里随机化对象,因为在随机化前可能需要打开或关闭约束、改变权重,添加新的约束;构造函数用来初始化对象的变量,不能再这里调用randomize()函数;类中所有变量应该是随机的公有的,这样测试平台才能最大程度控制DUT。
当代码中有矛盾的约束,随机化过程就会失败,即assert检查randomize函数返回值,若返回0,断言检查到错误后会显示错误信息。

system verilog只能随机化2值数据类型,但位可以是2值或4值类型;可以使用整数和位矢量,但不能使用随机字符串,或在约束中指向句柄。

每个表达式里至少有一个变量是rand或randc类型的随机变量;否则类会在随机化时出错,除非正好满足约束条件,此时约束条件只是检查非随机变量是否有效。

简单表达式(在一个表达式中最多只能使用一个关系操作符(<、<=、==、>=、>)
例如:

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

这样的约束分割成两个关系表达式:{{lo<med}<hi},而表达式{lo<med}的值为0或1;即hi是大于0或1的,所以正确的约束需要将二者分开

constraint good {lo<med;
med<hi;}
由于在约束块中只能包含表达式,不能进行赋值;可以用关系运算符为随机变量1赋值,例如len==42;

权重分布:dist操作符,dist操作符带有一个值的列表以及权重,中间用:=或者:/分开,值或权重可以是常数或者变量;值可以是一个值或值的范围,例如[lo:hi];权重的和也不一定是100.:=操作符表示值范围内的每一个值的权重是相同的;:/操作符表示权重要均分到值范围内的每一个值。
在这里插入图片描述
第一个约束表示(src取0的权重为40;[1:3]的权重均为60)
第二个约束表示(dst取0的权重为40;[1:3]均分权重60)

值和权重可以是常数或变量。可以使用权重变量来改变值的概率分布,甚至可以把权重设为0,从而删除一个值

可以使用inside产生一个值的集合
在这里插入图片描述
可以用$指定最大值和最小值
在这里插入图片描述
随机集合约束的取反
在这里插入图片描述
在集合里使用数组:将集合里的值保存到数组中即可
在这里插入图片描述
条件约束:两种关系操作->和if-else;->操作符可以产生和case操作符类似的语句块,可以用于枚举的表达式。
在这里插入图片描述
而if-else更适合“真-假”类型的表达式
在这里插入图片描述
使用合适的数学运算来提高效率
在这里插入图片描述
使用solve…before约束引导概率分布

class solvebefore
	rand bit x;
	rand bit [1:0] y;
	constraint c_xy{
	(x==0)->y==0;
	solve x before y;
	}
endclass

solve…before约束不会改变解的个数,只会改变各个值的分布;比如在1000次的randomize()调用中;x为0的次数大约是500,x为1的次数大约是500;而将约束改为solve y before x ;y为0的次数为250,y为1的次数为250,y为2的次数为250,y为3的次数为250;会得到完全不同的概率分布。

控制多个约束块
在运行期间,可以使用内建的constraint_mode()函数打开或关闭约束;可以用handle.constrain.constraint_mode()控制一个约束块,用handle.constraint_mode()控制对象的所有约束。
在这里插入图片描述
内嵌约束:可以使用randomize() with来增加额外的约束
在这里插入图片描述
注意:在使用randomize()with中约束块同样需要{}

如果需要在调用randomize()之前或之后立即执行一些操作,可以使用两个void类型的pre_randomize()和post_randomize()函数来完成这些功能。

在这里插入图片描述
使用变量的约束,方便约束的修改
在这里插入图片描述
可以在类中定义非随机变量,这样调用randomize函数是不会被随机化;

在测试过程中使用外部约束(外部约束可以放在另一个文件里,从而在不同的测试里可以复用外部约束;外部约束对类的所有实例都起作用,而内嵌约束仅仅影响一次randomize()调用。
在这里插入图片描述
1、除非必要,不要在随机约束中使用有符号类型
2、避免使用复杂的运算,例如除法、乘法和取模(如果需要除以或乘以2的幂次方,使用左移或右移操作;使用宽度小于32的变量可以得到更高的运算性能)

使用foreach约束动态数组和队列

class good_sum5;
rand uint len[];//32位无符号数组
constraint c_len {foreach (len[i])
len[i] inside {[1:255]};//单个数组值的范围
len.sum<1024;//总值的范围
len.size() inside {[1:8]};}//事务个数的范围
endclass

产生具有唯一元素值的数组
1、使用嵌套foreach循环
在这里插入图片描述
2、使用包含randc变量的辅助类
在这里插入图片描述
3、唯一值发生器
在这里插入图片描述
产生原子激励和场景
1、和历史相关的原子发生器
最简单的方法是采用基于以前事务的随机值的原子发生器(可以使用post_randomize函数复制产生的事务,用于下一次randomize()调用)
2、随机序列

initial
begin
for(int i=0;i<15;i++)
begin
randsequence(stream)//产生stream序列
stream:cfg_read :=1|//cfg_read的权重是1
io_read :=2|
mem_read :=5;
cfg_read:...
mem_read:...
io_read:...
endsequence
end
end

随机控制(用randcase建立决策树)
在这里插入图片描述
在这里插入图片描述
随机数发生器
verilog使用一种简单的PRNG(伪随机数发生器)

reg [31:0] state=32'h12345678;
function logic [31:0] my_random;
logic [63:0] s64;
s64=state*state;
state=(s64>>16)+state;
my_random=state;
endfunction

先计算出状态的64位平方值,取中间的32位数值,然后加上原来的32位数值。

而sv测试平台通常会有几个激励发生器同时运行,如果共享一个PRNG,则获得的都是随机数的一个子集。
在这里插入图片描述
Gen1的修改不但影响Gen1自己的随机数,也影响了Gen2
在这里插入图片描述
在sv中,每个对象和线程都有一个独立的PRNG,改变一个对象不会影响其他对象获得的随机数。
在这里插入图片描述
sv的每个对象都有自己的PRNG和独立种子,当启动一个新的对象或线程时,子PRNG的种子由父PRNG产生。所以在仿真开始时的一个种子可以产生一个随机激励流,之间又是相互独立的。

发布了64 篇原创文章 · 获赞 5 · 访问量 3200

猜你喜欢

转载自blog.csdn.net/buzhiquxiang/article/details/104222744