【SystemVerilog】SV 随机测试

本文介绍了SystemVerilog中如何通过伪随机数生成器实现随机激励,包括内置的随机函数、randcaase和randsequence结构、基于对象的随机生成以及随机变量的声明、约束条件、randomize()方法和随机模式控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 什么是随机

        在计算机系统中, 游戏算法和编码技术一直对随机有特殊的需求。 一个顺序执行机器,如处理器, 是一个确定的系统, 它自动地执行指令。 计算机行为的确定特性使得它们的数字序列是可预测的。 对于真正的随机, 无法凭借当前值来预测下一个值。 计算机系统的确定性是很难实现一个随机的行为。
        借助伪随机数产生器, 计算机系统中引入随机。 也就如其名字一样, 伪随机数不是真正意义上的随机。 然而通过数学公式或者一个预处理的列表, 随机数是可以获取的。 有很多研究伪随机算法的理论, 现代算法对于生成伪随机数已经可以很接近真正的随机。
        伪随机数是可以预测的, 假如你知道序列的第一个数值。 对于某些应用, 可预测性也是很重要的特性。 对于验证而言, 可预测性是有好处的, 因为它使得失败的测试用例可以在同样的条件下重新运行, 从而重现特定的情景。 对于仿真而言, 一系列随机数可以在几个测试中用来重现, 伪随机同样也可以实现。
        复杂的芯片设计要求激励产生能够自动化, 可以是确定的也可以是随机的。 确定测试用例用来检验特定的功能或者参数。 随机激励可以用来检查不同的功能覆盖点减少测试用例的开发, 但是它增加了验证平台的复杂性。SystemVerilog采用伪随机数产生器来产生随机变量, 从而产生随机激励。

2. 随机生成机制


SystemVerilog有四种机制可以创建随机激励, 实现随机数的产生和随机控制。
1) 采用SystemVerilog内置的系统函数来产生随机数, 其中有!urandom 和!urandom_range
等, 除 此 之 外, 还 有 一 系 列 标 准 概 率 分 布 的 系 统 函 数:!random、!dist_uniform、!dist_normal、!dist_exponetial、!dist_possion、!dist_chi_square、!dist_t和dist_erlang。
2)randcaase 和randsequence 结构来实现随机的分支选择
3) 基于对象的随机生成, 随机地初始化对象的数据成员的值。
4) 标准随机函数std::randomize()可以随时对任意变量进行随机化并添加约束。

3. 基于对象的随机生成

直接看一个例子:

小ICer

可以看出,基于队形的随机生成包含了三个部分:定义随机变量、指定约束条件(可选)、通过调用内置randomize()方法产生随机。

3.1 随机变量

类中的数据成员可以使用randrandc关键字来声明为随机的变量。 其语法如下:

使用 rand关键字声明的变量是标准的随机变量。 它们的值在其取值范围内均匀分布。
例如:
rand bit[7:0] y;

这是一个8位的无符号整数, 取值范围为0到255。 如果未被约束, 该变量应该以相同的概率被赋值为0到255 范围内的任意值。在本例中, 连续地调用随机化产生相同值的概率为1/256.
      使用randc声明的变量是周期随机变量, 它在声明范围内的一个随机排列中循环地选择所有的值。 为了更好地理解randc, 我们来看看下面一个两位的随机变量y:
rand bit[1:0] y;
变量 y可以在 0、 1 、 2 和 3 之间取值。 随机化的过程会为y的取值范围计算一个初始的随机排列, 然后再连续的调用中按顺序返回这些值。 当返回一个排列的最后一个元素后, 它会通过计算一个新的随机排列来重复这一过程。
        randc的基本思想是在取值范围内的所有值中随机地遍历, 并且在一次遍历中不会有重复的值。 当本次遍历结束后, 会自动启动一个新周期的遍历。 形象的例子就是扑克牌发牌的过程, 每一轮都有54张随机序列的扑克牌, 只有当54张牌发完以后才能进入下一轮的发牌过程, 在这个过程中, 同一张牌不能在本轮中重复出现两次
在定义随机变量的时候需要注意的事项如下。
1) 解析器可以随机化任何整型类型的单一变量。
2) 数组可以声明成rand或randc 在这种情况下, 数组的所有成员元素都被当作 rand或randc看待
3) 动态数组和关联数组可以使用rand或randc声明。 数组中的所有元素都被随机化, 并会重写先前的任何数据。
4) 使用rand或randc声明的动态数组的大小也可以被约束。 在这种情况下, 数组应该根据大小的约束被重新调整, 并且会接着随机化所有的数组元素。 数组大小的约束如下所示:

rand bit[7:0] len;
rand integer data[];
constraint db {data.size == len;}

变量len 具有8位的宽度。 解析器会在8位的范围内 (0 到 255) 为len变量计算一个随机值, 接着会随机化data数组的第一个len元素。 如果一个动态数组的大小没有被约束, 那么randomize()会随机化数组中的所有元素, 而大小不会被改变。
5) 对象句柄可以使用 rand声明, 在这种情况下, 该对象的所有变量和约束都被并发地求解, 对象不能使用 randc声明。

3.2 约束条件

SystemVerilog的约束支持以下两种方式。
1) 指定取值范围, 通过指定随机值的上限或者下限, 或者某一个集合, 或者某一特定值
来限制其范围。
2) 分布式约束, 为随机值的取值范围指定特定的权重, 来影响其取值的概率分布。

  • inside集合操作
    • expression inside {set}
    • eg: constraint CC {x inside {3, 5, [9:15], [24:32};}
  • dist分布操作:
    • expression dist {dist_list | value_range [:= |:/dist_weight}
    • 分布集合为以逗号分隔的整型表达式和范围的列表。列表中的每一项都可以带有一个可选的权重, 这个权重使用 “:=” 或 “ :/” 操作符说明。 如果没有为某一条目指定权重,那么缺省权重是:=1 。 权重可以是任意的整型表达式。
    • eg: constraint x_dist {x dist {100 :=1, 200 :=2, 300 :=5};}
    • 当采用:=操作符为一个条目指定一个权重时,如果条目是一个范围,它为范围中的每一个值指定权重。当采用:/操作符为一个条目指定权重时,如果条目时一个范围,它会将范围作为一个整体指定权重;如果范围中有n个值,那么范围中每个值得权重为range_weight/n.

3.3 随机方法

        对象中的变量使用randomize()方法进行随机化。 每个类都有一个内建的 randomzie()虚方法, 它的声明原型如下:
virtual function int randomize();
randomize()方法是一个虚函数, 它为对象中的所有激活的随机变量产生随机值, 产生的随机值应该符合激活的约束。

3.4 随机使能控制

        一般情况下, 所有定义的随机变量和约束默认都是被激活。 但是, 在运行的过程中我们可以通过使用内置方法 rand_mode() 和constraint_mode()对随机变量的状态和约束进行控制、 关闭或者激活。

         rand_mode() 可以用来控制激活或关闭一个随机变量。 当一个随机变量处于未激活状态的时候, 这个随机变量就好像没有使用rand或randc 声明一样。 未激活的随机变量不会被randomize()方法随机化, 并且它们会被解算器当作一般的状态变量。 所constraint_mode()有的随机变量最初都是激活的。
rand_mode() 方法是内置的,并且不能被重写。

         默认情况下, 所有的约束都是激活的。constraint_mode()方法可以用来控制激活或关闭一个约束。 当约束处于未激活 ( 关闭) 状态时, 它不会被 randomize()方法采用。constraint_mode()方法是内建的并且不能被重写。

4. 标准随机函数

标准随机函数与类的随机方法的作用相同, 只是它仅限于操作当前范围内的变量而不是类成员变量。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值