System Verilog 随机化的使用
对system verilog 随机化操作进行介绍
目录
3.4 pre_randomize和post_randomize的使用
1. 前言
针对复杂的设计,仅依靠定向测试已不能够完全覆盖所有的代码逻辑。因此需要采用受约束的随机测试法(Constrain Random Test)来自动产生非定向测试集。
2. 约束语法
2.1 约束表达式
只可对由位组成的变量(整数、位矢量)进行随机化,字符串不可进行随机。
变量随机化包含三部分,一是采用(rand or randc)进行变量定义;二是采用constraint关键字对变量进行约束;三是采用randomize函数生成随机值。rand和randc关键字区别如下:
rand:每次随机化时,这个变量都会生成一个值,相邻两次两次随机可能会产生一样的值;
randc:周期随机性,当该变量所有可能的值都产生过后,下次随机才会产生一样的值;
约束的表达式如示例,注意要检查随机化的结果,随机化失败,变量可能会生成未知的值。
class packet;
rand logic [3:0] src,dst;
randc logic [9:0] data;
constrain rand_cons {
src > 0;
src < 10;
dst > 0;
}
constrain randc_cons {
data > 100;
}
endclass
module test_tb;
packet p;
initial begin
p = new();
assert(p.randromize()); //随机化成功则返回1,否则返回0触发断言
end
endmodule
除此以外,还可将数学运算加进约束,示例:
class packet;
rand logic [9:0] addr;
rand logic [4:0] odd_dat, even_dat;
constrain addr_cons {
addr % 8 == 0;
}
constrain dat_cons {
odd_dat %2 == 1;
even_dat %2 == 0;
}
endclass
2.2 权重约束
通过使用dist操作符生成不同权重的随机值,dist操作符后面跟一个值或范围,中间用:=或:/分开。两个符号的区别如下:
:= 表示值范围内的每一个值的权重是一样的;
:/ 表示权重均分到值范围内的每一个值;
注意dist后的权重和不一定是100。inside操作符生成权重相同的随机值。示例如下:
class packet;
rand logic [4:0] src,dst;
rand logic [9:0] addr;
constrain addr_cons {
src dist {0:=40, [1:3]:=60};
//src=0, 概率为40/220
//src=1, 概率为60/220
//src=2, 概率为60/220
//src=3, 概率为60/220
}
constrain dst_cons {
dst dist {0:/40, [1:3]:/60};
//dst=0, 概率为40/100
//dst=1, 概率为20/100
//dst=2, 概率为20/100
//dst=3, 概率为20/100
}
constrain addr_cons {
addr inside {[$:10],[100:$]}; //$表示最大值,最小值
//每个值概率一样
}
endclass
2.3 条件约束
通过 "->" 和 "if-else" 操作符让约束块只在某种条件下有效,示例如下:
class packet;
bit en;
rand logic [1:0] src,dst;
rand logic [1:0] addr;
constrain src_dst_cons {
(src==0) -> dst==0; //表示src=0的时候,dst只能取0
}
constrain addr_cons {
if (en !=0 ) {
src inside {[1:3]}; //表示en不等于0时,src在1~3里随机
dst inside {[1:3]};
}
else {
src == 0;
dst == 0;
}
}
使用solve...before约束引导概率分布(只适用于rand操作符),示例如下:
class packet;
rand bit x;
rand logic [1:0] y;
constrain rand_cons {
(x==0) -> y==3;
}
constrain xy_cons {
(x==0) -> y==3;
solve x before y; //表示先驱x的值,再取y的值
}
endclass
rand_cons约束条件下,当x=0,y只能为3;而x=1,y可取0,1,2,3四种组合,所以共有5种组合,每种组合概率相同,均为1/5;如下表:
x | y | 概率 |
0 | 3 | 1/5 |
1 | 0 | 1/5 |
1 | 1 | 1/5 |
1 | 2 | 1/5 |
1 | 3 | 1/5 |
xy_cons约束条件下,先取x的随机值,x=0/1的概率均为1/2;在确定有的取值,概率如下表:
x | y | 概率 |
0 | 3 | 1/2*1=1/2 |
1 | 0 | 1/2*1/4=1/8 |
1 | 1 | 1/2*1/4=1/8 |
1 | 2 | 1/2*1/4=1/8 |
1 | 3 | 1/2*1/4=1/8 |
2.4 双向约束
多个随机变量可以双向约束,示例如下:
class packet;
rand logic [4:0] x, y, z;
constrain xyz_cons {
x < y;
y > 5;
z < x;
x > 1;
}
endclass
2.5 内嵌约束
通过randomize() with语句实现内嵌约束,示例如下:
class packet;
rand logic [3:0] addr;
rand logic [9:0] data;
constrain addr_cons {
addr inside {[0:9], [13:15]};
}
endclass
module test_tb;
packet p;
initial begin
p = new();
assert(p.randromize() with {addr == 0;
data > 100;}); // 强制addr=0,data>10
assert(p.randromize() with {addr > 5;
data > 20;});
end
endmodule
2.6 数组约束
对数组的和、深度和每个值的范围进行约束,示例如下:
class packet;
rand logic [4:0] len[];
constrain len_cons {
len.size() inside {[5:10]};
len.sum < 50;
foreach (len[i])
len[i] inside {[1:4]};
}
endclass
3.约束的使用
3.1 使用非随机值(rand_mode)
经过一段时间的随机化后,有些变量的某些值还没有随机到,可以通过rand_mode函数将这些变量设置为固定值,示例如下:
class packet;
rand logic [3:0] addr;
rand logic [9:0] data;
constrain addr_cons {
addr inside {[0:9], [13:15]};
}
endclass
module test_tb;
packet p;
initial begin
p = new();
assert(p.randromize());
...
p.data.rand_mode(0);
p.data = 541;
assert(p.randromize()); //生成的data值固定为541,addr随机
end
endmodule
3.2 随机化个别变量
只对类中的某几个变量进行随机,示例如下:
class packet;
rand logic [3:0] addr;
rand logic [9:0] data;
constrain addr_cons {
addr inside {[0:9], [13:15]};
}
endclass
module test_tb;
packet p;
initial begin
p = new();
assert(p.randromize(addr)); //随机化addr
assert(p.randromize(data)); //随机化data
end
endmodule
3.3 打开/关闭约束(constraint_mode)
采用constraint_mode函数将某些变量的约束关掉,示例如下:
class packet;
rand logic [3:0] addr;
rand logic [9:0] data;
constrain addr_cons {
addr inside {[0:9], [13:15]};
}
constrain data_cons {
data inside {[10:105]};
}
endclass
module test_tb;
packet p;
initial begin
p = new();
p.constraint_mode(0); //关闭所有变量的约束
p.addr_cons.constraint_mode(1); //打开addr的约束
assert(p.randromize());
end
endmodule
3.4 pre_randomize和post_randomize的使用
pre_randomize和post_randomize为void类型函数,不需要单独调用。无返回值,不能消耗时间,不能有阻塞操作,可以由用户重写。类随机化的执行顺序为:
pre_randomize() -> randomize() -> post_randomize()
因此可以在pre_randomize函数里设置一些约束权重,约束上下限等,在post_randomize函数里计算一些随机数据等。示例如下:
class packet;
rand bit[7:0] x,y,z;
bit en = 0;
constrain xyz_cons {
if(a==0)
z==x+y;
else
z==x;
}
function void pre_randomize();
en = 1;
endfunction
function void post_randomize();
z = y;
endfunction
endclass
module test_tb;
packet p;
initial begin
p = new();
assert(p.randomize());
end
endmodule
4. 随机化函数
随机化函数 | 功能 |
$random() | 平均分布,返回32位有符号随机数 |
$urandom() | 平均分布,返回32位无符号随机数 |
$urandom_range() | 指定范围内的平均分布,必须指定上限,下限可选 |
$dist_exponential() | 指数衰落 |
$dist_normal() | 钟型分布 |
$dist_poisson() | 钟型分布 |
$dist_uniform() | 平均分布 |
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)