随机约束、随机分布、随机数组等-systemverilog
2021/11/18 23:42:54
本文主要是介绍随机约束、随机分布、随机数组等-systemverilog,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一、简介
why
- 芯片体积增大,复杂度逐渐提高,定向测试已经无法满足验证的需求,随机化验证的比例逐渐提高;
- 定向测试能够找到你认为可能存在的缺陷,而随机测试可以找到你都没法想到的缺陷;
- 随机测试的环境要求比定向测试复杂,它需要激励、参考模型和在线比较。
- 随机测试相对定向测试可以减少相当多的代码量,而产生的激励较定向测试也更多项;
- CRT(constraint random test)能够提高效率,提供测试激励和测试场景;
what
- 器件配置:通过寄存器和系统信号
- 环境配置:随机化验证环境,例化合理的时钟和外部反馈信号;
- 原始输入数据:例如数据包的长度、宽度,数据的顺序
- 延时:握手信号之间的时序关系,例如valid和ready,req和ack之间的时序关系
- 协议异常:如果反馈信号给出异常,那么设计能否保持数据处理的稳定性
二、随机化种类
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
- rand是可以重复的随机定义,randc可以类比是在一副牌里抽一张出来,但是抽出来之后就不放回去了,等待所有牌都被抽完才会重新抽,并且在随机约束解析时,会先解析randc的变量,不同的解析顺序可能导致不一样的随机分布结果;
- randc循环性质随机,但是他的资源占用比多大,因为它需要保存前面的随机值;
- randomize把类里面的所有属性进行随机;
- 一般随机化使用方法:
- 定义类,在类中声明关心的属性为rand/randc;
- new对象
- handle调用随机函数randomize;
- 需要注意断言中的使用:
assert(p.randomize) $info(...);else $fatal(...);
注意assert后面如有有info可以加分号,如果没有消息需要打印则不需要加
assert(condition) expression; else expression; assert(condition) else expression;
2.1布尔表达式
一般是在约束里所有表达式进行判断进行逻辑判断.
class order; rand bit [7:0] lo,med,hi; constraint bad { lo<med<hi; } endclass
- 约束bad按照从左自右顺序分割两个表达式:
((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
2.2 权重分配(weighted distributions)
符号 | 含义 |
---|---|
:= | 表示值范围内的每一个值的权重都是相同的; |
: / | 表示权重要均分到值范围内的每一个值 |
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
- 权重read8/16/32_wt后续可以更改,这里的8/16/32是总线访问分别对应字节访问、半字访问还有字访问,所以在数据访问是不一样的;
- 字节访问第0位是保留下来,半字访问是第0位是不关心的,字访问是第0位和第一位不关心的;
2.3 范围表达式随机(range expressions)
用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; }
2.4 条件表达式
通常约束块里面的所有约束都是有效的,但是有时我们只想让约束在某些时刻有效,例如在总线支持字节、半字、字的读操作,但是我们想只支持字的操作时。
- 使用
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
2.5 外部约束
外部约束可以在需要的时候才添加约束,也可以不加约束;
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
2.6 双向约束
约束块不想自上而下执行程序性代码,它们是声明性的代码,是并行执行的,所有的约束表达式同时有效,古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
三、随机约束分布概率
3.1 没有约束的类
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 |
- 没有约束的类是可以根据x和y分别对应不同的解来计算概率的,例如x出现的概率是1/2,y出现0的概率是1/4,所以概率位1/8
3.2 关系操作
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 |
- 这里增加了关系约束,x等于0的时候,y等于0;
- y的值依赖于x的值,所以只有五种可能,所以都为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 |
- randc是先解析的,所以先解析x的值(0、1)。如果x等于0,则y肯定是0,针对x值0是1/2的概率;
- 其他情况x等于1时为1/2,然后y出现0、1、2、3的概率为1/4,所以E-H是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 |
- 这里与上面不同之处在于先解析y,然后y(0、1、2、3)分别为1/4,x的取值有两种可能,但是由于约束的原因,在y等于1、2、3时,x不可能为0, 所以y=0,x=0、1分别为1/8;
- 所以x等于1,y等于1、2、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 |
- 首先randc是轮询的
- x = 0,y只能是0;
- x = 1,y只能在1、2、3里面
- 但是这里两个randc,可能不同仿真工具可能不一样的仿真结果,我们应该避免这种让仿真工具有问题;
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 |
3.3 solve…before
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 |
- 与randc的先解析相似,概率分布也和randc的概率分布一样;
- 但是不要滥用solve…before,会降低计算速度;
四、随机约束控制
4.1 控制多个约束块constraint_mode()
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
- 可以单独关闭类中的某个约束块,可以单独开启每个约束块,使用0/1即可;
- 可以一口气把类中的所有的约束块都给关了;
4.2 控制随机变量rand_mode()
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
- 可以通过rand_mode对某个随机变量的随机功能进行开关控制;
4.3 控制随机变量randomize() with{}
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
- 这里的randomize() with{}可以强制约束甚至可以变成一个特定的值;
4.4 randomize单独控制变量
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
- 这里可以让不是rand类型的变量也可以进行随机化,实现对单变量的控制;
- 但是这里不推荐一个一个变量进行随机化;
4.5 pre_randomize与post_randomize
它们的特点:
- 都是function,不会消耗事件;
pre_randomize->randomize->post_randomize
- pre_randomize()和post_randmize()函数可以被用户重写,用户使用pre_randomize()函数,在随机前修改代码中非随机变量的值,如上下限、权重等;
- post_randmize()函数可以在随机后修改随机值或做一些其它的计算。
- randomize失败的化post不会执行,
- pre和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
五、随机化常见错误
- 在随机变量中使用了有符号变量导致随机化错误;
- 变量可能会溢出导致高位去除而随机化出错;
避免随机化错误的技巧: - 避免使用乘除和取模的操作,如果要使用就通过左移和右移代替乘除;
- 使用AND mask代替取模;
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;}//这里也是不对的,多随机变量的出现形式可能会出现相互矛盾的;
所以我们在使用随机化时需要注意
- 数据类型
- 数据位宽(精确些)
- 多个约束块中的变量之间的关系
- 约束块中表达式的结果
- 约束块中各约束冲突
这篇关于随机约束、随机分布、随机数组等-systemverilog的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-03-29Gitlab 实现仓库完全迁移,包括所有提交记录、分支、标签
- 2024-03-28numpy moving average
- 2024-03-28lsp框架
- 2024-03-28in文件
- 2024-03-28ninoka nk 700
- 2024-03-28volatile java
- 2024-03-28netflix hystrix
- 2024-03-28landsat ndvi
- 2024-03-28变分法
- 2024-03-28FMZ股票实盘、模拟盘程序化交易实战--股票版DualThrust策略