一、解的概率
1、没有约束的类
没有约束的两个随机变量
class Unconstrainted;
rand bit x; //0或1
rand bit[1:0] y //0,1,2,3
endclass
2、关系操作
带有关系操作的类
class Imp1;
rand bit x; //0或1
rand bit[1:0] y //0,1,2,3
constraint c_xy{
(x == 0) -> y == 0;
}
endclass
3、关系操作和双向约束
带有关系操作和约束的类
class Imp2;
rand bit x; //0或1
rand bit[1:0] y //0,1,2,3
constraint c_xy{
y > 0; //因为双向,所以x值不可能为0
(x == 0) -> y == 0;
}
endclass
/*
关系操作规定x==0时,y的值为0,但是y==0时,对x的值没有约束。
由于关系操作是双向的,如果y的值为非0值,那么x的值将为1。
*/
4、使用solve…before约束引导概率分布
使用solve…before和关系操作的类
class SolveBefore;
rand bit x; //0或1
rand bit[1:0] y //0,1,2,3
constraint c_xy{
(x == 0) -> y == 0;
slove x before y; //不会改变解的个数,只会改变各个值得概率分布
}
二、控制多个约束块
一个类可以包含多个约束块,可以把不同的约束块用于不同的测试。在运行期间,可以使用内建的constraint_mode()函数打开或关闭约束。可以用handle.constrain.constraint_mode()控制一个约束块,用handle.constraint_mode()控制对象的所有约束。
使用constraint_mode()函数
class Packet;
rand int length;
constraint c_short{length inside {[1:32]};}
constraint c_long{length inside {[1000:1023]};}
endclass
Packet p;
initial begin
p = new();
//通过禁止c_short约束产生长包
p.c_short.constraint_mode(0);
assert(p.randomize());
transmit(p);
//通过禁止所有的约束,然后使能短包约束来产生短包
p.constraint_mode(0);
p.c_short.constraint_mode(1);
assert(p.randomize());
transmit(p);
end
三、有效性约束
设置多个约束以保证随机激励的正确性是一种很好的随机化技术,也成为有效性约束。
使用有效性约束检查写命令的数据字长
class Transaction;
rand enum{BYTE,WORD,LWRD,QWRD} length;
rand enum{READ,WRITE,RMW,INTR} opc;
constraint valid_RMW_LWRD{
(opc == RMW) -> length == LWRD;
}
endclass
四、内嵌约束
SV中允许使用randomize() with来添加额外的约束,这和类里增加约束是等效的。
class Transaction;
rand bit[31:0] addr,data;
constraint c1{addr inside {[0:100],[1000:2000]};}
endclass
Transaction t;
initial begin
t = new();
//addr范围:50-100,1000-1500,data<10;
assert(t.randomize() with {addr >= 50; addr <= 1500; data < 10;}); //相当于在原来的约束范围内新加了一个约束范围
driveBus(t);
//强制addr取固定值,data>10
assert(t.randomize() with (addr == 2000; data > 10;));
driveBus(t);
end
/*
在with{}语句里,SV使用了类的作用域,是addr而不是t.addr
*/
五、pre_randomize和post_randomize函数
有时候需要在调用randomize()之前或之后立即执行一些操作,可以使用两个特殊的void类型的pre_randomize和post_randomize函数。
1、构造浴缸型分布
某些应用里需要产生非线性的随机分布。如短包或长包比中等长度的包更容易发现缓冲器溢出类型的错误。可以通过详细描述的dist约束构造浴缸型的分布。
构造浴缸型分布
class Bathtub;
int value; //浴缸型分布的随机变量
int WIDTH = 50, DEPTH = 4, seed = 1;
function void pre_randomize();
//计算指数曲线
value = $dist_exponential(seed,DEPTH); //非线性分布的函数
if(value > WIDTH)
value = WIDTH;
//把这一个点随机地放在左边或右边的曲线上
if($urandom_range(1))
value = WIDTH - value;
endfunction
endclass
2、关于void函数
因为pre_randomize和post_randomize函数只能调用其他函数,不能调用消耗时间的任务,所以在执行randomize()函数的期间无法产生一段延时。如果想调试随机化过程中出现的问题,可以调用预先准备好的void类型的显示程序来显示中间结果。