背景:验证两种方法一种是直接用例,指哪打哪,即遍历每一个具体的例子;另一种是随即用例:全面打击,覆盖意想不到的地方。直接用例在测试量很大时费时费力。
1.为什么使用随机
使验证能朝着可量化流程方向发展;让可测激励空间的向量更加容易枚举。提高验证的效率。
特点:1)自动生成测试随机激励 : 改变驱动DUT的数据特性
2) 随机选择测试用例 : 随机运行已知的有效测试
3)随机测试平台中的参数 : 随机选择端口,地址,操作参数等。
2.randomization 随机化
(1)类中的变量可以用关键字rand与randc来随机化取值。其中整数型变量、数组、数组大小、对象句柄可以被以上两个关键字修饰。
class packet;
rand reg[16:0] length; //0~16取到的概率是项等的
randc reg [7:0] types; //randc表示周期性随机,即所有的可能值都取过之后随机值才可能重复;
(2)randomize()
随机成员如果要随机化,必须由被例化的对象显示调用系统随机函数randomize()
举例说明
//class
class packet;
rand bit [2:0] addr1;
randc bit [2:0] addr2;
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)rand_mode()
通过修改rand_mode()的参数值,可以允许或禁止随机化;默认情况下参数为1;语法格式如下:
addr.rand_mode(0); //参数为0表示禁止随机化
packet.addr.rand_mode(0);
对象名.成员名.rand_mode(0);//关闭成员的随机化
对象名.rand_mode(0);//关闭所有成员的随机化
class Fruits;
rand bit [3:0] var1;
rand bit [1:0] var2;
endclass
module tb;
initial begin
Fruits f = new();
$display ("Before randomization var1=%0d var2=%0d", f.var1, f.var2);
f.var1.rand_mode (0);// 关闭var1的随机化
// Print if var1 has randomization enabled/disabled
if (f.var1.rand_mode())
$display ("Randomization of var1 enabled");
else
$display ("Randomization of var1 disabled");
f.randomize();
$display ("After randomization var1=%0d var2=%0d", f.var1, f.var2);
end
endmodule
3.随机化中的约束
为什么要约束?
纯粹的随机激励需要很长时间才能产生有意义的效果;约束能使有意义的效果产生的概率提升;默认情况下,约束条件的每个可能解决方案都具有相同的可能性,可以创建(distributions)来修改它;约束和分配的权重可以构成测试工作平台的基础激励。
(1)约束的主要种类
集合成员约束: inside;
权重分布(weighted distribution): dist;
唯一性约束(unique constraints):unique
条件约束: if-else
迭代约束 : foreach
(1.1)集合成员约束 : inside
用inside操作符产生一个随机数的集合,随机变量在这个集合中选取,且每个值取到的概率相同。
实例如下:
constraint addr_range {addr inside {1,3,4,6,9};}
constraint addr_range { addr inside {[5:10]}; }
constraint addr_range { addr inside {1,3,[5:10],12,[13:15]}; }
constraint addr_range { addr !(inside {[5:10]}); }//对范围取反
集合可以是范围,也可以是多个数的列举,还可以对范围进行取反操作等
rand bit [3:0] start_addr;
rand bit [3:0] end_addr;
rand bit [3:0] addr;
constraint addr_range { addr inside {[start_addr:end_addr]}; }//范围的边界也可以是随机值
下面看例子
class packet;
rand bit [3:0] addr_1;
rand bit [3:0] addr_2;
rand bit [3:0] start_addr;
rand bit [3:0] end_addr;
constraint addr_1_range { addr_1 inside {[start_addr:end_addr]}; }
constraint addr_2_range { !(addr_2 inside {[start_addr:end_addr]}); }
endclass
module constr_inside;
initial begin
packet pkt;
pkt = new();
$display("------------------------------------");
repeat(3) begin
pkt.randomize();
$display("\tstart_addr = %0d,end_addr = %0d",pkt.start_addr,pkt.end_addr);
$display("\taddr_1 = %0d",pkt.addr_1);
$display("\taddr_2 = %0d",pkt.addr_2);
$display("------------------------------------");
end
end
endmodule
结果如下
(1.2)权重分布(weighted distribution): dist;
dist操作符产生随机数的权重分布,不同值出现的概率不同。dist操作符带有一个值的列表以及相应的权重,中间用 := 或 :/ 分开。:=操作符表示范围内的每个值的权重是相同的,:/表示权重要均分到每一个值。
addr dist { 2 := 5, [10:12] := 8 };
//addr = 2 , weight 5
// addr = 10, weight 8
//addr = 11, weight 8
//addr = 12, weight 8
addr dist { 2 :/ 5, [10:12] :/ 8 };
//addr = 2 , weight 5
// addr = 10, weight 8/3
// addr = 11, weight 8/3
//addr = 12, weight 8/3
例子
class packet;
rand bit [3:0] addr;
constraint addr_range { addr dist { 2 := 5, 7 := 8, 10 := 12 }; }
endclass
module constr_dist;
initial begin
packet pkt;
pkt = new();
$display("------------------------------------");
repeat(10) begin
pkt.randomize();
$display("\taddr = %0d",pkt.addr);
end
$display("------------------------------------");
end
endmodule
输出结果:
class packet;
rand bit [3:0] addr_1;
rand bit [3:0] addr_2;
constraint addr_1_range { addr_1 dist { 2 := 5, [10:12] := 8 }; }
constraint addr_2_range { addr_2 dist { 2 :/ 5, [10:12] :/ 8 }; }
endclass
module constr_dist;
initial begin
packet pkt;
pkt = new();
$display("------------------------------------");
repeat(10) begin
pkt.randomize();
$display("\taddr_1 = %0d",pkt.addr_1);
end
$display("------------------------------------");
$display("------------------------------------");
repeat(10) begin
pkt.randomize();
$display("\taddr_2 = %0d",pkt.addr_2);
end
$display("------------------------------------");
end
endmodule
输出结果
通过solve...before改变权重
class ABC;
rand bit a;
rand bit [1:0] b;
constraint c_ab { a -> b == 3'h3; }
endclass
module tb;
initial begin
ABC abc = new;
for (int i = 0; i < 8; i++) begin
abc.randomize();
$display ("a=%0d b=%0d", abc.a, abc.b);
end
end
endmodule
各种值的概率:
在约束中加上solve..before的情况:
class ABC;
rand bit a;
rand bit [1:0] b;
constraint c_ab { a -> b == 3'h3;
// Tells the solver that "a" has
// to be solved before attempting "b"
// Hence value of "a" determines value
// of "b" here
solve a before b;
}
endclass
module tb;
initial begin
ABC abc = new;
for (int i = 0; i < 8; i++) begin
abc.randomize();
$display ("a=%0d b=%0d", abc.a, abc.b);
end
end
endmodule
取值概率:
(1.3)唯一性约束(unique constraints):unique
在随机化过程中,可以使用唯一约束生成变量集或数组中唯一元素的唯一值 .
唯一约束允许:
跨变量生成唯一值;在数组中生成唯一元素
class unique_elements;
rand bit [3:0] var_1,var_2,var_3;
rand bit [7:0] array[6];
constraint array_c {unique {array};}//唯一约束,关键字unique
function void display();
$display("var_1 = %p",var_1);
$display("var_2 = %p",var_2);
$display("var_3 = %p",var_3);
$display("array = %p",array);
endfunction
endclass
program unique_elements_randomization;
unique_elements pkt;
initial begin
pkt = new();
pkt.randomize();
pkt.display();
end
endprogram
结果
累了。。。