第六章:随机化(续1)

6.6 pre_randomize和post_randomize函数

我们在调用randomize()函数之前或者之后要立即执行一些操作。比如,在随机化之前可能要设置类里的一些非随机变量(上下限、权重),或者随机化之后需要计算随机数据的误差矫正位。
SystemVerilog中可以使用void类型的pre_randomize和post_randomize函数来完成这些功能。void类型的函数并没有返回值,与任务不同,并不会消耗时间。

6.6.1 构造浴缸型分布函数

我们在实际的应用中,通常要用到一些非线性的随机分布,这时候我们希望能够有一种浴缸型的分布,在两端的概率大,中间的概率小。
可以通过详细描述dist约束构造浴缸型的分布,但是需要多次调整才能获得需要的形状。
在Verilog中,我们已经提供了很多非线性函数,例如:$dist函数,但是并没有浴缸型函数,这时我们可以通过两条指数曲线去构造我们想要的函数。
常用的函数:

  • $random() ——平均分布,返回32比特有符号随机数;
  • $urandom() ——平均分布,返回32比特无符号随机数;
  • $urandom_range() ——在指定范围内的平均分配;
  • $dist_exponential() ——指数衰落;
  • $dist_normal() ——钟型分布;
  • $dist_poisson() ——钟型分布;
  • $dist_uniform() ——平均分布;
    浴缸型分布
    构造浴缸型分布
    值得一提的是由于变量value是由function计算得到的,而不是随机约束求解器得到的,所以并不需要rand修饰符定义。

6.7 约束的技巧和技术

我们怎样才能写出便于维护和修改的CRT?通常是有一些小技巧的。下面我们就这些技巧做一下介绍。

6.7.1 使用变量的约束

通常一些上下限还有一些权重值,可以通过设置一个变量来维护。
权重
可以通过改变read8_wt=0,来禁止这项命令生效。缺省情况下,read8_wt,read16_wt,read32_wt是1,1,1.

6.7.2 用约束检查值的有效性

调用handle.randomize()函数的同时,SystemVerilog会检查这些变量是否满足约束条件。

6.7.3 调试函数

在随机化的过程中,为了输出随机化的结果,我们通常会设置function void display()函数来进行可视化输出。

6.7.4 非随机值的使用

如果一套的随机约束已经产生了大部分你想要的激励向量,只有少数几个向量需要修改,那么你可以使用rand_mode()函数把这些变量设置成非随机变量。
使用rand_mode禁止变量的随机化
利用调试函数得出结果
结果
对length变量进行rand_mode()设置以后,约束丧失了对length的约束能力。

6.7.5 随机化个别变量

上一小节,我们讲了从一个大的约束里面除去对某个变量的约束,那么这一小节我们来讲,只对某一个或者某几个变量进行约束。
在调用randomize()函数时只传递变量的一个子集,这样的话就只会随机化类里面的几个变量。只有参数列表里面的变量才会被随机化。所有的约束仍然保持有效。
随机化类里面的一部分变量
low是一个非随机变量,却被随机化赋于了一个随机值,并且满足约束条件。

6.7.5 打开或关闭约束

如果利用if-else语句声明的约束显得很复杂,可读性不是很强的情况下,可以采用打开或关闭进行约束。

6.7.6 在测试过程中使用内嵌约束

使用random()with{}内嵌约束语句使约束的作用范围局部化,作为对约束的补充是一种很好的做法。但是与之而来的问题是约束代码位于代码不同的位置,还难维护;其次很难在不同的测试里复用这些内嵌约束。

6.7.7 在测试过程中使用外部约束

我们知道函数的函数体可以在函数的外部定义,同样,约束的约束体也可以在类的外部定义。
带有外部约束的类带有外部约束的程序

  • 外部约束可以放到另一个文件中,从而在不同的测试里可以复用外部约束。
  • 外部约束对类的所有实例都起作用,而内嵌约束仅仅影响一次randomize()调用。

6.8 随机化常见的错误

6.8.1 小心使用有符号变量
  • 除非必要,不要在随机约束里使用有符号的数据类型。
  • 在使用无符号的数时,一定要注意是否溢出,这个问题可以通过限制位宽来解决。

6.9 迭代和数组约束

以上篇幅我们都只对标量类型的变量进行约束,现在思考如何在随机化数组时进行约束?
利用foreach约束和一些数组函数可以改变值的分布性状。
利用foreach会影响仿真器的运行速度,特别是遇到foreach嵌套的时候,这个时候我们可以通过使用randc变量来代替foreach的嵌套。

6.9.1 数组的大小

size()函数可以用来约束动态数组或队列里的元素个数。
约束动态数组的大小
一定要设置数组的上限,否则会产生成千上万个元素。

6.9.2 数组元素的和

sum()函数可以用于约束数组中元素的和。在使用sum()函数的时候,你需要注意一下几点:

  • 使用无符号的数
  • 注意位宽
  • 注意溢出问题
6.9.3 约束数组和队列的每一个元素

foreach能够对数组里的每一个元素进行约束。
foreach约束
使用foreach产生递增的数组元素的值
foreach约束只能有一个数组名,不允许使用层次化的引用。

6.9.4 产生具有唯一元素值的数组

**怎么才能产生一个随机数组,使它的每一个元素的值都是唯一的呢?
方法一:使用嵌套的foreach循环让求解器比较任意两个元素,但是这样会降低仿真器的求解速度。
foreach的嵌套
方法二:使用包含randc变量辅助类,这样的话就可以不断随机化同一个变量。
使用randc辅助类产生唯一的元素值
方法三:最为常用的一种方法。将方法二中的常量参数化。
唯一值发生器
产生元素具有唯一值的随机数组的类

  • new函数用来产生max_value,用于RandcRange的参数输入。
  • display函数用于调试输出。
    使用类
posted on 2018-08-28 20:23  猪肉白菜_125  阅读(1384)  评论(0编辑  收藏  举报