目录

  • 随机约束和分布
    • 为何需要随机?
    • 为何需要约束?
    • 需要随机什么?
    • 声明随机变量的类
  • 什么是约束?
    • 权重分布
  • 约束块控制
    • 打开或关闭约束
    • 内嵌约束
    • 随机函数
  • 数组约束
    • 数组的属性约束
  • 随机化句柄数组
    • 随机控制

随机约束和分布

为何需要随机?

芯片体积增大,复杂度越来越高,定向测试已无法满足验证的需求,而随机测试的比例逐渐提高

  • 定向测试能找到认为可能存在的缺陷,随机测试可以找到意想不到的缺陷;
  • 随机测试的环境要求比定向测试复杂,需要激励、参考模型、在线比较
  • 随机测试相对定向测试可以减少很多代码量,产生的激励较定向测试也更多样。(减少测试用例的代码量,更多的复用,但验证环境的结果增多了)

为何需要约束?

如果没有约束,产生有效激励的同时也产生很多无效和非法的激励;

  • 随机自由是一种合法的随机,需要限定激励的合法范围;
  • 随机的对象不只是一个数据,而是有联系的变量集。通常这些变量被封装在一个数据类中,同时需要在类中声明数据之间的约束关系。因此约束之后要产生随机数据需一个“求解器”,即在满足数据本身和数据之间约束关系时的随机数值解
  • 约束不但可以指定数据的取值范围,还可以指定各个数值的随机权重分布

需要随机什么?

器件配置:通过寄存器和系统信号

  • 环境配置随机化验证环境,例如合理的时钟和外部反馈信号;
  • 原始输入数据:例如MCDF数据包的长度、带宽,数据间的顺序;
  • 延时握手信号之间的时序关系,如valid和ready,req和ack之间的时序关系;
  • 协议异常:如果反馈信号给出异常,设计是否可以保持后续数据处理的稳定性

在随机测试中,可以随机化下列哪些要素? 答案:AC
A、设计的功能配置;B、设计的结构;C、输入数据;D、输出数据

设计的结构是静态的,在编译时确定;验证的结构是动态的,发生在仿真阶段。

声明随机变量的类

随机化是为了产生更多可能的驱动,将相关数据有机整理在一个中,使用rand关键词表明变量的随机属性。

  • randc表示周期随机性,即所有可能的值都赋过值后随机值才可以重复
  • 随机属性需要配合SV预定义的类随机函数std::randomize()使用;
  • 约束constraint也同随机变量一起在中声明。
class Packet;//The random variablesrand bit [31:0] src, dst, data[8];randc bit [7:0] kind;// Limit the value for srcconstraint c {src > 10;src < 15;}
endclass
Packet P;
initial beginP = new(); //Create a packetassert (Packet.randomize())else $fatal(0,"Packet::randomize failed");transmit(P);
end  //需要随机的变量有4个,只要其中一个约束有问题,那么所有变量都没有进行随机

什么是约束?

约束表达式的求解由SV的约束求解器完成。

  • 求解器能够选择满足约束的值,这个值是由SV的PRNG(伪随机数发生器)从一个初始值seed产生。只要改变种子的值,就可以改变CRT的行为。
  • SV标准定义了表达式的含义及产生的合法值,但没有规定求解器计算约束的准确顺序,即不同仿真器对同一个约束类和种子值求解的数值可能不相同
  • SV只能随机化二值数据类型,无法随机化出X值和Z值,也无法随机化字符串。
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 varrand 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;}elsesrc inside {0,[2:10],[100:107]};}
endclass

权重分布

关键词dist可以在约束中用来产生随机数值的权重分布

  • dist操作符带有一个值的列表以及相应的权重,中间用:=:/分开。值或权重可以是常数或变量
  • 权重不用百分比表示,权重的和也不必是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/220dst 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
}
  • inside是常见的约束运算符,表示变量应属于某些值的集合,除非还存在其他约束,否则随机变量在集合里面取值的概率是相等的,集合里面也可使用变量。例如c inside {[low:high]}; //low<=c && c<=high
  • 使用$指定最大值和最小值,例如c inside {[$:4],[20:$]}; //0<=c<=4 || 20<=c<=63(因为rand bit [5:0] c ; // 0<=c<=63)

