目录
1.控制多个约束块儿constraint_mode()
2.控制随机变量
2.1 rand_mode()
2.2 randomize() with {}
2.3 randomize单独控制变量
3.回调函数 pre_randomize和post_randomize
4.约束的重载(覆盖 )
4.1使用constraint_mode(0)关闭约束后用randomize_with{}重新定义约束
4.2子类extends父类,然后定义同名约束覆盖父类的约束
如果在一个类中定义了多个约束块儿,以便为了后续根据实际需要打开所需的约束块儿时,该如何操作?(就像一个筋膜枪,你要根据实际需要调节频率(约束频率范围))
具体讲解在代码注释中讲解
class Packet;
rand int length;
//以下2个约束块儿互相排斥,切不可将2个约束块儿同时打开,否则会随机出错误结果
constraint c_short//定义约束1<=length<=32
{
length inside {[1:32]};
}
constraint c_long //定义约束1000<=length<=1023
{
length inside {[1000:1023]};
}
endclass
program test;
Packet p;
initial begin
p = new();
p.c_short.constraint_mode(0); //关闭c_short约束块儿
assert(p.randomize());//此时length只在1000-1023中随机
$display("P:length is %d",p.length);//1000-1023
p.constraint_mode(0); //关闭所有约束条件
p.c_short.constraint_mode(1); //打开c_short约束
assert(p.randomize());//此时length只在1-32中随机
$display("P:length is %d",p.length);//1-32
end
endprogram
如果我们在一个类中定义了n个随机变量,在后续调用该类的时候,我们想根据实际需要控制类中的某个变量是否要随机化,该如何操作?
关键词:类实例化名.变量名.rand_mode(0关闭/1开启)
class Packet;
rand bit [7:0] length, payload[];
constraint c_valid
{
length > 0;
payload.size() == length;
}
endclass
program test;
Packet p;
initial begin
p = new();
p.length.rand_mode(0); //关闭length的随机功能
p.length = 42; //未现在不随机的length赋值
$display("P:length is %d",p.length);//42
assert (p.randomize());
p.length.rand_mode(1); //打开length的随机功能
$display("P:length is %d",p.length);//0-255
end
endprogram
如果我们定义了一个类,在后续调用时想在原来约束的基础上进一步加约束该如何操作?
关键词:类实例化名.randomize()with{所需约束}
class Transaction;
rand bit [31:0] addr, data;
constraint c1
{
addr inside{[0:100],[1000:2000]};
}
endclass
program test;
Transaction t;
initial begin
t = new();
assert(t.randomize() with {addr >= 50; addr <= 1500; data < 10;});//在c1的基础上进一步约束范围
$display("t::addr=%d,data=%d",t.addr,t.data);//addr is 50-100 or 1500-2000,data is 0-10
assert(t.randomize() with {addr == 2000; data > 10;});//addr赋值2000,data大于10
$display("t::addr=%d,data=%d",t.addr,t.data);//addr is 2000,data 大于10
end
endprogram
若外部所加约束与内部约束冲突,则看内部约束是否加了soft关键字,若加了则以外部约束为准,若没加则报错
该方法和2.1类似,都是对单个变量是否随机化进行操作,所不同的是操作方式
关键词:类句柄.randomize(变量名)。表示只随机该变量,其它变量不随机
class Rising;
byte low;
rand byte med, hi;
constraint c_up
{
low < med;
med < hi;
}
endclass
program test;
Rising r;
initial begin
r = new();
r.randomize(); //对所有随机变量在约束上进行随机
r.randomize(med); //只随机med,hi保持上一个值
r.randomize(low); //只随机low,但low不是随机变量,med和hi保持上一个值
end
endprogram
回调函数是指在父类中定义一个空方法,然后在不同子类中实现这些空方法
他们都是function, 不消耗仿真时间;
只要调用了randomize函数,在执行randomize函数之前先执行pre_randomize函数,再执行randomize函数,最后执行post_randomize函数。他们通常用来设置一些非随机的变量或者计算随机数据中的错误,如果如randomize调用失败,那么post_randomize将不会被执行,但是pre_randomize不管 randomize是否成功都会执行。
class wr_tran;
int constraint_en;
int broadcast;
rand int wr_addr;
rand int wr_data;
rand bit valid;
constraint generic_c
{
valid ==1;
wr_addr<100;
}
function void pre_randomize();//定义预处理函数
$display("call the pre_randomize !");
if(!constraint_en)
generic_c.constraint_mode(0);
endfunction
function void post_randomize();//定义后处理函数
$display("call post_randomize !");
if(wr_addr ==1)
broadcast =1;
else
broadcast =0;
endfunction
endclass
module m1;
wr_tran tr;
initial begin
tr =new();
tr.constraint_en=0;//为pre_randomize提供条件
tr.randomize() with {tr.wr_addr==200;tr.wr_data==3;tr.valid==0;};
$display("tr.wr_addr=%d,tr.wr_data=%d,tr.valid=%d,tr.broadcast=%d",tr.wr_addr, tr.wr_addr,tr.valid,tr.broadcast);
end
endmodule
执行结果如图所示:
可见先打印了pre中的字符串,然后执行randomize为几个变量定值,然后执行post函数打印字符串,由于wr_addr 赋值为3,所以broadcas为0。
具体解释见下面代码注释
class constrainend;
rand bit x;
rand bit [1:0] y;
constraint c_xy //对x,y定义约束
{
(x==0)-> y==0;
}
endclass
program test;
constrainend p;
initial begin
p=new();
p.c_xy.constraint_mode(0); 将实例p中对x,y的约束关闭
assert(p.randomize() with {x==0; y==0;});//随机化x,y,并添加一个新约束
$display("x = %d",p.x);//不会再被原类中的约束限制,而是被randomzie_with约束限制
$display("y = %d",p.y);
end
endprogram
具体解释见下面代码注释
class constrainend;
rand bit x;
rand bit [1:0] y;
constraint c_xy
{
(x==0)-> y==0;
}
endclass
class overwrite extends constrainend;//子类继承父类,会继承属性和方法,所以父类的约束也继承了
constraint c_xy//子类如果想定义一个新约束覆盖父类,则需要定义一个同名约束
{
x==0;
y==0;
}
endclass
program test;
overwrite p;
initial begin
p=new();
assert(p.randomize());//在子类约束的基础上随机化
$display("x = %d",p.x);
$display("y = %d",p.y);
end
endprogram