SystemVerilog 第6章 随机化
6.1 介绍
- 定向测试可以找到你认为可能存在的bug,而CRT(受约束的随机测试方法)可以找到你都无法确定的bug
6.2 随机化用途
- 器件配置、环境配置、原始输入数据、封装后的输入数据、协议异常、延时、事务状态、错误(error)和违规(violation)
- 关于延时:时钟发生器应该位于测试平台之外的一个模块
6.3 SV的随机化
6.3.1 随机变量
- 随机变量的声明和使用
class Packet;
rand bit [31:0] src;
endclass
program test;
Packet p=new();
p.randomize();
endprogram
- randc表示周期性随机,所有可能值都赋值过后随机值才会出现重复
- 构造函数是用来初始化的变量的,不要在new()函数中对变量进行随机
6.3.2 检查randomize结果
- 使用断言assert(p.randomize());检查随机化结果,成功返回1,失败返回0
- 可以指定断言失败后的显示,格式如下:
//格式1:断言成功后跟语句,需要加分号
assert(p.randomize())
command1;
else
$fatal(0,"Packet::randomize failed");
//格式2:断言成功没有语句,不要加分号
assert(p.randomize())
else
$fatal(0,"Packet::randomize failed");
6.3.3 约束求解
- 约束表达式的求解式有SV的约束求解器完成的
6.3.4 可随机化的数据类型
- 整型变量(integeral),有位组成的变量(bit类),packed struct,enum
6.4 约束
6.4.1 约束定义
- 约束是一组关系表达式,约束用 “{}” 包住,每条关系表达式写成一条语句
- 格式:用 {} 包住
class Packet;
rand bit [31:0] src;
constraint c_stim {
src < 100;
src > 10;
}
endclass
6.4.2 布尔表达式
- 一条关系表达式中只能使用一个关系操作符(<,<=<,==,>=,>)
6.4.3 等效表达式
- 约束块中只能包含关系表达式,因此 == 关系表达式作用相当于赋值
6.4.4 权重分布
- :=后面跟的权重值即为每个变量取值得的权重(相同)
- : /后面跟的权重值要平均分到每一个变量取值
- 变量取值可以是一个范围 [lo:hi],权重可以是变量
constraint c_dist {
length dist {0:=40,[1:3]=60};
}
6.4.5 inside+集合(set)
- inside后面跟的{}表示的是一个集合,里面元素用逗号 “,” 分割
- $可以代表最大值和最小值
- 集合的补集可以使用 ! 操作符
c inside {[$:4],[20:$]};
!(c inside {[$:4],[20:$]});
6.4.6 集合中使用数组
- 可以将数组放入集合中,形成inside+集合的约束语句
6.4.7 条件约束
- ->类似于case语句
- if…else中的语句块要使用 {} 包住,不可以使用begin…end,因为约束是声明性语句,不是过程语句
//->
constraint c_io {
io_space_mode -> addr == 1'b1;
}
//if...else
constraint c_len_rw {
if(op==READ) {
len inside {[lo:hi]};
}
else {
len == LWRD;
}
}
6.4.8 双向约束
- 关系表达式中左边和右边的变量是相互牵制的,如果有一边的值已经确定下来,则另一边的选择会自动被约束
6.4.9 数学方法的选用
- 约束求解器对简单的 加、减、位提取和移位处理快;对乘、除、取模(取余数)运算量大
- 可以用位提取或 & "mask"操作代替取模;用移位代替除法和乘法
6.5 解的概率
- 没有约束的类
所有解的概率都相同 - 关系操作的类
所有满足约束的解的概率都相同 - 关系操纵+randc
① 有randc时候,先对randc的变量进行随机,randc的变量每一个取值对应的系列解的”概率和”相等
② 当有多个randc变量时,randc的变量之间会相互制约,关系表达式作用方向式双向的,即 x==0 -> y==0约束中x, y都是randc的话,y==0时候x也必须为0 - 关系操作+双向约束
约束块里的条件表达式相互影响 - solve…before…
① solve…before…控制变量随机的顺序,会改变解的概率,但不会改变解的值;其作用相当于randc
② solve…before…表达式中的变量不可以是randc类型的
constraint c_xy {
x==0 -> y==0;
solve x before y;
}
6.6 控制多个约束块
- constraint_mode()
p.constraint_mode(0); //close all constraint
p.c_xy.constraint_mode(0); //only close c_xy constraint block
- rand_mode()
p.rand_mode(0); //close all randmoize
p.x.rand_mode(0); //close x randmoize
- randomize(variable)
非随机变量被作用后也会被随机
p.randmoize(x); //only open x randmoize
- randomize() with {}
约束块的补充,和class中的约束块是平级的,解取两者交集
p.randomize() with {...}; //对class约束块的补充
6.7 有效性约束
6.8 内嵌约束
- 即class内默认约束块,randomize() with {};语句是其补充
6.9 pre/post_randomize()
- randomize()调用时候会默认调用pre/post_randomize()函数,不论randomize()时候调用成功,pre_randomize()都会执行;post_randomize()只有再randomize()函数成功执行后才会执行
6.9.1 浴缸型分布
- 可以再pre_randomize()函数中调用$dist_exponential函数构造浴缸分布变量
6.9.2 void函数
- pre/post_randomize()函数是void函数,因为是函数所以不含时序,不能有延时
6.10 随机函数
function | distribution | datatype |
---|---|---|
$random() | 平均分布 | 32 signed |
$urandom() | 平均分布 | 32 unsigned |
$urandom_range() | (指定区间)平均分布 | |
$dist_exponential() | 指数衰落 | |
$dist_normal() | 钟型分布 | |
$dist_poisson() | 钟型分布 | |
$dist_uniform() | 平均分布 |
- $urandom_range(x,y)函数平均分布结果的范围为[x,y] (若x>y则为[y,x]);只有一个参数x时对应区间为[0:x]
6.11 约束的技巧和技术
6.11.1 带变量的约束
- 布尔表达式中使用变量
- dist约束中使用权重变量(设置权重为0即禁止)
6.11.2 使用非随机值
- p.lenth.rand_mode(0) //关闭rand变量lenth的随机
6.11.3 用约束查看数据有效性
- handle.randomize(null) //不随机变量,只查看数据是否满足约束条件
6.11.4 随机化个别变量
- p.randomize(length) //只随机化length
- 可以采用该方法对一个非随机变量进行随机
6.11.5 打开或关闭约束
- 使用条件操作符从而执行不同约束(->或if…else…)
- p.constraint_mode(0) //关闭所有constraint
- p.c_length.constraint_mode(0) //关闭c_length
- 关闭一个约束时候,也损失了该约束的有效性检测功能
6.11.6 测试过程中使用内嵌约束
- class中定义的约束即为内嵌约束,可以使用randomize() with {…}来扩展内嵌约束
6.11.7 测试过程中使用外部约束
- 可以像类的外部函数那样定义外部约束
- 定义格式
class Packet;
...
constraint c_length;
endclass
constraint Packet::c_length {
...
}
- 注意:
①不用写 extern关键字
②外部约束和class一同放到program/module外的单独文件中
③用 `include “Packet.sv”+外部约束的形式放于top模块内部或外部皆可
④外部约束对所有的实例的对象都有效(因为涉及到class的作用域)
6.11.8 扩展类
- 子类中定义和父类同名的constraint,约束会发生重载
6.12 随机化的常见错误
6.12.1 有符号变量
- 符号:尽量避免使用有符号类型变量
- 位宽: 约束值得位宽应比变量位宽多一位,避免数据溢出
6.12.2 提高求解器性能
- 避免使用复杂运算:乘法,除法,取模(%)
- 用移位代替乘除
- 用 “&+掩模” 作用于变量代替取模
6.13 数组/队列约束
6.13.1 数组的大小
constraint c_len {
len.size() inside {[1:10]};
}
6.13.2 元素的和
- len.sum()
- 注意数据溢出:和的位宽是和数组元素相同的
6.13.3 数组约束
- 变量的符号类型
- 约束值得位宽应该比变量多一位
- 使用foreach()循环对元素遍历
6.13.4 约束每一个元素
- 即使用foreach()循环
- 每个foreach约束中只能有一个数组名,不允许使用层次化引用(foreach中调用子类)
6.13.5 产生唯一元素值的数组
- 使用包含randc变量得辅助类
6.13.6 随机化句柄数组
- 随机前要分配好所有元素,然后再通过约束限定数组大小(约束求解器不能创建对象)
parameter max_size = 10;
class randstuff;
rand int value;
endclass
class randarray;
randstuff array[];
constraint c_array {
array.size() inside {[1:max_size]};
}
function new();
array = new{max_size];
foreach(array[i])
array[i]=new();
endfunction
endclass
6.14 产生原子激励和场景
wait update
6.15 随机控制
wait update
6.16 随机数发生器
wait update
6.17 随机器件配置
wait update