在systemverilog中,静态的约束和静态的类的性质类似。一个约束块可以被定义为静态的,通过在它的定义中添加static关键字,此时这个约束块叫做静态约束,所有类的实例共享这个静态约束块。因此该类的任一句柄改变constraint_mode将会影响其他实例。约束形式为:
static constraint constraint_name { ....; }
以下是一个例子:
class packet;
rand bit [7:0] addr ;
static constraint addr_range {addr == 5;}
endclass
module static_constr;
initial begin
packet pkt1;
packet pkt2;
pkt1 = new();
pkt2 = new();
$display("Before disabling constraint");
pkt1.randomize();
$display("\t pkt1.addr = %0d", pkt1.addr);
pkt2.randomize();
$display("\t pkt2.addr = %0d", pkt2.addr);
pkt2.addr_range.constraint_mode(0);
$display("After disabling constraint");
pkt1.randomize();
$display("\t pkt1.addr = %0d", pkt1.addr);
pkt2.randomize();
$display("\t pkt2.addr = %0d", pkt2.addr);
end
endmodule
结果如下,可见尽管是pkt2调用了constraint_mode方法,句柄pkt1指向的实例也受影响。

约束是写在类的里面的,内联约束允许使用者对类内的约束增加额外的约束,内联约束写在类的外面,同时还有randomize方。
使用关键字with,约束求解器constraint solver会同时考虑内联约束和类内约束。内联约束不会覆盖override类内约束,并且不能和类内约束冲突,否则将导致随机化失败。其使用方法如下:
object.randomize()with{...};
class packet;
rand bit [3:0] addr;
endclass
module inline_constr;
initial begin
packet pkt;
pkt = new();
repeat(2) begin
pkt.randomize()with{addr == 8;};
$display("\taddr = %0d", pkt.addr);
end
end
endmodule
如上面这个例子,在类内并没有约束,在类外添加约束,addr = 8,结果输出如下所示:

class packet;
rand bit [3:0] addr;
rand bit [3:0] data;
constraint data_range{data > 0; data < 10;}
endclass
module inline_constr;
initial begin
packet pkt;
pkt = new();
repeat(2)begin
pkt.randomize()with {addr == 8;};
$display("\t addr = %0d data = %0d", pkt.addr, pkt.data);
end
end
endmodule
上面这个在类内和类外都有约束,其输出结果为:

如果再加个约束data = 12,那么编译器就会报错:

报错的信息如下:

在一些情况下,不能在一个整行写完约束。因此我们可以使用function来约束随机变量,约束逻辑要写在function的内部。
使用方法为:
constraint constraint_name { var = function_call(); };
class packet;
rand bit [3:0] start_addr;
rand bit [3:0] end_addr;
constraint start_addr_c {
start_addr == s_addr(end_addr);
}
function bit [3:0] s_addr(bit [3:0] e_addr);
if(e_addr < 4)
s_addr = 0;
else
s_addr = e_addr - 4;
endfunction
endclass
module func_constr;
initial begin
packet pkt;
pkt = new();
repeat(3) begin
pkt.randomize();
$display("\t start_addr = %0d end_addr = %0d", pkt.start_addr, pkt.end_addr);
end
end
endmodule
其输出结果为:

在systemVerilog中,一个约束被关键字soft约束时,就叫做软约束。通过前文我们可以知道当类的约束和内联约束之间有冲突,那么导致随机化约束失败。但是在一些场景下,我们可能需要覆盖约束,soft就派上用场,soft可以被覆盖。
考虑如下场景,在testbench中,transaction类的约束用于产生正常的激励,对于错误激励,出错的testcase需要有一个内联约束,该约束有可能会和类内约束冲突。此时,我们只能改变类内的约束,但改动类内约束,会影响到其他testcase。如果可以覆盖类内约束,就迎刃而解了(注,错误激励,会不按正常激励的逻辑产生值,少不了约束冲突)
class packet;
rand bit [3:0] addr;
constraint addr_range {soft addr > 6;}
endclass
module soft_constr;
initial begin
packet pkt;
pkt = new();
repeat(2)begin
pkt.randomize()with {addr < 6;};
$display("\t addr = %0d", pkt.addr);
end
end
endmodule
如上面例子所示,在类中使用软约束addr > 6 ,但是在类外语句中约束其<6.由运行结果所示,约束求解器工作正常,并使用覆盖后的约束条件。输出结果如下所示:
约束还可以用unique 修饰,通过unique我们可以给多个变量或者数组元素随机化独一无二的值
class unique_elements;
rand bit [3:0] var_1, var_2, var_3;
rand bit [7:0] array[6];
constraint varis_c{unique {var_1, var_2, var_3};}
constraint array_c{unique {array};}
function void display();
$display("var_1 = %p", var_1);
$display("var_2 = %p", var_2);
$display("var_3 = %p", var_3);
$display("array = %p", array);
endfunction
endclass
program unique_elements_randomization;
unique_elements pkt;
initial begin
pkt = new();
pkt.randomize();
pkt.display();
end
endprogram
其输出结果如下所示,我们可以看出unique保证了其约束的值不会出现重复。
# var_1 = 10
# var_2 = 1
# var_3 = 2
# array = '{17, 129, 93, 14, 70, 236}
systemverilog中的约束是双向求解的,这意味着对所有的随机变量的约束时并行求解的。在下面的例子中,直观上理解是b依赖于a。但是求解器会认为a依赖于b,b也依赖于a。假设b的内联约束为1,那么为了满足该条件,a就必须为0.
constraint c_name { if(a == 0) b == 1;
else b == 0; }
正是如此,sv的约束被成为双向约束。下面的示例,面对三个约束,求解器要同时满足
class packet;
rand bit [3:0] a;
rand bit [3:0] b;
rand bit [3:0] c;
constraint a_value { a == b + c; }
constraint b_value { b > 6; }
constraint c_value { c < 8; }
endclass
module bidirectional_constr;
initial begin
packet pkt;
pkt = new();
repeat(5) begin
pkt.randomize();
$display("Value of a = %0d \tb = %0d \tc =%0d",pkt.a,pkt.b,pkt.c);
end
end
endmodule
其输出结果为:
# Value of a = 3 b = 15 c =4
# Value of a = 2 b = 13 c =5
# Value of a = 15 b = 15 c =0
# Value of a = 13 b = 11 c =2
# Value of a = 0 b = 11 c =5
运行结果,要注意a,b,c都是4bit,进位会丢弃,15+4=19=5’h13,截取第四位为3

