Constraint inside
前面的约束,采用条件表达式>,倘若随机值是有限个值,并且没有明显的规律,总结表达式会较为困难。sv可以使用inside操作符,表示随机变量会从inside块中取值.
inside块里面可以是变量,常数和范围。inside之后用大括号,把取值放于括号内。其声明形式如下:
constraint addr_range {addr inside {...};}
对于范围表示要使用[],其声明形式如下:
constraint addr_range {addr inside {[5:10]};}
若是一系列的值,通过逗号分隔。
constraint addr_range {addr inside {1,3,5,7,9};}
对于上述的可以混合使用。
constraint addr_range {addr inside {1,3,[5:10],12.[13:15]};}
吐过想要排除一些值,可以使用!(感叹号),对整个约束取反。
constraint addr_range {addr !(inside{[5:10]});11}
一些随机变量也可以被使用在inside语句块中,如下所示:
rand bit [3:0] start_addr ;
rand bit [3:0] end_addr ;
rand bit [3:0] addr ;
constraint addr_range {addr inside {[start_addr : end_addr]};}
下面给出一个例子:
class packet;
rand bit [3:0] addr ;
rand bit [3:0] start_addr ;
rand bit [3:0] end_addr ;
constraint addr_1_range {addr inside {[start_addr : end_addr]};}
endclass
module constr_inside;
initial begin
packet pkt;
pkt = new();
$display("----------------------------------------------");
repeat(3) begin
pkt.randomize();
$display("start_addr = %0d, end_addr = %0d", pkt.start_addr, pkt.end_addr);
$display("\t addr = %0d", pkt.addr);
$display("----------------------------------------------");
end
end
endmodule
由下面输出结果看出,addr都是在开始地址和结束地址之间。输出结果如下:
dist constraint
我们还可能需要控制随机值的概率分布,sv提供dist操作符,可以实现带权重分布,dist需要紧跟一系列的值和权重。其声明形式如下:
value := weight or
value :/ weight
其中value表示把希望的值赋给一个随机变量,权重表示在随机化过程中这个数值所被考虑的频次。需要注意的是:
- 数值和权重可以是常数或者是变量
- 数值可以是一个值,或者一个范围
- 一个数值的默认权重是1
- 权重和即所有的weight的和加起来不一定是100,可以自由发挥,并不影响总的概率是1.
value:/weight表示对于值value赋予权重weight,但是如果value是一个范围是,范围内的值会平分权重weight,下面的李忠,10-12共三个取值,因此每个取值概率是8/3.
class packet;
rand bit [3:0] addr ;
constraint addr_range {addr dist {2 := 5, 7 := 8, 10 := 12};}
endclass
module constr_dist;
initial begin
packet pkt;
pkt = new();
$display("----------------------------------------");
repeat(10) begin
pkt.randomize();
$display("\t addr = %0d", pkt.addr);
$display("----------------------------------------");
end
end
endmodule
其输出结果是:
理应是10的输出个数最多的,输出最少的个数是2。
class packet;
rand bit [3:0] addr_1 ;
rand bit [3:0] addr_2 ;
constraint addr_1_range{addr_1 dist {2 := 5, [10:12] := 8};}
constraint addr_2_range{addr_2 dist {2 :/ 5, [10:12] :/ 8};}
endclass
module constr_dist;
initial begin
packet pkt;
pkt = new();
$display("-------------------------------------------");
repeat(10) begin
pkt.randomize();
$display("\t addr_1 = %0d", pkt.addr_1);
end
$display("-------------------------------------------");
$display("-------------------------------------------");
repeat(10)begin
pkt.randomize();
$display("\t addr_2 = %0d", pkt.addr_2);
end
$display("-------------------------------------------");
end
endmodule
这里需要理解的是,对于addr_1中,2的权重5,10,11,12对应的权重都是8.而在addr_2中,2的权重是5,而10,11,12的权重都是3/8。因此其输出结果是:
implication constraints
implication是隐含的意思,systemverilog提供隐含操作符(->)。可以用来声明两个变量之间的关系。一般被放置于表达式和约束条件之间。即:
expression -> contraint
只有当左面的表达式为真的时候,右边的约束才会被考虑。
class packet;
rand bit [3:0] addr ;
string addr_range ;
constraint address_range {(addr_range == "small") -> (addr < 8);}
endclass
module constr_implication;
initial begin
packet pkt;
pkt = new();
pkt.addr_range = "small";
$display("---------------------------------------------");
repeat(4) begin
pkt.randomize();
$display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
end
$display("---------------------------------------------");
end
endmodule
如上面例子,若addr_range等于small的话,那么才会有约束的随机化,如若不是small的话,则约束将不会生效。输出结果是:
if else 的约束
if else的语句块中也允许约束的条件执行,如果这个表达式是真,那么在一个约束块中所有的约束都会被满足,否则是在else的语句块中的约束会被满足。
class packet;
rand bit [3:0] addr ;
string addr_range ;
constraint address_range {
if(addr_range == "small")
addr < 8;
else
addr > 8;
}
endclass
module constr_if_else;
initial begin
packet pkt;
pkt = new();
pkt.addr_range = "small";
$display("----------------------------------------------------");
repeat(3) begin
pkt.randomize();
$display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
end
$display("----------------------------------------------------");
pkt.addr_range = "high";
$display("----------------------------------------------------");
repeat(3)begin
pkt.randomize();
$display("\t addr_range = %s addr = %0d", pkt.addr_range, pkt.addr);
end
$display("----------------------------------------------------");
end
endmodule
上面例子中,若addr_range是small,则随机化后的addr值都会小于8,如果是high的话,那么随机化后的addr值都会大于8.因此其输出结果如下所示:
foreach constraint
在systemverilog中的contraint块中也支持foreach循环。使用foreach对于数据的约束将是非常简单的。因此也叫做循环约束。在约束数组时,我们要指定或者约束动态数组的大小。其约束形式如下所示:
constraint constraint_name { foreach ( variable[iterator] ) variable[iterator] <..conditions..> }
下面的例子:
class packet;
rand byte addr [];
rand byte data [];
constraint avalues {
foreach(addr[i])
addr[i] inside {4, 8, 12, 16};
}
constraint dvalues {
foreach(data[j])
data[j] > 4 * j;
}
constraint asize {addr.size < 4;}
constraint dsize {data.size == addr.size;}
endclass
module constr_iteration;
initial begin
packet pkt;
pkt = new();
$display("--------------------------------------------");
repeat(3) begin
pkt.randomize();
$display("\t addr-size = %0d data-size = %0d", pkt.addr.size(), pkt.data.size());
foreach(pkt.addr[i])
$display("\t addr = %0d data = %0d", pkt.addr[i], pkt.data[i]);
$display("--------------------------------------------");
end
end
endmodule
显示addr 动态数组的元素必须时4,8,12,16,且大小必须小于4,而data数组的元素必须大于它的Index的4倍。约束两个动态数组的大小相等。其输出结果如下所示,当数组的大小为0时,则没有元素输出。
disable constraint
使用constraint_mode方法不使能一个类中的约束。默认情况下所有约束都会被使能。类似我们前文所提出的rand_mode方法。constraint_mode方法可以用来不使能任何特定的约束块。
- constraint_mode(1)表示约束被使能
- constraint_mode(0)表示约束被不使能
- 返回约束块的状态
其声明形式如下:
<object_hanlde>.<constraint_block_name>.constraint_mode(enable);
//enable == 1, constraint block enable
//enable == 0, constraint block disable
下面这个例子没有不使能约束条件,因此会随机选取5或者10中一个数进行打印输出,代码如下所示:
其输出结果是:
但是若在上面例子中加上不使能约束,则:
其输出结果是:
其实contraint_mode()可以返回约束块的状态:
class packet;
rand bit [3:0] addr;
constraint addr_range {addr inside {5, 10 , 14};}
endclass
module static_constr;
initial begin
packet pkt;
pkt = new();
$display("Before Constraint disable");
$display("Value of constraint mode = %0d", pkt.addr_range.constraint_mode());
pkt.randomize();
$display("\t addr = %0d", pkt.addr);
//disabling constraint
pkt.addr_range.constraint_mode(0);
$display("After Constraint disable");
$display("Value of constraint mode = %0d", pkt.addr_range.constraint_mode());
pkt.randomize();
$display("\t addr = %0d", pkt.addr);
end
endmodule
其输出结果是: