1、受约束的随机测试法(CRT)

  随着设计变得越来越大,要产生一个完整的激励集来测试设计的功能变得越来越困难。解决的办法是采用受约束的随机测试法自动产生测试集。CRT环境比定向测试的环境复杂,不仅需要产生激励,还需要通过参考模型、传输函数或其他方法预测输出结果。然而只要准备好了这个环境,就可以运行上百次的仿真而无需手工检查结果,从而提高工作效率,这也是CRT的优势:用CPU时间来换取人工检查的时间。

2、SV中的随机化

  rand修饰符:表示每次堆积化这个类时,这些变量都会赋一个值。

  randc修饰符:表示周期随机性,即所有可能的值都赋过值后随机化值才可能重复。

  约束:一组用来确定变量的值的范围的关系表达式,表达式的值永远为真。约束的表达式放在括号“{ }”中。

  randomize()函数在遇到约束方面的问题时返回0.

  不能在类的构造函数里随机化对象,类里的所有变量都应该是随机的和公有的,这样测试平台才能最大程度地控制DUT。

3、约束

  使用约束来定义各个变量的相互关系以产生有用的激励。

  约束块包含若干个表达式,在一个表达式中最多只能使用一个关系操作符(<,<=,==,>=,>)

  权重分布:使用dist操作符,如 src dist {0:=40,[1:3]:=60},这表示0的权重是40,1,2,3的权重都是60,总权重为220. dst dist {0:/40,[1:3]:/60},这表示0的权重是40,1,2,3三个值的总权重为60. 值和权重可以是常数或变量,设为变量可以动态改变权重。

  集合成员和inside运算符:可以用inside运算符产生一个值的集合,各个值的选取机会相等。c inside {[2:6]} ,这表示2<=c<=6。在inside约束中即使有重复的值,各个值的概率也是均等的。

  在集合里使用数组:把集合里的值保存到数组里后就可以使用这些值了。

  条件约束:让一个约束表达式只在某些时候才有效。例如,一条总线支持字节、字和长字的读操作,但只支持长字的写操作。“->”操作符可以产生和case操作符效果类似的语句块,它可以用于枚举类型的表达式,“if-else”适合于“真-假”类型的表达式。“A->B”表示满足A的情况下执行B

  双向约束:SV的约束是双向的,这表示它会同时计算所有的随机变量的约束。增加或删除任一个变量的约束都会直接或间接影响所有相关变量值的选取。“->”和“if-else”也是双向的,如{(a==1)->(b==0)}约束下有 (a,b)=(0,0)、(a,b)=(0,1)、(a,b)=(1,0)这三种情况,a==1时对b有约束,但b==0时对a没有约束。

4、解的概率

  使用solve……before约束引导概率分布:使用该约束不会改变解的个数,只会改变各个值的概率分布。不要过度使用solve……before,会降低速度

5、控制多个约束块

  一个类可以包含多个约束块,在运行期间,可以使用内建函数打开或者关闭约束。handle.constrain.constraint_mode()控制一个约束块的开启(1)或关闭(0);handle.constraint_mode()控制对象的所有约束。

6、有效性约束

  设置多个约束以保证随机激励的正确性。例如,总线的“读-修改-写”命令只允许操作字数据长度。

  rand enum {BYTE,WORD,LWRD,QWRD} length;

  rand enum {READ,WRITE,RMW,INTR} opc;

  constraint valid_RWM_LWRD{

    (opc==RMW)->length==LWRD;

  }

7、内嵌约束

  随着测试的进行,你面对的约束越来越多。它们会相互作用,最终产生难以预测的结果;用来使能和禁止这些约束的代码也会增加测试的复杂性。很多测试只会在代码的一个地方随机化对象。SV允许使用randomize() with来增加额外的约束,这和在类里增加约束是等效的。一般是在带约束的基类上进一步增加约束。如:

  constraint c1 {addr inside {[0:100],[1000:2000]};}

  t.randomize() with {addr >=50; addr <= 1500;};