如上面这个例子中,在module内部通过内联约束b1,为了满足这个条件,就要把a0,而a == 0 就和a =1相互矛盾。编译器会报错:

由于求解的双向性,会让一些独立的随机变量影响其他随机变量。要解决此困境,我们可以指定求解顺序
下例中,通过->,如果a=1,b==0约束生效,a=0时,对b应该没有约束,但b不能为0,为0会使得a要为1。a和b本应该互不影响,但约束的双向性导致a和b互相依赖
由下面结果可以看出,a = 1出现的概率是很低的。这主要是因为b的取值只有0,a 才可能为1.
# Value of a = 0, b = 12
# Value of a = 0, b = 5
# Value of a = 0, b = 2
# Value of a = 0, b = 1
# Value of a = 0, b = 5
# Value of a = 1, b = 0
# Value of a = 0, b = 9
# Value of a = 0, b = 10
# Value of a = 1, b = 0
# Value of a = 0, b = 3
为了让a=1出现的概率增大,我们应该先求解a,这是因为先求解a并没有约束,这样从概率的角度上来说,a == 1的概率可以提升到50%。我们只用添加下图中红框中的语句就可以了。

运行结果:
# Value of a = 1, b = 0
# Value of a = 0, b = 9
# Value of a = 0, b = 14
# Value of a = 1, b = 0
# Value of a = 0, b = 2
# Value of a = 0, b = 14
# Value of a = 0, b = 9
# Value of a = 1, b = 0
# Value of a = 0, b = 7
# Value of a = 0, b = 10
$urandom系统函数返回的是一个新的32位的无符号的随机数,varible = $urandom(seed) ,seed是一个可选的参数,决定了产生随机数的顺序,种子可以是一个整数表达式。对一个特定的种子,将会产生相同的值。
$ random函数的功能和$urandom函数类似,只不过它返回的是一个32位的有符号数。
$urandom_range函数用作返回在一个范围内的无符号的32位的整数。声明形式如下:
$urandom_range( int unsigned maxval, int unsigned minval = 0 );addr1 = $urandom_range(30,20);
addr2 = $urandom_range(20); //takes max value as '0'
addr3 = $urandom_range(20,30); //considers max value as '30' and min value as '20'
其函数原型位:
function int unsigned $urandom_range(int unsigned maxval, int unsigned minval = 0)
如果第一个参数比第二个参数小,两个参数的值会被自动调换。
下面是一个例子:
module system_funcations;
bit [31:0] addr1;
bit [31:0] addr2;
bit [64:0] addr3;
bit [31:0] data;
initial begin
addr1 = $urandom();
addr2 = $urandom(89);
addr3 = {$urandom(),$urandom()};
data = $urandom * 6;
$display("addr1=%0d, addr2=%0d, addr3=%0d, data=%0d",addr1,addr2,addr3,data);
addr1 = $urandom_range(30,20);
addr2 = $urandom_range(20); //takes max value as '0'
addr3 = $urandom_range(20,30); //considers max value as '30' and min value as '20'
$display("addr1=%0d, addr2=%0d, addr3=%0d",addr1,addr2,addr3);
end
endmodule
结果:
# addr1=3948585912, addr2=1979238544, addr3=16107885100594265732, data=4138940696
# addr1=20, addr2=2, addr3=30