条件约束:可以通过 “->”或if-else让一个约束表达式在特定时刻有效。

  • 约束块不是自上向下的程序性代码,而是声明性的代码,是并行的,所有的约束表达式同时有效
  • 约束也是双向的,这表示会同时计算所有随机变量的约束,增加或删除任一变量的约束都会直接或间接影响所有相关值的选取。

约束块控制

打开或关闭约束

一个类可包含多个约束块,可以把不同约束块用于不同测试;

  • 各个约束块之间的约束内容是互相协调不违背的;
  • 使用内建的constraint_mode()函数可以根据不同需要打开或关闭约束;
  • p.constraint_mode(0)是关闭约束,p.constraint_mode(1)是打开约束。
class Packet;rand int length;constraint c_short {length inside {[1:32]};}constraint c_long {length inside {[1000:1023]};}
endclass
Packet p;
initial beginp = 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。

内嵌约束

约束块之间会相互作用,最终产生难以预测的结果,使能和禁止这些约束的代码也会增加测试的复杂性;

  • 约束需要考虑类的开放封闭原则
  • SV允许使用randomize() with增加额外的约束,和在类里增加约束是等效的,但同时要注意内部约束和外部约束之间应协调,如果出现互相违背的情况,那么随机数值求解会失败;
  • 关键字soft是修饰软约束,当与其它外部约束冲突时软约束优先级会更低
class Transaction;rand bit [31:0] addr,data;constraint c1 {soft addr inside {[0:100],[1000:2000]};}
endclass
Transaction t;
initial begint= new();assert(t.randomize() with {addr >= 50; addr <= 1500; data < 10;});driveBus(t);//force addr to a specific value,data>10assert(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,减低了约束的优先级,使得内嵌约束起作用。

随机函数

pre_randomize()和post_randomize()函数

  • 两个预定义的void类型函数pre_randomize()和post_randomize()函数,可看作randomize()函数的回调函数。用户可在类中定义这两个函数,分别在其中定义随机化前的行为和随机化后的行为

随机数函数:SV提供一些常用的系统随机函数。这些随机函数可直接调用来返回随机数值(不通过class,直接调用)。

  • $random()平均分布,返回32位符号随机数;
  • $urandom()平均分布,返回32位符号随机数;
  • $urandom_range(A,B)在指定范围内的平均分布。

随机化个别变量

  • 在调用randomize()时可以在括号里定义个别变量;
  • 只有在括号里的变量才会被随机化,其他变量被当做状态变量而不会被随机化;
  • 所有约束仍然保持有效
  • 类里所有被指定或没有指定rand的变量都可作为randomize()的参数而被随机化;
  • randomize的参数若不是之前定义的rand变量,则类的rand变量不会被随机化。
class Rising;byte low, //非随机变量,初始值为0rand byte med,hi; //随机变量,初始值为0constraint up {low < med; med < hi;}
endclass
initial beginRising 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=6r.randomize(low);//只随机化low;此时med=6,hi=9,low可以是0-5,假设low=3
end
//在例化r之后如果先调用r.randomize(low),那么可能产生low=报错,med=0,hi=0;
//因为med和hi不参与randomize,保持为0

数组约束

在约束随机标量的同时,也可以对随机化数组进行约束。

class dyn_size;rand logic[31:0] d[];constraint d_size {d.size() inside {[1:10]}; }
endclass

数组的属性约束

数组的大小应该给定范围,防止生成过大体积的数组或空数组;

  • 可在约束中结合数组的各种方法sum()product()and()or()xor()
  • SV可利用foreach对数组的每个元素进行约束,和直接写对固定大小数组的每个元素的约束相比更简洁;
  • 针对动态数组,foreach更适合于对非固定大小数组中每个元素的约束。

如果要产生一个随机数组,其每个元素的值唯一,可使用双循环嵌套
如果直接使用randc数组,那么数组中的每个元素只会独立地随机化,并不会按照本意使得数组中的元素值唯一。