8、pre_randomize和post_randomize函数

  可以在随机化之前设置类里的一些非随机变量,或者随机化之后计算随机数据的误差校正位。

9、随机数函数

  (1)$random()——平均分布,返回32位有符号随机数

  (2)$urandom()——平均分布,返回32位无符号随机数

  (3)$urandom_range()——在制定范围内的平均分布,如a=$urandom_range(3,10)

10、约束的技巧和技术

  (1)使用变量的约束:如改变变量范围的上下限,改变权重变量的dist分布

  (2)使用非随机值:使用rand_mode函数可以把变量设置为非随机变量。如:

    rand bit [7:0] length,payload[];

    assert (p.randomize());

    p.length.rand_mode();    //设置包长为非随机值

    p.length=42;                 //设置包长为常数

    assert (p.randomize());

  (3)随机化个别变量

    在调用randomize()函数时可以只传递变量的一个子集,这样就只会随机化类里的几个变量。只有参数列表里的变量才会被随机化,其他变量会被当做状态变量而不会被随机化。

  (4)打开或关闭约束

    可以使用条件操作符(->或if-else)来构建由非随机变量控制的约束。

    也可以使用constraint_mode()打开或关闭约束。

  (5)在测试过程中使用内嵌约束

    当新的约束是对缺省约束的补充时,可以使用randomize() with内嵌的约束语句使约束的作用范围局部化。

  (6)在测试过程中使用外部约束

    函数的函数体可以在函数的外部定义,同样,约束的约束体也可以在类的外部定义。可以在一个文件里定义一个类,这个类只有一个空的约束,然后在不同的测试里定义这个约束的不同版本以产生不同的激励。

    program automatioc test;

    include "packet.sv" constraint Packet::c_external {length==1;}

