SV随机化约束
CRT机制
- 在复杂数字电路中,完全依赖定向测试(手动编写特定测试用例)难以覆盖所有边界情况和异常场景
- 受约束的随机测试(Constrained Random Testing,CRT)是产生复杂设计所需激励的唯一可行的方法
关键词
rand:声明普通随机变量,随机化范围内的取值概率是等同的,可能重复randc:声明循环随机变量,所有可能值都被取过之前不重复
1 | class Packet; |
约束块
- 通过
constraint块限制随机值的范围,可以使用特定的约束方法生成特定的随机序列
1 | constraint addr_range { |
随机化方法
- 调用
randmozie()方法为随机变量选取满足所有约束条件的新值- 若随机化成功,则返回
1,否则返回0 - 当调用
randomize()函数时只传递变量的一个子集,则只会随机化子集中的变量 randmozie()是类的方法,需要通过对象调用,不能直接作为独立函数使用
- 若随机化成功,则返回
1 | class packet; |
约束方法
唯一值约束
- 唯一值约束来确保一组变量在随机化时被赋予互不相同的值
unique操作符:约束块内使用unique { }包裹变量集合;也可以对数组使用,确保数组中所有元素的值都是唯一的
1 | class Packet; |
范围约束
- 范围约束用于限制随机变量的取值范围,确保随机化值落在指定的区间集合内
- 也可以把集合里的值保存到数组中,再进行范围约束
inside操作符指定范围,!inside指定排除范围
1 | rand bit [7:0] data1, data2, data3; |
- 关系操作符
>,<,>=,<=,==
1 | rand int value; |
条件约束
条件语句
if-else结构
1 | rand bit mode; |
蕴含操作
- 蕴含操作符
->,逻辑上描述为“如果…,那么…”,可用于替代if-else
1 | constraint c_cond_imply { |
- 蕴含操作
A -> B逻辑等价于!A || B,其逆否命题!B->!A有相同的逻辑表达式和真值表
| A | B | A→B,!B->!A |
|---|---|---|
| 真 | 真 | 真 |
| 真 | 假 | 假 |
| 假 | 真 | 真 |
| 假 | 假 | 真 |
1 | constraint c_cond_imply_contra { // c_cond_imply的等价约束 |
- 以上两个蕴含操作的例子都定义了以下行为
addr必须落在之间,否则随机化失败- 当
mode为0时,addr随机约束在之间 - 当
mode为1时,addr随机约束在之间
概率约束
引导顺序
- 使用
solve...before引导约束求解器的求解顺序,间接影响随机结果的概率分布,适用于存在约束关系的变量 - 下例为不引导顺序的蕴含操作,
a随机化概率并不均匀
1 | class Example; |
- 此时若希望
a的随机化概率均匀分布,就可以使用solve...before来引导求解顺序,间接影响概率分布- 告诉约束求解器,先随机化
a在随机化b
- 告诉约束求解器,先随机化
1 | class Example; |
- 上述两例的解空间及概率分布如下
| a | b | 是否合法 | 不引导顺序概率 | 引导顺序概率 |
|---|---|---|---|---|
| 0 | 0 | 是 | 1/5 | 1/8 |
| 0 | 1 | 是 | 1/5 | 1/8 |
| 0 | 2 | 是 | 1/5 | 1/8 |
| 0 | 3 | 是 | 1/5 | 1/8 |
| 1 | 0 | 是 | 1/5 | 1/2 |
| 1 | 1 | 否 | 0 | 0 |
| 1 | 2 | 否 | 0 | 0 |
| 1 | 3 | 否 | 0 | 0 |
权重分布
- 使用
dist操作符直接定义随机结果的概率权重,适用于独立变量 :=操作符:指定单个值的权限,所有权重值是绝对的
1 | rand int opcode; |
:/操作符:指定一个值范围的权重,该权重会平均分配给范围内的每一个值
1 | rand int delay; |
软约束
- 所有约束默认都是硬约束;使用
soft关键词声明的软约束在冲突时可被忽略
1 | class Transaction; |
内嵌约束
- 在调用
randomize()的同时,使用with关键词临时、局部地添加额外的约束
用法
- 可以用来进一步限制变量的取值范围
1 | class Packet; |
- 可以用来临时定义类中变量中的关系
1 | class Transaction; |
- 可以用来引用所在作用域的局部变量
1 | task test_case(int desired_addr); |
优先级
- 内嵌约束的优先级高于类内部定义的约束
1 | class Simple; |
外部约束
- 函数的函数体能在类的外部定义,同样约束的约束体也可以在类的外部定义
- 和类的原型方法一样,外部约束必须事先在原来的类里定义外部约束的原型
- 这种方法只能增加约束,不能改变已有的约束;相比于临时性的内嵌约束,具有更好的可复用性
- 先定义一个只有空约束的类,后续在不同的测试里定义这个约束的不同版本以产生不同的激励
1 | // packet.sv |
迭代约束
随机数组
- 使用
foreach用于约束随机数组的每一个元素
1 | class RandArray; |
随机序列
- 如果想为一个复杂的、多层次的协议生成激励,需要建立一个随机对象数组(随机序列)
1 | class Transaction; //简单事务 |