class UniqueSlow;rand bit[7:0] ua[64];constraint c{foreach(ua[i])  //对数组中的每个元素操作foreach(ua[j])if(i != j) //除了元素自己ua[i] != ua[j];  //和其他元素比较}
endclass

可使用randc变量辅助生成唯一元素的数组。

class randc8;randc bit[7:0] val;
endclass
class LittleUniqueArray;bit[7:0] ua[64];function void pre_randomize();randc8 rc8;rc8 = new();  //此句若放在foreach里,则不断创建新对象,跟用rand声明val无区别foreach(ua[i]) beginassert(rc8.randomize());  //若调用LittleUniqueArray.randomize(),//则只执行该类的pre_randomize(),故ua数组得不到rc8随机化的数值ua[i] = rc8.val;endendfunction
endclass
class packet;rand bit [3:0] da[];  //该动态数组不需要例化,因为添加了rand//后面randomize后会帮助创建、例化、填充这些元素constraint da {da.size() inside {[3:5]};foreach(da[i]) da[i] <= da[i + 1];}
endclass
packet p;
initial beginp = new();p.randomize() with {da.size() inside {3,5};};
end
//一开始约束size为3-5,后来进行了独立约束size为3或5。
//但foreach(da[i]) da[i] <= da[i + 1];时没有限制i的取值,i=5时,i的范围时[0:4]。
//da[4]<=da[5](对应第六个元素)超出了范围,所以约束有冲突,随机化失败会报错
//解决办法:在foreach(da[i])后加上if(i<=da.size()-2)

随机化句柄数组

  • 随机化句柄数组的功能是在调用其所在类的随机函数时,随机函数会随机化数组的每个句柄所指定的对象。因此随机句柄数组的声明要添加rand表示其随机化的属性,同时在调用随机函数前要保证句柄数组中的每个句柄元素都非悬空,需要在随机化前为每个元素句柄构建对象
  • 如果要产生多个随机对象,则可能需要建立随机句柄数组。需要在随机化前分配所有元素,因为随机求解器不会创建对象。使用动态数组可按需分配最大数量的元素,然后再使用约束减小数组的大小。随机化时,动态句柄数组的大小可保持不变或减小,但不能增加
parameter MAX_SIZE = 10;
class RandStuff;bit [1:0] value = 1;
endclass
class RandArray;rand RandStuff array[];constraint c{array.size() inside {[1:MAX_SIZE]};}function new();//分配最大容量array = new [MAX_SIZE];foreach (array[i])array[i] = new(); //每次创建均为RandStuff创建后的值,即为value=1endfunction
endclass
RandArray ra;
initial begin//构造数组和所有对象ra = new();//约束数组的数量为两个assert(ra.randomize()with {array.size == 2});foreach (ra.array[i])$display(ra.array[i].value);
end

随机控制

随机序列:产生事务序列的另一个方法是使用SV的randsequence结构,这对于随机安排组织原子测试序列很有帮助。

initial beginfor(int i = 0; i < 15; i++) beginrandsequence(stream)stream: cfg_read := 1 |         //权重分布io_read  := 2 | mem_read := 5;cfg_read : {cfg_read_task;} | {cfg_read_task;} cfg_read;  //1/8io_read :  {io_read_task;} | {io_read_task;}  io_read;  //2/8mem_read : {mem_read_task;} | {mem_read_task;} mem_read;  //5/8endsequenceend
end

可以使用randcase建立随机决策树,但没有变量可供追踪调试。

initial beginint len;randcase1: len = $urandom_range(0,2);      // 10% : 0,1,28: len = $urandom_range(3,5);        // 80% : 3,4,OR 51: len = $urandom_range(6,7);     // 10% : 6 OR 7endcase$display("len=%0d", len);
end

randsequence和randcase是针对轻量级的随机控制的应用,可通过定义随机类取代上述随机控制的功能,且由于类的继承性使得在后期维护代码更方便。randsequence的相关功能在协调激励组件和测试用例时可能会用到,而randcase对应随机约束中的dist权重约束和if-else条件约束的组合

SystemVerilog学习笔记5——随机约束和分布相关推荐

  1. SV学习(8)——随机约束和分布、约束块控制

    SV学习(8)--随机约束和分布.约束块控制 1. 随即约束和分布 1.1. 为什么需要随机? 1.2. 要随机做什么? 1.3. 声明随机变量的类 1.4. 什么是约束 1.5. 权重分布 1.6. ...

  2. SystemVerilog学习笔记(可综合的部分)(一)

