class packet; //定义随机变量 rand bit[31:0] src,dst,data[8]; randc bit[7:0] kind; //约束变量 constraint c//约束需要有实例名 { src > 10; src < 15; }//注意没有;号 endclass program test; packet p; initial begin p = new(); assert(p.randomize) else $fatal(0,"Packet :: randomize failed"); transmit(p); end endprogram
assert(p.randomize) $info(...);else $fatal(...);
注意assert后面如有有info可以加分号,如果没有消息需要打印则不需要加assert(condition) expression; else expression; assert(condition) else expression;
一般是在约束里所有表达式进行判断进行逻辑判断.
class order; rand bit [7:0] lo,med,hi; constraint bad { lo<med<hi; } endclass
((lo<med)<hi)
,首先计算lo<med,它们的值是0或1,然后根据约束,hi的值要大于0或1,所以变量lo和med虽然随机化了,但是没有受到约束;class order; rand bit [15:0] lo,med,hi; constraint good { lo < med; med <hi; } endclass
符号 | 含义 |
---|---|
:= | 表示值范围内的每一个值的权重都是相同的; |
: / | 表示权重要均分到值范围内的每一个值 |
rand int src,dst; constraint c_dist { src dist{0:=40,[1:3]:=60}; //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}; //dst = 0,weight = 40/100 //dst = 1,weight = 20/100 //dst = 2,weight = 20/100 //dst = 3,weight = 20/100 }
带变量的权重分配
typedef enum {READ8,READ16,READ32} read_e; class ReadCommands; rand read_e read_cmd; int read8_wt = 1,read16_wt = 1,read32_wt = 1; constraint c_read { read_cmd dist { READ8 := read8_wt; READ16 := read16_wt; READ32 := read32_wt; }; } endclass
用inside
运算符产生一个值的集合,除非对变量还有其他约束,否则sv在值的集合中取随机值时,各个值的选取机会是相等的,在集合中也可以使用变量
rand int c; int lo,hi; constraint c_range { c inside{[lo:hi]};//!(c inside{[lo:hi]};c<lo or c >hi }
可以使用$
代表取值范围的最小值和最大值
rand bit [6:0]b;//0<=b<=127 rand bit [5:0]e; constraint c_range { b inside {[$:4],[20:$]}; c inside {[$:4],[20:$]}; }
在集合中使用数据
rand int f; int fib[5] = '{1,2,3,5,8}; constraint c_fibonacci { f inside fib; }
通常约束块里面的所有约束都是有效的,但是有时我们只想让约束在某些时刻有效,例如在总线支持字节、半字、字的读操作,但是我们想只支持字的操作时。
if...else
class stim; bit flag; rand bit [31:0] dst; constraint c_stim { if(flag) { dst inside {[40:80]}; } else dst inside {[2:10],[50:67]}; } endclass
->
class stim; bit flag; rand bit [31:0] dst; constraint c_stim { flag -> dst inside {[40:80]}; !flag -> dst inside {[2:10],[50:67]}; } endclass
外部约束可以在需要的时候才添加约束,也可以不加约束;
class packet; rand bit [7:0] length; rand bit [7:0] payload[]; constraint c_valid { length > 0; payload.size() == length; } constraint c_external; endclass program test; constraint packet::c_external{length == 1;} endprogram
显示外部约束的格式:在使用之前如果没有前面的extern
会报错;
extern constraint c_ext
约束块不想自上而下执行程序性代码,它们是声明性的代码,是并行执行的,所有的约束表达式同时有效,古SV会同时计算所有的随机标量约束,取他们的交集
rand logic[15:0] r,s,t; constraint c_bitir { r < t; s == r; t <30; s >25; }
有一个练习:
parameter MAX_SIZE = 10; class packet; rand bit [31:0] src,dst,data[8]; randc bit [2:0] kind; constraint c { src > 10; src < 15; } endclass:packet //随机化句柄数组 class randarray; rand packet array[]; constraint c { array.size() inside{[1:MAX_SIZE]}; } function new(); array = new[MAX_SIZE]; foreach(array[i]) array[i] = new(); endfunction endclass:randarry module top_tb; packet p; initial begin p = new(); assert (p.randomize) else $fatal(0,"packet::randomize failied"); foreach(p.array[i])begin $display("src =%d",p.array[i].src); $display("dst =%d",p.array[i].dst); $display("data = ",p.array[i].data); $display("kind = %d",p.array[i].kind); end end endmodule
class unconstrained; rand bit x;//0、1 rand bit[1:0]y;//0、1、2、3 endclass module top_tb; unconstrained u; int cnt000,cnt001,cnt010,cnt011,cnt100,cnt101,cnt110,cnt111; initial begin u = new(); for(int i = 1;i<20000;i++)begin assert(u.randomize()); case({u.x,u.y}) 3'b000:cnt000 = cnt000+1'b1; 3'b001:cnt001 = cnt001+1'b1; 3'b010:cnt010 = cnt010+1'b1; 3'b011:cnt011 = cnt011+1'b1; 3'b100:cnt100 = cnt100+1'b1; 3'b101:cnt101 = cnt101+1'b1; 3'b110:cnt110 = cnt110+1'b1; 3'b111:cnt111 = cnt111+1'b1; endcase end $display("{u.x,u.y} is 000 time %0d",cnt000); $display("{u.x,u.y} is 001 time %0d",cnt001); $display("{u.x,u.y} is 010 time %0d",cnt010); $display("{u.x,u.y} is 011 time %0d",cnt011); $display("{u.x,u.y} is 100 time %0d",cnt100); $display("{u.x,u.y} is 101 time %0d",cnt101); $display("{u.x,u.y} is 110 time %0d",cnt110); $display("{u.x,u.y} is 111 time %0d",cnt111); end endmodule
解 | x | y | 概率 |
---|---|---|---|
A | 0 | 0 | 1/8 |
B | 0 | 1 | 1/8 |
C | 0 | 2 | 1/8 |
D | 0 | 3 | 1/8 |
E | 1 | 0 | 1/8 |
F | 1 | 1 | 1/8 |
G | 1 | 2 | 1/8 |
H | 1 | 3 | 1/8 |
class impact1; rand bit x;//0、1 rand bit[1:0]y;//0、1、2、3 constraint c_xy { (x == 0)->y == 0; } endclass module top_tb; impact1 u; int cnt000,cnt001,cnt010,cnt011,cnt100,cnt101,cnt110,cnt111; initial begin u = new(); for(int i = 1;i<20000;i++)begin assert(u.randomize()); case({u.x,u.y}) 3'b000:cnt000 = cnt000+1'b1; 3'b001:cnt001 = cnt001+1'b1; 3'b010:cnt010 = cnt010+1'b1; 3'b011:cnt011 = cnt011+1'b1; 3'b100:cnt100 = cnt100+1'b1; 3'b101:cnt101 = cnt101+1'b1; 3'b110:cnt110 = cnt110+1'b1; 3'b111:cnt111 = cnt111+1'b1; endcase end $display("{u.x,u.y} is 000 time %0d",cnt000); $display("{u.x,u.y} is 001 time %0d",cnt001); $display("{u.x,u.y} is 010 time %0d",cnt010); $display("{u.x,u.y} is 011 time %0d",cnt011); $display("{u.x,u.y} is 100 time %0d",cnt100); $display("{u.x,u.y} is 101 time %0d",cnt101); $display("{u.x,u.y} is 110 time %0d",cnt110); $display("{u.x,u.y} is 111 time %0d",cnt111); end endmodule
解 | x | y | 概率 |
---|---|---|---|
A | 0 | 0 | 1/5 |
B | 0 | 1 | 0 |
C | 0 | 2 | 0 |
D | 0 | 3 | 0 |
E | 1 | 0 | 1/5 |
F | 1 | 1 | 1/5 |
G | 1 | 2 | 1/5 |
H | 1 | 3 | 1/5 |
class impact2; randc bit x;//0、1 rand bit[1:0]y;//0、1、2、3 constraint c_xy { (x == 0)->y == 0; } endclass module top_tb; impact2 u; int cnt000,cnt001,cnt010,cnt011,cnt100,cnt101,cnt110,cnt111; initial begin u = new(); for(int i = 1;i<20000;i++)begin assert(u.randomize()); case({u.x,u.y}) 3'b000:cnt000 = cnt000+1'b1; 3'b001:cnt001 = cnt001+1'b1; 3'b010:cnt010 = cnt010+1'b1; 3'b011:cnt011 = cnt011+1'b1; 3'b100:cnt100 = cnt100+1'b1; 3'b101:cnt101 = cnt101+1'b1; 3'b110:cnt110 = cnt110+1'b1; 3'b111:cnt111 = cnt111+1'b1; endcase end $display("{u.x,u.y} is 000 time %0d",cnt000); $display("{u.x,u.y} is 001 time %0d",cnt001); $display("{u.x,u.y} is 010 time %0d",cnt010); $display("{u.x,u.y} is 011 time %0d",cnt011); $display("{u.x,u.y} is 100 time %0d",cnt100); $display("{u.x,u.y} is 101 time %0d",cnt101); $display("{u.x,u.y} is 110 time %0d",cnt110); $display("{u.x,u.y} is 111 time %0d",cnt111); end endmodule
解 | x | y | 概率 |
---|---|---|---|
A | 0 | 0 | 1/2 |
B | 0 | 1 | 0 |
C | 0 | 2 | 0 |
D | 0 | 3 | 0 |
E | 1 | 0 | 1/8 |
F | 1 | 1 | 1/8 |
G | 1 | 2 | 1/8 |
H | 1 | 3 | 1/8 |
class impact3; rand bit x;//0、1 randc bit[1:0]y;//0、1、2、3 constraint c_xy { (x == 0)->y == 0; } endclass module top_tb; impact3 u; int cnt000,cnt001,cnt010,cnt011,cnt100,cnt101,cnt110,cnt111; initial begin u = new(); for(int i = 1;i<20000;i++)begin assert(u.randomize()); case({u.x,u.y}) 3'b000:cnt000 = cnt000+1'b1; 3'b001:cnt001 = cnt001+1'b1; 3'b010:cnt010 = cnt010+1'b1; 3'b011:cnt011 = cnt011+1'b1; 3'b100:cnt100 = cnt100+1'b1; 3'b101:cnt101 = cnt101+1'b1; 3'b110:cnt110 = cnt110+1'b1; 3'b111:cnt111 = cnt111+1'b1; endcase end $display("{u.x,u.y} is 000 time %0d",cnt000); $display("{u.x,u.y} is 001 time %0d",cnt001); $display("{u.x,u.y} is 010 time %0d",cnt010); $display("{u.x,u.y} is 011 time %0d",cnt011); $display("{u.x,u.y} is 100 time %0d",cnt100); $display("{u.x,u.y} is 101 time %0d",cnt101); $display("{u.x,u.y} is 110 time %0d",cnt110); $display("{u.x,u.y} is 111 time %0d",cnt111); end endmodule
解 | x | y | 概率 |
---|---|---|---|
A | 0 | 0 | 1/8 |
B | 0 | 1 | 0 |
C | 0 | 2 | 0 |
D | 0 | 3 | 0 |
E | 1 | 0 | 1/8 |
F | 1 | 1 | 1/4 |
G | 1 | 2 | 1/4 |
H | 1 | 3 | 1/4 |
class impact1; randc bit x;//0、1 randc bit[1:0]y;//0、1、2、3 constraint c_xy { (x == 0)->y == 0; } endclass
解 | x | y | 概率 |
---|---|---|---|
A | 0 | 0 | 1/4 |
B | 0 | 1 | 0 |
C | 0 | 2 | 0 |
D | 0 | 3 | 0 |
E | 1 | 0 | 0 |
F | 1 | 1 | 1/4 |
G | 1 | 2 | 1/4 |
H | 1 | 3 | 1/4 |
class impact5; rand bit x;//0、1 rand bit[1:0]y;//0、1、2、3 constraint c_xy { y > 0; (x == 0)->y == 0; } endclass module top_tb; impact5 u; int cnt000,cnt001,cnt010,cnt011,cnt100,cnt101,cnt110,cnt111; initial begin u = new(); for(int i = 1;i<20000;i++)begin assert(u.randomize()); case({u.x,u.y}) 3'b000:cnt000 = cnt000+1'b1; 3'b001:cnt001 = cnt001+1'b1; 3'b010:cnt010 = cnt010+1'b1; 3'b011:cnt011 = cnt011+1'b1; 3'b100:cnt100 = cnt100+1'b1; 3'b101:cnt101 = cnt101+1'b1; 3'b110:cnt110 = cnt110+1'b1; 3'b111:cnt111 = cnt111+1'b1; endcase end $display("{u.x,u.y} is 000 time %0d",cnt000); $display("{u.x,u.y} is 001 time %0d",cnt001); $display("{u.x,u.y} is 010 time %0d",cnt010); $display("{u.x,u.y} is 011 time %0d",cnt011); $display("{u.x,u.y} is 100 time %0d",cnt100); $display("{u.x,u.y} is 101 time %0d",cnt101); $display("{u.x,u.y} is 110 time %0d",cnt110); $display("{u.x,u.y} is 111 time %0d",cnt111); end endmodule
解 | x | y | 概率 |
---|---|---|---|
A | 0 | 0 | 0 |
B | 0 | 1 | 0 |
C | 0 | 2 | 0 |
D | 0 | 3 | 0 |
E | 1 | 0 | 0 |
F | 1 | 1 | 1/3 |
G | 1 | 2 | 1/3 |
H | 1 | 3 | 1/3 |
class slovebefore; rand bit x;//0、1 rand bit[1:0]y;//0、1、2、3 constraint c_xy { (x == 0)->y == 0; solve x before y; } endclass module top_tb; slovebefore u; int cnt000,cnt001,cnt010,cnt011,cnt100,cnt101,cnt110,cnt111; initial begin u = new(); for(int i = 1;i<20000;i++)begin assert(u.randomize()); case({u.x,u.y}) 3'b000:cnt000 = cnt000+1'b1; 3'b001:cnt001 = cnt001+1'b1; 3'b010:cnt010 = cnt010+1'b1; 3'b011:cnt011 = cnt011+1'b1; 3'b100:cnt100 = cnt100+1'b1; 3'b101:cnt101 = cnt101+1'b1; 3'b110:cnt110 = cnt110+1'b1; 3'b111:cnt111 = cnt111+1'b1; endcase end $display("{u.x,u.y} is 000 time %0d",cnt000); $display("{u.x,u.y} is 001 time %0d",cnt001); $display("{u.x,u.y} is 010 time %0d",cnt010); $display("{u.x,u.y} is 011 time %0d",cnt011); $display("{u.x,u.y} is 100 time %0d",cnt100); $display("{u.x,u.y} is 101 time %0d",cnt101); $display("{u.x,u.y} is 110 time %0d",cnt110); $display("{u.x,u.y} is 111 time %0d",cnt111); end endmodule
解 | x | y | 概率 |
---|---|---|---|
A | 0 | 0 | 1/2 |
B | 0 | 1 | 0 |
C | 0 | 2 | 0 |
D | 0 | 3 | 0 |
E | 1 | 0 | 1/8 |
F | 1 | 1 | 1/8 |
G | 1 | 2 | 1/8 |
H | 1 | 3 | 1/8 |
class packet; rand int length; constraint c_short {length inside{[1:32]};} constraint c_long {length inside{[1000:1023]};} endclass module top_tb; packet p; initial begin p = new(); p.c_short.constraint_mode(0);//disabling short constraint assert(p.randomize()); $display("p::length = %d",p.length); p.constraint_mode(0); p.c_short.constraint_mode(1); assert(p.randomize()); $display("p::length = %d",p.length); end endmodule
class packet; rand bit [7:0] length,payload[]; constraint c_valid {length > 0;payload.size() ==length;} endclass module top_tb; packet p; initial begin p = new(); p.length.rand_mode(0); p.length = 42; assert(p.randomize()); $display("p::length = %d",p.length); p.length.rand_mode(1); assert(p.randomize()); $display("p::length = %d",p.length); end endmodule
class transaction; rand bit [31:0]addr,data; constraint c1{addr inside{[0:100],[1000:2000]};} endclass module top_tb; transaction t; initial begin t = new(); assert(tr.randomize() with {addr >= 50;addr <= 1500;data < 10;}); $display("t::addr is %d",t.addr); $display("t:data is %d",t.data); assert(t.randomize() with{addr == 2000;data >10;});//force addr to a specific value,data >10 $display("t::addr is %d",t.addr); $display("t:data is %d",t.data); end endmodule
class rising; byte low; rand byte med,hi; constraint c_up{low<med;med<hi;} endclass module top_tb; rising r; initial begin r = new(); r.randomize(); $display("r::low is %d,r:med is %d,r::hi is %d",r.low,r.med,r.hi); r.randomize(med); $display("r::low is %d,r:med is %d,r::hi is %d",r.low,r.med,r.hi); r.randomize(low); $display("r::low is %d,r:med is %d,r::hi is %d",r.low,r.med,r.hi); end endmodule
它们的特点:
pre_randomize->randomize->post_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 top_tb; wr_tran tr; initial begin tr = new(); tr.constraint_en = 0; tr.randomize() with { wr_addr == 200; wr_data == 3; valid == 0; }; $display("wr_addr = %d, wr_data = %d, valid = %d, broadcast = %d", tr.wr_addr,tr.wr_data,tr.valid,tr.broadcast); end endmodule
sig1:12345678 sig 1 &000FF 000
class test; rand bit[7:0]sig1; rand int unsigned sig1; constrain c { sig2>1000; sig1>sig2;//sig1的最大值256,无法达到1000,需要注意位宽、符号
rand bit[7:0]sig1; rand bit[7:0]sig2; constraint c1{sig1>5;} constraint c2{sig2>10;} constraint c2{sig1+sig2 ==13;}//这里也是不对的,多随机变量的出现形式可能会出现相互矛盾的;
所以我们在使用随机化时需要注意