随机化技术
随着设计变得越来越大,要产生一个完整的激励集来测试设计的功能也变得越来越困难。
解决的办法是采用受约束的随机测试法(CRT)自动产生测试集。
1.什么需要随机化
对DUT(待测设计)里所有关键点都采用随机化的技术。随机化使控制路径里的每个分支都可能被测试。
需要考虑的方面:
- 器件配置
- 环境配置
- 原始输入数据
- 封装后的输入数据
- 协议异常
- 延时
- 事务状态
- 错误和违规
2.随机变量类型和方法
随机化变量以及随机约束都只能在class中声明变量,class中的局部变量也不能修饰
- rand随机变量的值在指定范围内均匀分布,如果不添加约束,随机变量可以是指定有效范围内的任何值
- randc 声明周期性随机变量,取值按照声明的有效范围周期性出现,且数据类型只可以是bit或enum
- randomize() 方法,如果随机化成功,则返回1,否则返回0
- constraint_mode() 函数打开或关闭约束
- rand_mode() 函数可以打开或关闭随机变量
//随机化范围根据位宽为0~15
rand bit[3:0] addr1;
//y为2bit无符号整形数,取值范围:0~3,在一个周期内必然会产生0、1、2、3四个数、顺序不定
//即所有可能值都取过之后随机值才可能重复
randc bit[1:0] addr2;
//关闭
packet.c.constraint_mode(0)
packet.addr1.rand_mode(0)
//打开
packet.c.constraint_mode(1)
packet.addr1.rand_mode(1)
例子:
//class
class packet;
rand bit [2:0] addr1;
rand bit [2:0] addr2;
constraint c {
add1 >2;
add2 <5;
}
endclass
module rand_methods;
initial begin
packet pkt;
pkt = new();
repeat(10) begin
pkt.randomize();
$display("\taddr1 = %0d \t addr2 = %0d",pkt.addr1,pkt.addr2);
end
end
endmodule
3.随机化约束constraint
- 使用关键字constraint来添加约束语句块,指定随机变量的取值范围,或者各个变量之间的相互关系
-约束块是并行的,所有约束表达式同时有效
3.1关系操作符约束(>、<、=、>=、<=)
在一个表达式中最多只能使用一个关系操作符,不能连续使用
声明一个约束:0<a<b<c
class Bus
rand bit[15:0] a,b,c;
constraint c1 {
0 < a;
a < b;
b < c;
}
endclass
3.2 范围操作符约束(inside)
class Bus;
rand int c;
int lo,hi;
constrant c_range{
c inside {[lo:hi]};
//等价于lo<=c并且c<=hi
!(c inside {[lo:hi]});//对约束集合的取反
}
endclass
3.3条件约束(if-else;- >)
通常约束块里的约束表达式都是有效的,如果想让约束在某些时刻有效,可以使用条件约束。
- - > 操作符可以产生和case操作符同效果的语句块,可以用于枚举
- if - else 更适合“真假”类型的表达式
class BusOp;
...
constraint c_io {
(io_space_mode) - >
addr[31] == 1'b1;
}
constraint c_len_rw{
if(op == READ)
len inside {[BYTE:LWRD]};
else
len == LWRD;
}
endclass
3.4 双向约束
SV的约束是双向的,这代表它会同时计算所有随机变量的约束,增加或删除任何一个约束都有可能对随机变量的取值产生影响。
class Bus;
rand logic [15:0] r,s,t;
constraint c_bidir{
r < t;
s == r;
t < 30;
s > 25;
}
endclass
SV同时计算四个约束表达式,根据约束之间的限定,下表列出了三个变量的各种取值:
3.5内嵌约束randomize()with{}
SV允许使用 randomize()with{} 来增加额外的约束,这和在类里增加约束是等效的。
class packet;
rand bit [2:0] addr1;
rand bit [2:0] addr2;
endclass
module rand_methods;
initial begin
packet pkt;
pkt = new();
assert(pkt.randomize()with{addr1 >= 2;addr <= 5;});
$display("\taddr1 = %0d \t addr2 = %0d",pkt.addr1,pkt.addr2);
end
end
endmodule
4.权重分布
dist操作符允许产生权重分布,这样某些值的选取机会要比其他值更大一些。
符号用 : = 或者 : /
- : = 表示值范围内每个值的权重都是相同的
- : / 表示权重要平均分配到范围内的每个值
40+60*3=220
40+60=100
rand int src,dst;
constraint c_dist{
src dist {0:=40,[1:3]:=60};
dst dist {0:/40,[1:3]:/60};
}
5.数组约束
5.1约束数组中的元素
用foreach对数组的每个元素进行约束
用randc产生一个随机数组,每一个元素的值都是唯一的,但要经过特殊处理
方法 | 释义 |
---|---|
size() | 对数组的长度限定 |
sum() | 求和 |
product() | 求积 |
and() | 求与 |
or() | 或 |
xor() | 异或 |
class good
rand uint len[];
constraint c_len {
foreach (len[i]) len[i] inside {[1:255]};
len.sum() < 1024;
len.size() inside {[1:8];};
}
endclass
5.2利用randc变量产生唯一元素值的数组
class randc8;
randc bit [7:0] val;
endclass
class LittleUniqueArray;
bit [7:0] ua[64];
function void pre_randomize();
randc8 rc8;
rc8 = new();
foreach (ua[i]) begin
assert(rc8.randomize());
ua[i]=rc8.val;
end
endfunction
endclass
5.3 随机化句柄数组
如果要产生多个随机对象,就需要建立随机句柄数组。
随机句柄数组的声明一定要加rand来表示随机化的属性,同时在调用随机函数前,要保证数组中每一个句柄元素都非悬空的,故需要在随机化之前为每一个句柄元素构建对象
parameter MAX_SIZE = 10;
class RandStuff;
bit[1:0] value = 1;
endclass:RandStuff
class RandArray;
rand RandStuff array[];
//约束数组大小
constraint c{
array.size() inside {[1:MAX_SIZE];}
}
function new();
//分配最大容量
array = new[MAX_SIZE];
foreach(array[i])
array[i] = new();//保证数组中每个句柄元素都非悬空
endfunction
endclass:RandArray
RandArray ra;
initial begin
//构造数组和所有对象
ra = new();
//随机化数组但可能会减小数组
assert(ra.randomize());
foreach(ra.array[i])
$display(ra.array[i].value);
end