0. rand 和 randc
(1) rand 和randc 修饰的对象必须是类的成员变量,不能是静态变量。类外的随机属性需要配合SV预定义的类随机函数 std::randomize() 使用。
即只有通过声明rand变量,并且在后期通过对象调用 randomize() 函数才可以随机化变量。
(2) 随机求解成功则randomize返回1,否则返回0,通常添加断言来检查是否随机成功,不成功可以抛出一个error或者直接fatal
(3) 约束是声明性语句不是程序性语句
(4) rand 只能约束2值的数据类型,但是可以修饰4值的数据类型,string类型不能添加rand,枚举类型可以,因为本质上枚举类型就是int类型
同一个randc关键字定义的实例在执行随机化时是轮流取值的,每个元素都是唯一的,但是必须是对同一个实例的多次随机化才会有这个性质,如果每次都是对新的实例进行随机化,
那么最后出来的结果都是随机的,不一定会唯一。
1. 权重赋值符号(dist关键字)
(1) “:=”代表前面的值每一个都“等于”后面的权重。
(2) “:/”代表前面的值一起“均分”后面的权重值。
(3) 权重值或权重可以是常数或者是变量。
2. 集合成员和inside赋值符号
(1) 可以使用inside来从一个集合中取值,如果想要取集合外的值,那么直接使用一个取反符号;
(2) 可以直接把数组当成一个集合,然后使用inside进行约束,注意,如果数组中某个元素出现多次,那么出现的概率是相同的,也就是说不管元素重复出现多少次,求解的概率都是一样的;
补充面试题目:如何把四个盘子随机分配给四种苹果,一个盘子只能装一中水果(产生所有元素值均唯一的数组)
(1) 使用unique关键字约束
rand bit [7:0] plate [4] ;
rand bit [7:0] apple;
rand bit [7:0] orange;
rand bit [7:0] banana;
rand bit [7:0] pear;
rand bit [1:0] jerry_r [4]; //各位观众!jerry_r 就是我们的编号随机数组了!
constraint jerry_fruit {
apple inside {[2:11]};
orange inside {[70:111]};
banana inside {[0:4]};
pear inside {[5:29]};
}
constraint jerry_list {
unique {jerry_r}; //关键词unique就是关键了!
}
function void post_randomize( ); //我们把原固定编号换成编号随机数组!搞定
begin
int i=0;
plate[jerry_r[i++]]= apple;
plate[jerry_r[i++]]= orange;
plate[jerry_r[i++]]= banana;
plate[jerry_r[i++]]= pear;
end
endfuction
(2) 使用randc关键字约束数组,使其产生唯一的元素
(3) 使用两层循环
3. 精细化控制约束的几种方法
(1) 在调用 randomize( )时可以传递变量的一个子集,这样只随机化类里的几个变量。只有参数列表里的变量才会被随机化,其它变量会被当做状态变量而不会被随机化。
这里要注意的是:这种应用针对的是类里所有被指定或者没有被指定rand的变量都可以作为 randomize()的参数而被随机化。
(2) 使用内嵌约束,随机化后再根据场景添加一些额外的约束来产生预期的取值分布。
注意,如果使用内嵌约束的话,内嵌的约束要和定义的约束相协调,否则求解器会求不出解;
或者使用soft关键字,将该变量的约束修改成软约束,这样如果和外部的内嵌约束相违背,会以内嵌约束为准;
(3) 使用多个约束块,在外部使用 constraint_mode()来控制每一个约束快的打开与关闭
4. 类约束和系统约束
与在类中定义约束,并且通过对象调用随机化函数 randomize() 相对的是,一些细碎的场景并不需要像类那么全面支持随机约束的方式,而是需要一种更简单的机制来随机化一些在类之外的变量。
于是,系统随机std::randomize()的方法(或者称之为域随机(scope randomize function)),可以让用户在当前的作用域中无需定义类和例化对象就可以完成对变量的随机化。
5. 控制约束的开启与关闭
(1) 打开或者关闭某个对象或者对象成员的随机
acc.rand_mode(0); // 关闭对象acc内所有变量的随机属性
acc.arr.rand_mode(0); // 关闭对象acc的成员arr的随机属性
(2) 打开或者关闭某个约束块
acc.constraint_mode(0); // 关闭所有约束块
acc.c6.constraint_mode(0); // 关闭某个约束块
6. 如何产生一个数组元素唯一的数组?
(1) 使用unique关键字
(2) 使用两层for循环逐个元素约束
(3) 使用randc配合
(4) 对数组的元素赋数组的索引值,然后在post_randomize中使用shuffle方法对数组的元素进行打乱
7. 静态数组、动态数组,队列,关联数组的随机化
(1) 静态数组 : 数组的大小不变,可以对数组的每一个元素添加约束,可放constraint或者post_randomize中
(2) 动态数组 : 可以使用 size()约束数组的大小,使用 sum()约束数组的和,使用 product()约束数组的积。一般可以在post_randomize中对每一个元素进一步求解;
(3) 队列
(4) 关联数组
8. SV中的随机方法
(1) 系统随机函数:$random, $urandom, $urandom_range;还提供了$dist_uniform, $dist_normal, $dist_exponential, $dist_poisson 等不同分布的随机函数
(2) 对象随机方法object.randomize()
(3) 标准库随机函数std::randomize()
9. 对象随机方法object.randomize()
它是所有SV类中都会默认存在的内置虚函数(原型是virtual function int randomize()),但是它不能被覆盖(overridden)。
当你使用object.randomize() 来对对象进行随机化的时候,注意它只会随机化类中有rand关键词修饰的成员变量,并且在成功随机化之后会返回1,失败则返回0。
除此之外,两个回调函数 pre_randomize()和 post_randomize(),这两个函数分别会在执行 randomize()的前后自动被调用。注意,这两个函数并不是虚函数(其函数原型没有virtual关键字),
但他们是由虚函数 randomize()来自动调用的,因此也表现为虚函数的多态行为。