器件配置:通过寄存器和系统信号;
在随机测试中,可以随机化下列哪些要素? 答案:AC
A、设计的功能配置;B、设计的结构;C、输入数据;D、输出数据
设计的结构是静态的,在编译时确定;验证的结构是动态的,发生在仿真阶段。
随机化是为了产生更多可能的驱动,将相关数据有机整理在一个类中,使用rand关键词表明变量的随机属性。
class Packet;
//The random variables
rand bit [31:0] src, dst, data[8];
randc bit [7:0] kind;
// Limit the value for src
constraint c {
src > 10;
src < 15;
}
endclass
Packet P;
initial begin
P = new(); //Create a packet
assert (Packet.randomize())
else $fatal(0,"Packet::randomize failed");
transmit(P);
end //需要随机的变量有4个,只要其中一个约束有问题,那么所有变量都没有进行随机
约束表达式的求解由SV的约束求解器完成。
class data;
rand bit [2:0] month;
rand bit [4:0] day;
rand int year;
constraint c_data {
month inside {[1:12]};
day inside {[1:31]};
year inside {[2010:2030]};
}
endclass //注意位数的限制,比如month只有三位只能随机0-7
class Stim;
const bit [31:0] CONGEST_ADDR = 42; //定义常量
typedef enum {READ,WRITE,CONTROL} stim_e; //自定义枚举类型,stim_e类型名
randc stim_e kind; //Enumerated var
rand bit [31:0] len,src,dst; //随机变量
bit congestion_test; //非随机变量
constraint c_stim{
len < 1000;
len > 0;
if (congestion_test){
dst inside {[CONGEST_ADDR + 100 : CONGEST_ADDR - 100]};
src == CONGEST_ADDR;
}
else
src inside {0,[2:10],[100:107]};
}
endclass
用:=或:/分开。值或权重可以是常数或变量;
权重不用百分比表示,权重的和也不必是100;
rand int scr,dst;
constraint c_dist{
src dist {0:=40,[1:3]:=60};// :=的意思是产生40个0,1-3每个数产生60个,共产生220个数
//src = 0,weight(权重) = 40/220
//src = 1,weight(权重) = 60/220
//src = 2,weight(权重) = 60/220
//src = 3,weight(权重) = 60/220
dst dist (0:/40,[1:3]:/60);// :/的意思是0的概率是40%,1-3的概率一共是60%
//dst = 0,weight(权重) = 40/100
//dst = 1,weight(权重) = 20/100
//dst = 2,weight(权重) = 20/100
//dst = 3,weight(权重) = 20/100
}
打开或关闭约束
一个类可包含多个约束块,可以把不同约束块用于不同测试;
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(); //创建一个long packet通过禁止短约束块
p.c_short.constraint_mode(0);//关闭short packet,只有long_packet约束有效
assert (p.randomize());
transmit(p);
//创建一个short packet通过禁止所有约束然后只使能短约束块
p.constraint_mode(0);//long和short的约束都失效
p.c_short.constraint_mode(1);//打开short的约束
transmit(p);
end
//如果随机化该对象时不禁止其中任何一个约束块,那么调用随机函数randomize()后,
//p.length的值为0也会报错,因为约束冲突导致randomize失败有warning返回默认值0。
内嵌约束
约束块之间会相互作用,最终产生难以预测的结果,使能和禁止这些约束的代码也会增加测试的复杂性;
class Transaction;
rand bit [31:0] addr,data;
constraint c1 {soft addr inside {[0:100],[1000:2000]};}
endclass
Transaction t;
initial begin
t= new();
assert(t.randomize() with {addr >= 50; addr <= 1500; data < 10;});
driveBus(t);
//force addr to a specific value,data>10
assert(t.randomize() with {addr == 2000; data > 10;});
driverBus(t);
end
如果加上t.randomize() with {addr inside [200:300]; data inside [10:20]; },若没有关键词soft,addr的约束和内嵌矛盾,addr约束不满足,addr和data都会报错。但因为有soft,减低了约束的优先级,使得内嵌约束起作用。
两个预定义的void类型函数pre_randomize()和post_randomize()函数,可看作randomize()函数的回调函数。用户可在类中定义这两个函数,分别在其中定义随机化前的行为和随机化后的行为。
随机数函数:SV提供一些常用的系统随机函数。这些随机函数可直接调用来返回随机数值(不通过class,直接调用)。
class Rising;
byte low, //非随机变量,初始值为0
rand byte med,hi; //随机变量,初始值为0
constraint up {low < med; med < hi;}
endclass
initial begin
Rising r;
r = new();
r.randomize();//随机化med,hi,但不改变low,此时low=0,假设med=5,hi=9
//先整体的randomize产生合理的low,med和hi值
r.randomize(med); //只随机化med;此时low=0,hi=9,med可以是1-8,假设med=6
r.randomize(low);//只随机化low;此时med=6,hi=9,low可以是0-5,假设low=3
end
按照上面的代码仿真结果log如下图所示:
在例化r之后如果先调用r.randomize(low),那么可能产生low=报错,med=0,hi=0;实际例子如下图;
因为med和hi不参与randomize,保持为0