    SystemVerilog学习笔记(一) 1. Verilog-1995的数据类型 2. 网络(net)类型 3.变量(variable)类型 4.向量(packed arrays) 5.数组(unp ...

  3. SystemVerilog学习笔记

    SystemVerilog学习笔记(会持续更新~) 文章目录 SystemVerilog学习笔记(会持续更新~) SV数据类型 固定数组 固定数组的声明格式 一维数组与二维数组 固定数组的一些操作 固 ...

  4. [SV]SystemVerilog学习笔记之struct union

    SystemVerilog学习笔记(四) 一.结构体(struct) 1.1.结构体声明(struct) 结构体声明:结构体默认是变量,也可以声明为线网 var struct { // 通过var进行 ...

  5. [Systemverilog学习笔记] Thread Communication-Event、Semaphore、mailbox

    [Systemverilog学习笔记] Thread Communication-Event.Semaphore.mailbox 学习目标: 通过下文了解Event.Semaphore.mailbox ...

  6. SystemVerilog学习笔记1 ---《数据类型》

    1. 数据类型 1.1 logic 变量没有声明类型时,默认为logci verilog中有两种基本的数据类型:变量和线网(net).都为4状态(0.1.X.Z) SystemVerilog中将Ver ...

  7. (学习笔记)Oracle约束

    约束指表中的字段要满足某些要求或条件,又或者带有某些意义 1.主键约束:作用是保证一条数据的唯一性.例如,有一张班级姓名表,某一天来了两位同学,恰好两位同学是同名同姓,则需要一个非空且唯一的字段来区别 ...

  8. optaplanner学习笔记(十)约束配置:动态调整约束权重

    概要 为每个约束确定正确的权重和级别并不容易.因为各个约束之间存在优先级平衡的情况.此外,量化软约束的影响对我们来说通常是一种全新的体验,因此他们需要多次调整才能找到一个适合的权重和级别. 提供一个 ...

  9. numpy学习笔记之随机采样函数

    numpy的随机采样函数 np.random.choice(a, size=None,replace=None, p=None) 功能:Generates a random sample from a ...

最新文章

  1. 解决pip更新问题。 You are using pip version 19.0.3, however version 19.1 is available.
  2. .jsp与servlet之间页面跳转及参数传递实例
  3. 电商双11已臻巅峰,众筹的双11才刚刚开始
  4. C# 窗口最大化但不占用任务栏位置
  5. python图片超链接_python自动获得网页上的所有超链接并全部截图
  6. linux系统可以用迅雷吗,在Linux系统下使用wine运行迅雷5的方法
  7. 热释电传感器三个引脚_智能家居组件漫谈——人体传感器
  8. 数字金额转化为中文大写
  9. 网易云课堂资源合集百度云分享 下载
  10. 淘宝联盟官方APi在小程序云函数中的使用教程(附案例)
  11. python多边形的绘制教程_使用Python matplotlib绘制3D多边形
  12. Android流星雨效果---史上最炫,浪漫,值得陪你女朋友一起看~ [捂脸]
  13. Mybatis 详细的创建流程及创建第一个Mybatis增删改查程序 CRUD
  14. ios文件app访问samba服务器,ios链接samba服务器
  15. 设置数字和字符串的格式(已更新)
  16. 覆盖式理解Android 消息处理机制(带源码解析)
  17. 银河麒麟V10操作命令
  18. Excel快速对齐表格的中姓名(两个字姓名和三个字姓名对齐)
  19. 流程审批系统设计思路及实现方法
  20. 人生开始成熟的3个标志:承认父母普通,承认自己普通,承认孩子普通

热门文章

  1. 【bzoj4184】shallot 线段树+高斯消元动态维护线性基
  2. equals和hashCode详解
  3. “差分曼彻斯特编码”相比“曼彻斯特编码”有什么优势?
  4. Shopee虾皮的流量从哪里来?站内外都包括哪些方面呢?
  5. 不会用就是凹凸曼 iOS5操控详细教程
  6. jquery如何设置占位隐藏_JQuery显示、隐藏div的几种方法简明总结
  7. WRK Handle Table技术报告
  8. 解释:WIFI:T:WPA;S:linfen;P:13826975059;H:false; 是什么意思
  9. AOE网活动的最早、最迟发生时间及关键路径问题
  10. 手机 机器人 谢超_防范于未“燃” 这个机器人有双“火眼金睛”