参考链接:
SV--随机约束(一)_sv constraint-CSDN博客
SV--随机约束(二)_sv constraint f循环-CSDN博客
[SV]Constraint 遇到的问题_父类和子类 constraint-CSDN博客
目录
1、随机化的概念理解
2、约束(constraint)
2.1、inside
2.2、内嵌约束
2.3、约束块控制
2.4、对数组的约束
3、SV中的随机化函数
1、随机化的概念理解
我们要随机什么?
- 器件配置:通过寄存器和系统信号
- 环境配置:随机化验证环境,例如合理的时钟和外部反馈信号
- 原始输入数据:例如MCDF数据包的长度、带宽、数据间的顺序
- 延时:握手信号之间的时序关系,例如valid和ready,req和 ack之间的时序关系
- 协议异常:如果反馈信号给出异常, 那么设计是否可以保持后续数据处理的稳定性呢?
随机化是为了产生更多可能的驱动,因此在软件世界"class"一侧的运用更多,所以我们倾向于将相关数据有机整理在一个类的同时,也用rand关键词来表明它们的随机属性。
randc表示周期随机性,即所有可能的值都赋过值后随机值才可能重复。
随机属性需要配合SV预定义的类随机函数std::randomize()使用。即只有通过声明rand变量,并且在后期通过对象调用randomize()函数才可以随机化变量。
2、约束(constraint)
- 约束表达式的求解是由SV的约束求解器 (constraint solver)完成的。
- 求解器能够选择满足约束的值,这个值是有SV的PRNG (伪随机数发生器 Pseudo random number generator) 从—个初始值{seed}产生。只要改变种子的值,就可以改变CRT的行为。
- sv标准定义了表达式的含义以及产生的合法值, 但没有规定求解器计算约束的准确顺序。 这即是说,不同仿真器对千同一个约束类和种子值求解出的数值可能是不相同的。
- 什么可以被约束? sv只能随机化2值数据类型, 但位可以是2值或4值。 这即是说, 无法随机化出X值和Z值,也无法随机化字符串。
- 约束块不像自上向下的程序性代码。它们是声明性的代码,是并行的,所有的约束表达式同时有效。
2.1、inside
inside是最常见的约束运算符,表示限定前面命名的变量的取值范围,除非还存在其他约束,否则随机变量在集合里取值的概率是相等的。
一个简单约束的写法:
class date;
rand bit[2:0] month;
rand bit[4:0] day;
rand int year;
constraint c_date {
month inside {[1:12]};
day inside {[1:31]};
year inside {[2010:2030]};
}
endclass
还可以用$来指定最小值和最大值。
rand bit[6:0] b; // 0 <= b <= 127
rand bit[5:0] e; // 0<= e <= 63
constraint c_range {
b inside {[$:4], [20:$}; // 0 <= b <= 4 || 20 <= b <= 127
e inside {[$:4], [20:$}; // 0 <= e <= 4 II 20 <= e <= 63
}
约束中也可以用条件表达式,即在指定条件下,后面的约束才成立。
constraint c_io {
(io_space_mode) -> addr[31] == l'bl; }
constraint c_en_rw {
if (op == READ)
len inside {[1: 10]}
else
len == 10; //约束里用的是==,不是=
}
2.2、内嵌约束
SV允许使用randomize()with来增加额外的约束,这和在类里增加约束是等效的,但同时要注意类内部约束和外部约束之间应该是协调的,如果出现互相违背的清况,那么随机数值求解会失败。
必要的时候可以使用soft来声明约束,这代表当前写的约束属于软约束,如果在后续情况下遇到和soft约束冲突的情况下,soft约束失效。
class Transaction;
rand bit[31:0] addr, data;
constraint cl { soft addr inside {[0: 100], [1000: 2000]};}
endclass
Transaction t;
initial begin
t = new();
// addr is 50-100,
// 1000-1500, data < 10
assert (t.randomize() with {addr >= 50; addr <= 1500;
data < 10;));
driveBus(t);
// force addr to a specific
// value, data > 10
assert(t.randomize() with
{addr = 2000; data > 10;});
driveBus(t);
end
2.3、约束块控制
—个类可以包含多个约束块,可以把不同约束块用于不同测试。
对于其它情况,例如根据不同需要,来选择使能哪些约束块,禁止哪些约束块的要求,可以使用内建的constraint_mode()函数打开或者关闭约束。
0为关闭约束,1为打开约束。
class Packet;
rand int length;
constraint c_short{length inside {[1:32]};}
constraint c_long {lengh inside {[1000:1023]};}
endclass
Packet p;
initial begin
p = new();
p.c_short.constraint_mode(0);
assert(p.randomize ()) ;
transmit(p);
p.constraint_mode(0);
p.c_short.constraint_mode(1);
assert(p.randomize ());
transmit(p);
end
遇到约束冲突时的解决方法
2.4、对数组的约束
//面试的时候数组约束被问了两次,答得稀碎,所以感觉这部分还挺重要的。我连数组的内建函数sum都不知道……废了
sv可以利用foreach对数组的每一个元素进行约束,和直接写出对固定大小数组的每一个元素的约束相比,foreach要更简洁。
针对动态数组,foreach更适合于对非固定大小数组中每个元素的约束。
此外还可以在约束中结合数组的其它方法sum () , product () , and () , or ()和xor () 。
class good_sums;
rand uint len[];
constraintc len {
foreach (len[i]) len[i] inside {[1:255]};
len.sum() < 1024;
len.size() inside {[1:8]};}
endclass
数组求和约束防止溢出。
len.sum with(int'(item)) == 20
如果想要产生一个随机数组,他的每一个元素值都是唯一的,如果使用randc数组,那么数组中的每一个元素只会独立的随机化,并不会按照我们的本意使得数组中的每一个数是唯一的。
class UniqueSlow;
rand bit[7:0] ua[64] ;
constraint C { foreach (ua[i]) //对数组中的每一个元素操作
foreach (ua[j])
if (i!= j) //除了元素自己
ua [i] ! = ua [j] ; //和其它元素比较
}
endclass
如果要约束的是一个二维数组:
class A;
rand bit [11:0] width [];
rand bit [11:0] height [];
rand bit [11:0] rows_cols [][];
constraint width_cst {
width.size() inside{[100:5]};
height.size() inside {[200:700]};}
constraint c {rows_cols.size() == width.size();
foreach(rows_cols[ii])
rows_cols[ii].size == height.size();
}
constraint each_element {foreach(rows_cols[ii,jj])
rows_cols[ii][jj] inside {[1:255]};}
endclass
注意:对于二维数组在约束里的写法,不是rows_cols [ii][jj],而是rows_cols [ii,jj],用一个中括号+逗号写在一起。
3、SV中的随机化函数
$urandom( ) 方法返回一个32bit的无符号整型数据
$random( ) 方法返回的是一个32bit的带符号数据
$urandom_range( )返回一定范围的无符号数据
$urandom_range( int unsigned maxval, int unsigned minval = 0);
关于随机化种子(seed)
variable = $urandom(seed);
seed是一个可选项,如果不设置种子,或者设置种子为None(默认情况下,如果未明确指定种子,random会使用当前系统时间作为种子),则每次运行程序时生成的随机数将不同。
通过设置不同的种子值,可以生成不同的随机数序列。这对于需要多次实验并比较结果的情况非常有用,因为可以确保每次实验使用的随机数序列不同,从而得到更可靠的结果。