11、数组约束

  (1)约束动态数组的大小

    rand logic [31:0] d[];

    constraint d_size {d.size() inside {[1:10]};}

  (2)约束数组元素的和

    rand bit strob [10];

    constraint c_set_four {strob.sum()==4'h4;}

  (3)约束数组和队列的每一个元素

    下面的例子随机化一个长度[1:8]的数组,数组元素和小于1024:

    rand [9:0] len[];   //因为1024为10bit数,因此len的元素至少为10bit,和的位宽与元素的一样

    constraint c_len { foreach (len[i])

            len[i] inside {[1:255]};

            len.sum < 1024;   //1024为10bit数

            len.size() inside {[1:8]};}

  (4)使用randc可以辅助产生唯一的元素值的数组

12、随机控制

  在程序性语句里使用randcase,例如:

    randcase

    1:len=$urandom_range(0,2); //10%:0,1,2

    9:len=$urandom_range(3,5): // 90%:3,4,5

    endcase

13、代码示例

(1)类定义

package class_define;
//简单约束
class Packet;
rand bit [:] src,dst,data[];
rand bit a,b;
//设置约束
constraint c {
src <;
} // -> 类似case语句
constraint c2 {
(a==)->(b==); //(a,b)=(1,0)或者(0,0)或者(0,1)
b>; //现在只有(0,1)这一种情况 }
endclass:Packet //inside 和 指定权重的随机化
class Stim;
typedef enum {READ,WRITE,CONTROL} stim_e;
randc stim_e kind;
rand bit [:] len,src,dst;
bit c_stim_control;
bit [:] kind_weight=; constraint c_stim {
if(c_stim_control){
src inside {[:]};
}
else src inside {[:]}; //使用权重随机化
kind dist { READ := ,
WRITE := - kind_weight,
CONTROL := kind_weight
};
}
// 运行过程打开或关闭约束
constraint c1 {
len == ;
}
constraint c2 {
len == ;
} endclass:Stim //让集合中的数只被取一次
class RandcInside;
int array[]; //待选取的值
randc bit [:] index; //指向数组的指针
function automatic new(input int a[]); //构造,初始化
array = a;
endfunction
function int pick; //返回刚选取出来的值
return array[index];
endfunction
constraint c_size {index<array.size;} endclass:RandcInside //随机化数组,各个元素的值为1-255,和为1024
//注意:SV默认和的位宽与加数位宽一样,为了
//避免溢出,加数位宽为10bit
class array_random;
rand bit [:] len[];
constraint c_len {
foreach (len[i])
len[i] inside {[:]};
len.sum < ;
len.size() inside {[:]};
} function void display();
$write("sum=%4d,val=",len.sum);
foreach(len[i]) $write("%4d",len[i]);
$display;
endfunction:display endclass:array_random endpackage:class_define

(2)测试program

import class_define::*;
program test6;
initial begin
Packet p;
RandcInside ri;
Stim st;
array_random ar;
p = new();
ri = new('{1,3,5,7,9,11,13});
st = new();
ar = new(); // ========== 简单测试 =============
// ========== 条件约束 =============
// ========== 内嵌约束 =============
$display("====== class Packet ========");
assert (p.randomize())
else $fatal(,"Packet::randomize failed");
$display("p.src=%0d,p.a=%0d,p.b=%0d",p.src,p.a,p.b);
assert (p.randomize() with {src>;}); // 添加一个内嵌测试,8<src<10
$display("p.src=%0d,p.a=%0d,p.b=%0d",p.src,p.a,p.b); // ========== 带条件的约束、带权重的约束、
// ========== 运行过程打开或关闭约束 =============
$display("====== class Stim ======");
st.constraint_mode(); //关闭所有约束
st.c1.constraint_mode(); //开启c1约束
st.c_stim.constraint_mode(); //开启c_stim约束
st.c_stim_control = ; //改变c_stim的控制模式
st.kind_weight = ; // 改变kind变量的分配权重
assert(st.randomize());
$display("st.len=%0d,st.src=%0d,st.kind=%s",st.len,st.src,st.kind.name); st.constraint_mode(); //关闭所有约束
st.c2.constraint_mode(); //开启c2约束
st.c_stim.constraint_mode(); //开启c_stim约束
st.c_stim_control = ; //改变c_stim的控制模式
st.kind_weight = ; // 改变kind变量的分配权重
assert(st.randomize());
$display("st.len=%0d,st.src=%0d,st.kind=%s",st.len,st.src,st.kind.name); //让集合中的数只被取一次
$display("====== class RandcInside ======");
repeat (ri.array.size) begin
assert(ri.randomize());
$display("Picked %2d [%0d]",ri.pick(),ri.index);
end //随机化数组
$display("====== class array_random ======");
assert(ar.randomize());
ar.display(); end endprogram:test6

(3)输出

# ====== class Packet ========
# p.src=,p.a=,p.b=
# p.src=,p.a=,p.b=
# ====== class Stim ======
# st.len=,st.src=,st.kind=CONTROL
# st.len=,st.src=,st.kind=WRITE
# ====== class RandcInside ======
# Picked []
# Picked []
# Picked []
# Picked []
# Picked []
# Picked []
# Picked []
# ====== class array_random ======
# sum= ,val=

06-SV随机化的更多相关文章

  1. SV中的随机化

    SV搭建testbench的关键概念:CRT(constraint random test),测试集的随机化. 由于对象class由数据和操作组成,所以对数据的随机化一般放在一个class内.(对环境 ...

  2. SV randomize

    randomize中的变量只支持2-state的values,不支持4-states. randc类型的变量不能被约束在solve------before的语句中. constraint可以被定义在c ...

  3. SV中的数据类型

    Verilog-1995中规定的数据类型有:变量(reg), 线网(wire), 32位有符号数(integer), 64位无符号数(time), 浮点数(real). SV扩展了reg类型为logi ...

  4. APP漏洞扫描用地址空间随机化

    APP漏洞扫描用地址空间随机化 前言 我们在前文<APP漏洞扫描器之本地拒绝服务检测详解>了解到阿里聚安全漏洞扫描器有一项静态分析加动态模糊测试的方法来检测的功能,并详细的介绍了它在针对本 ...

  5. 《HelloGitHub月刊》第06期

    前言 <HelloGitHub>月刊做到第06期了(已经做了6个月了),在GitHub上获得了100+的stars,虽然不多,但是我很知足了,说明有人觉得这个项目是有价值的.同时园子中的' ...

  6. iOS系列 基础篇 06 标签和按钮 (Label & Button)

    iOS系列 基础篇 06 标签和按钮 (Label & Button) 目录: 标签控件 按钮控件 小结 标签和按钮是两个常用的控件,下面咱们逐一学习. 1. 标签控件 使用Single Vi ...

  7. javaSE基础06

    javaSE基础06 一.匿名对象 没有名字的对象,叫做匿名对象. 1.2匿名对象的使用注意点: 1.我们一般不会用匿名对象给属性赋值的,无法获取属性值(现阶段只能设置和拿到一个属性值.只能调用一次方 ...

  8. 异步编程系列06章 以Task为基础的异步模式(TAP)

    p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...

  9. 挣值管理(PV、EV、AC、SV、CV、SPI、CPI) 记忆

    挣值管理法中的PV.EV.AC.SV.CV.SPI.CPI这些英文简写相信把大家都搞得晕头转向的.在挣值管理法中,需要记忆理解的有三个参数:PV.AC.EV.     PV:计划值,在即定时间点前计划 ...

随机推荐

  1. HessianSharp如何部署到IIS7上?

    第一:添加映射 第二:选择经典

  2. Update、Insert注入技巧

    title: Update.Insert注入技巧 date: 2017-10-23 18:07:57 tags: ["注入"] 审计了不少代码,再看代码的时候最多出现的就是注入,很 ...

  3. 最近很火的namebase羊毛, 手把手教你怎么薅

    闲话少说直接说步骤: 1. 羊毛 https://www.namebase.io/airdrop 要求条件: 1) 要有github账号 2) 2019年2月之前有16+个follower 3) 要有 ...

  4. k8s系列---网络插件flannel

    跨节点通讯,需要通过NAT,即需要做源地址转换. k8s网络通信: 1) 容器间通信:同一个pod内的多个容器间的通信,通过lo即可实现: 2) pod之间的通信,pod ip <---> ...

  5. jq根据table的tr行数动态删除相应的行

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Linux 性能分析 工具命令

    背景知识:具备背景知识是分析性能问题时需要了解的.比如硬件 cache:再比如操作系统内核.应用程序的行为细节往往是和这些东西互相牵扯的,这些底层的东西会以意想不到的方式影响应用程序的性能,比如某些程 ...

  7. js—求数组中的最大最小值

    参考链接:https://www.w3cplus.com/javascript/calculate-the-max-min-value-from-an-array.html Math.min.appl ...

  8. Asp.net Core MVC(三)UseMvc设置路由

    在家办公,下班继续看点东西,不废话,继续看MVC的路由. asp.net核心mvc的路由是建立在asp.net核心的路由之上的.通过终结点加载路由中间件的配置方式在此不细说了,(DOTNET Core ...

  9. StarUML之一、UML的相关基本概念

    为什么用UML 项目需要,在项目开发实现前期进行框架技术设计(条条大路通罗马通罗马,画图或者写代码都可以,适合就可以!). 用户的交互我们通常用Axure(原型设计)体现, 框架和功能结构设计则用UM ...

  10. spring cloud微服务快速教程之(二)服务注册与发现 eureka

    0.为什么需要eureka 当我们从当体系统拆分为多个独立服务项目之后,如果aaa.com/uer.aaa.com/order;:相互之间调用,如果只是一个服务一个实例,那还可以直接通过固定地址(如h ...