基于《IEEE Standard for SystemVerilog — Unified Hardware Design, Specification, and Verification Language》18章的学习和自己的理解。有不对的地方希望大家补充。 编译工具 Cadence的Xcelium。这是第二篇,完成randomize的学习
rand_mode用来控制一个随机变量的状态是active还是inactive,如果随机变量.rand_mode(0) 表示该变量不随机inactive,那么该变量在constarint将作为一个state variable。注意这里是作为一个state variable,这个变量的值还需要满足在constraint block中的约束(soft constraint除外)。
class U;
rand int x;
constraint c{x inside {[0:3]};}
endclass
...
U u1=new();
u1.x =100;
u1.x.rand_mode(0);
assert(u1.randomize()); //会报错,x不在[0:3]的范围内
rand_mode()实际是:
task object[.random_variable]::rand_mode( bit on_off ); //控制当前object/变量的随机开关。
function int object.random_variable::rand_mode(); //返回object的当前的rand_mode()值
object 如果是unpacked array/structure, 可以通过索引/成员的方式控制某个变量。省略索引的话则rand_mode控制所有变量。
object 如果是object handle的话,也可以指定成员的方式控制单个变量,省略的话则控制class的所有变量。
class U;
rand int a,b,x,y;
constraint C{ a==b+1; x==count(y)};
function count(int v);
count = v*2
endfunction
endclass
U u1 =new;
u1.randomize(); //a=5, b=6, x=20 , y=10
u1.randomize(x); //求解成功,因为count(y) 为state variable,所以x=20;
u1.randomize(y); //求解失败
与rand_mode()类似,constraint_mode是控制constraint的状态是active还是inactive的,如果是inactive的话则随机randomize时该约束不再生效。如果没有指定constraint的名字,默认关闭该object中所有的constraint。
task object[.constraint_identifier]::constraint_mode( bit on_off ); //控制当前object的cosntraint的随机开关。
function int object.constraint_identifier::constraint_mode(); //返回object的当前的constraint_mode()值
相比与内建在class的随机,std::randomize更加灵活,不需要定义随机变量,object等。
int x,y,z;
x = randomize(y,z); //调用std::randomize, 随机y,z,求解成功,返回1;
x = randomize(y,z) with {y<z}; //加入约束
$urandom 将产生一个32bit的伪随机数。seed是可选的,每次使用相同的seed会产生相同的随机数序列。
function int unsigned $urandom [ (int seed ) ] ;
int x,y;
y = $urandom(10); x=$urandom(10); // x==y; 因为用了相同seed
y = $urandom(); x= $urandom; //x!=y ; 没有传入seed
注意 这里$random是verilog自带的随机function,它与urandom的区别是:
int x,y;
x = $random;
y = $urandom;
case中seed为1: x=303379748;y= 45886634;
case中seed为2: x=303379748;y= 17496488;
$urandom_range() 产生一个在一定范围内的随机值, 下边界默认是0,可以省略
function int unsigned $urandom_range( int unsigned maxval,
int unsigned minval = 0 );
int x,y;
y = $urandom_range(10); x=$urandom_range(10); // x!=y;
在process中使用,在process中展开介绍。
大家每天都在回归,每次回归时都有大量的随机用例去进行测试,testbench中的 u r a n d o m 、 urandom、 urandom、urandom_range & randomize()调用都会生成不同的随机数,从而导致DUT的不同刺激和配置。发现一个回归失败的用例, 首先要复现它,去进行debug,如果是rtl的bug,在bug fix后,需要使用fail的seed来对它进行测试,灌入相同的激励来验证bug是否修复。能否复现是非常关键的。
所以随机稳定性就是
当年曾经用过一个公司自研CHI VIP,VIP自带的庞大复杂的constraint加上自己的菜鸡代码让一个小小的UT验证跑出了一个子系统验证的速度。
所以如何合理的编写constraint,让求解器跑的更快一些就是非常重要的了。
如何提高求解速度? 那么首先就是要知道求解器是如何工作的,针对基本的原理,对约束进行优化。才是提高求解速度的正确思路。
有人问过 Dave Rich,constraint是如何求解的。
dave的原话;
“The simplest way of explaining how the constraints work is to think of table with columns for each random variable, and a row for each possible combination of values that satisfy the constraints (where all constraint expressions evaluate true). After that, one row gets randomly picked, so all random variable values get selected at once.
Actually implementing it that way would be very inefficient. The LRM does not specify how to implement constrain solvers as long as the behavior essentially matches the simple description I gave“
Dave的意思我理解一下虽然就是IEEE 中没有定义求解器的算法实现,求解器速度的快慢就看各个Vendor各显神通了,但基本原理应该是生成一个包含所有随机变量值的表,表的每一列是每一个随机变量,行是满足约束的每个变量的值, 然后选择某一个行作为结果。
所以我们能做的事情首先想到的就是如何限制这个表的大小:
1.避免冗余的变量,能用byte用byte,能声明位宽声明位宽,不能啥啥都是int。
2.每次随机你只想随机的变量,不需要的就不要随机了,可以通过rand_mode,constraint_mode来控制,最初设计架构时就要有所有考虑。
3. 合理分配哪些变量在pre_randomize,哪些变量在randomize,哪些变量在post_randomize中进行随机,避免所有变量都在constraint中进行随机,有效利用std::randomize()等随机task。一些大的arrays也在post_randomize中进行随机。
4. 将关联性不强的变量组放在独立的seq_item/transaction中,然后将每个小的seq_item、transaction再封装成一个整体。如:一个完整的命令由多个不同的小命令组成,将每个小命令独立为一个seq_item,各个小命令的关联,再完整的命令中体现。
剩下的就只能看公司的IT了,选一个好vendor了。
参考链接:
https://verificationacademy.com/forums/systemverilog/constraint-solver-0
http://www.testbench.in/CR_17_CONSTRAINT_SOLVER_SPEED.html
https://www.systemverilog.io/random-stability