目录
1、pre_randomize()和post_randomize()
一、随机约束和分布
1、为什么需要随机?
- 芯片体积增大,复杂度日渐提高,在20年前定向测试已经无法满足验证的需求,而随机测试的比例逐渐提高
- 定向测试能找到你认为可能存在的缺陷,而随机测试可以找到连你都没有想到的缺陷。
- 随机测试的环境要求比定向测试复杂它需要激励、参考模型和在线比较。上百次的仿真不再需要人为参与,以此来提高验证效率
- 激随机测试相对于定向测试可以减少相当多的代码量,而产生的激随励较定向测试也更多样
- 如果说定向测试是"站着测”,那么随机测试就是"躺着测”、“跪着测”、“跑着测”各种花式测,只有想不到,没有测不到
2、为什么需要约束?
- 如果随机没有约束,意味着什么?是绝对的自由吗?肯定不是,它是一匹脱缰的野马,没有拘束,产生有效激励的同时也产生了很多无效和非法的激励。
- 那么我们想要的随机自由是一种合法的随机,需要限定激励的合法范围。同时,伴随测试的进行,约束甚至应该"变形”,变得更趋于为测试的数值范围或者期待的数值范围
- 随机的对象不只是一个数据而是有联系的变量集。通常这些变量会被封装在一个数据类中,同时需要在类中声明数据之间的约束关系。因此约束之后要产生随机数据需要一个“求解器",即在满足数据本身和数据之间约束关系时的随机数值解
- 约束不但可以指定数据的取值范围,还可以指定各个数值的随机权重分布
3、我们要随机什么
:随机测试中,可以随机化设计的结构吗?
不可以,随机、验证的结构(类是动态的)发生在仿真设计的结构发生在编译的时候
4、声明随机变量的类
随机化是为了产生更多可能的驱动,因此在软件世界"class”的运用更多,所以我们倾向于将相关数据有机整理在一个类的同时,也用rand关键词来表明它们的随机属性
randc表示周期随机性,即所有可能的值都赋过值后随机值才可能重复
随机属性需要配合SV预定义的类随机函数std::randomize()使用。即只有通过声明rand变量,并且在后期通过对象调用randomize()函数,才可以随机化变量
约束constraint也同随机变量一起在类中声明
说明: rand和randc都是关键词,必须用来修饰类的成员变量
类里面方法的局部变量不能用这两个关键词修饰
rand和randc的区别:
以抽扑克牌为例子(一副扑克牌有54张):
5、什么是约束
- 约束表达式的求解是由SV的约束求解器(constraint solver)完成的。
- 求解器能够选择满足约束的值,这个值是有SV的PRNG (伪随机数发生器 Pseudoandom number generator )从一个初始值 (seed) 产生。只要改变种子的值,就可以改变CRT的行为。
- SV标准定义了表达式的含义以及产生的合法值,但没有规定求解器计算约束的准确顺序。这即是说,不同仿真器对于同一个约束类和种子值求解出的数值可能是不相同的
- 什么可以被约束? SV只能随机化2值数据类型,但位可以是2值或4值。这即是说,无法随机化出X值和Z值,也无法随机化字符串。
说明:
- 同一个仿真器,同一个版本,是同一个伪随机数发生器,那么用同一个种子,一定会产生相同的激励
- 随机化一般是确定的值,没有办法随机化出X OR Z
例子
说明:
- const是关键字表达的含义是常数,后期const值不能做第二次赋值。
-
每次randomize的时候,constraint里面的随机变量都要符合,没有产生任何的冲突才可以
6、权重分布
- 关键词dist可以在约束中用来产生随机数值的权重分布,这样某些值的选取机会要比其他值更大一些。
- dist操作符带有一个值的列表以及相应的权重,中间用:=或:/分开。值或权重可以是常数或者变量。
- 权重不用百分比表示,权重的和也不必是100
- := 操作符表示值范围内的每一个值的权重是相同的
- :/ 操作符表示权重要平均分到值范围内的每一个值
7、集合成员和inside运算符
8、条件约束
9、双向约束
- 需要注意的是,约束块不像自上向下的程序性代码。它们是声明性的代码,是并行的,所有的约束表达式同时有效。
- 约束也是双向的,这表示它会同时计算所有的随机变量的约束。增加或删除任何一个变量的约束都会直接或间接影响所有相关的值的选取。
二、约束块控制
1、打开或关闭约束
2、内嵌约束 (in-line)
- 伴随着复杂的约束,它们之间会相互作用,最终产生难以预测的结果。用来使能和禁止这些约束的代码也会增加测试的复杂性
- 经常增加或修改类例的约束也可能会影响整个团队的工作,这需要考虑类的开放封闭原则 (OCP) 。
- SV允许使用randomize() with来增加额外的约束,这和在类里增加约束是等效的,但同时要注意类内部约束和外部约束之间应该是协调的,如果出现互相违背的情况,那么随机数值求解会失败
说明:soft关键字,软约束,当外部的约束(硬约束)or其他的约束只要是叠加在一起的约束,当有冲突的时候,soft优先级更低,其他约束优先!!!
三、随机函数
1、pre_randomize()和post_randomize()
- 有时需要在调用randomize()之前或之后立即执行一些操作,例如在随机前设置类例的一些非随机变量(上下限、条件值、权重),或者在随机化之后需要计算随机数据的误差、分析和记录随机数据等
- SV提供了两个预定义的void类型函数pre_randomize()和post_randomize()函数。用户可以类中定义这两个函数,分别在其中定义随机化前的行为和随机化后的行为。
- 如果某个类中定义了pre_randomize()或者post_randomize()函数,那么对象在执行了randomize()之前或者之后会分别执行这两个函数。
- 所以,pre_randomize()和post_randomize()可以看做是randomize()函数的回调函数(callbackfunction)
2、随机数函数
3、随机化个别变量
- 在调用randomize()时可以传递变量的一个子集,这样只会随机化类里的几个变量
- 只有参数列表里的变量才会被随机化,其它变量会被当做状态变量而不会被随机化。(
只有在randomize里面指定的参数才会被随机化,没有被指定的参数即便有rand关键字也不能被随机化,此时的rand作用失效了)
- 所有的约束仍然保持有效
- 初学者需要注意该种应用针对的是类里所有被指定或者没有被指定rand的变量都可以作为randomize()的参数而被随机化。
四、数组约束
1、数组的属性约束
- 在约束随机变量的同时,我们还可以对随机化数组进行约束。
- 多数情况下,数组的大小应该给定范围,防止生成过大体积的数组或者空数组(小白不用担心,现在的软件会给出一个范围)
- 还可以在约束中结合数组的其它方法sum(),product(),and(),or(),xor()。
2、约束数组中的元素
- SV可以利用foreach对数组的每一个元素进行约束,和直接写出对固定大小数组的每一个元素的约束相比,foreach要更简洁。
- 针对动态数组,foreach更适合于对非固定大小数组中每个元素的约束。
3、产生唯一元素值的数组
如果想要产生一个随机数组,它的每一个元素的值都是唯一的。
如果使用randc数组,那么数组中的每一个元素只会独立地随机化,并不会按照我们的本意使得数组中的元素值是唯一的。
例子:
4、随机化句柄数组
- 随机句柄数组的功能是在调用其所在类的随机函数时,随机函数会随机化数组中的每一个句柄所指向的对象。
- 因此随机句柄数组的声明一定要添加rand来表示其随机化的属性,同时在调用随机函数前要保证句柄数组中的每一个句柄元素都是非悬空的,这需要在随机化之前为每一个元素句柄构建对象
- 如果要产生多个随机对象,那么你可能需要建立随机句柄数组。
- 和整数数组不同,你需要在随机化前分配所有的元素,因为随机求解器不会创建对象。
- 使用动态数组可以按照需要分配最大数量的元素,然后再使用约束减小数组的大小。
- 在随机化时,动态句柄数组的大小可以保持不变或减小,但不能增加
五、随机控制
1、随机序列
2、随机控制
3、总结
- randsequence和randcase是针对轻量级的随机控制的应用。而我们可以通过定义随机类取代上述随机控制的功能,并且由于类的继承性使得在后期维护代码时更加方便。
- randsequence的相关功能我们在协调激励组件和测试用例时可能会用到。
- randcase则对应着随机约束中的dist权重约束+if-else条件约束的组合。