在芯片验证过程中,经常需要对驱动数据进行随机化处理和约束,来实现更多和更有效率的验证场景覆盖。在SystemVerilog中通常有以下三种方式进行随机化处理和约束:1)系统函数$random();2)标准库函数std::randomize();3)面向对象的函数randomize()。
1. 系统函数$random()
首先,是第一种随机方式,调用$random()及同类型函数。
# | 函数 | 返回值 | |
1 | $random(reg/integer/time seed) | 32bit有符号数 | |
2 | $urandom(reg/integer/time seed) | 32bit无符号数 | |
3 | $urandom_range(int unsigned maxval, int unsigned minval) | 32bit指定范围内的无符号数 |
$random()和$urandom()可以通过指定函数种子来进行随机数生成,种子的类型需要为reg,整型或时间型变量。
variable = $random(seed); //直接生成有符号数
variable = $random % 60; //通过取余来获取一定范围内的有符号数,-59 ~ 59
variable ={$random % 60}; //通过拼接符,将其转换为无符号数,0 ~ 59
$urandom_range()则可以通过指定参数,获取一定范围的无符号数。需要注意的是,第一个参数为最大值,第二个参数为最小值。当输入参数发生调换时,系统可以自动调换最大值和最小值。同时,由于参数列表第一个为最大值,所以当指定一个参数时,为默认最大值,而未指定的最小值参数默认为0。
variable = $urandom_range(10,4); //生成范围为4~10的无符号数
variable = $urandom_range(4,10); //生成范围为4~10的无符号数
variable = $urandom_range(10); //生成范围为0~10的无符号数,最小值未指定默认为0
2. 标准库函数std::randomize()
其次,通过调用标准库函数std::randomize()同样可以实现变量的随机化以及更灵活的约束,该约束条件的使用语法在后面章节进行讲述。
bit [3:0] variable;
std::randomize(variable); //随机化变量范围0~15
std::randomize(variable)with{/*约束条件*/}; //可使用灵活的约束进行范围内随机
3. 面向对象函数randomize()
最后,通过对对象调用randomize()函数,同样可以对class内部有rand或randc修饰的变量进行有约束的随机化。在待随机对象内部可以添加约束,对变量的范围进行指定。而在对改对象进行随机化时,同样可以使用with进一步指定约束条件,但必须保证该约束条件是待随机对象内部约束条件的子集,否则发生约束冲突时,将随机化失败。解决该问题的一个方法是,在待随机对象内部的约束使用soft进行修饰,将该约束变为软约束,可以被更上层的随机约束覆盖。
class val_obj0;
rand bit [3:0] variable; //通过rand修饰变量,纯随机
constraint val_cons {/*约束条件*};
endclass
class val_obj1;
randc bit [3:0] variable; //通过randc修饰变量,周期性随机(随机遍历所有值)
constraint val_cons {/*约束条件*};
constraint val_cons {soft /*软约束条件*};
endclass
class top_obj;
val_obj0 obj0;
val_obj0 obj1;
function new();
obj0 = new();
obj1 = new();
val.randomize();
val.randmize()with{/*约束条件*/}; //当约束条件与对象内部约束条件冲突时,随机失败;
//当对象内部约束条件为软约束时,可覆盖软约束;
endfunction
endclass;
4. 随机约束
标准库std::randomize()函数和面向对象的randomiz()函数进行数据的随机过程中,都可以通过"with{约束条件;}"的方式进一步约束随机范围,生成自己更关注的数据。通常,除了上述我们进行随机的函数外,还有constraint语句,以及`uvm_do_with宏等需要添加约束条件,其语法与上述相同,均是通过"with{约束条件;}"的方式进行。
std::randomize(variable)with{约束条件1;约束条件2;};
val_obj.randomize()with{约束条件1;约束条件2;};
constraint val_cons {约束条件1;约束条件2;}
`uvm_do_with(tr,{约束条件1;约束条件2;});
约束条件一般为表达式,主要分为以下几种:
- 设定约束范围;
- 设定约束权重;
- 设定约束条件;
- 设定约束优先级;
以下约束语法的举例以constraint为例。
(1)对于约束范围指定,可以使用关系操作符(>,<,>=,<=,==)或者inside语句来指定随机范围,且一个表达式中只能有一个操作符。
//设定约束范围
constraint val_cons {variable < 10; variable > 4;}
constraint val_cons {variable inside {[4:10]};} //在使用[4:10]注意从小到大
(2)对于约束权重的指定,可以使用dist来完成,分为':='和':/'两种权重分布,分别代表统一权重值和均分权重值。
//权重分布
//1的权重为4,概率为4/22; 3~10的每个值的权重为6, 每个值的概率为3/22
constraint val_cons {variable dist {0 := 4, [1:3] := 6};}
//1的权重为4,概率为4/10; 3~10的所有值权重和为6, 每个值的概率为1/10
constraint val_cons {variable dist {0 :/ 4, [1:3] :/ 6};}
(3)对于约束条件的设定,可以使用if-else语句,'->'操作符。
constraint val_cons {if(a) variable > 5; else variable < 5;}
cosntraint val_cons {a -> variable > 5; ~a -> variable < 5;}
(4)对于约束优先级的设定,可以使用solve-before语句进行,完成关联约束的随机先后顺序指定。
constraint a_cons {a > 10;}
constraint b_cons {b > a;}
constraint order {solve a before b;} //完成a的随机化后,再随机b