SV随机化控制
控制方法
分布控制
- 系统预定义的回调函数,可以在类中重写,以便在随机化过程的关键节点注入自定义逻辑
pre_randomize():在开始执行、求解约束之前自动调用post_randomize():在成功执行、赋值之后自动调用- 如果
randmoize()失败,post_randomize不会被调用
1 | class Packet; |
禁用函数
禁用变量
- 禁用变量:
rand_mode(),临时关闭某个变量的随机化,使其在randomize()调用过程中保持当前值不变rand_mode(0):关闭指定变量的随机化rand_mode(1):开启指定变量的随机化rand_mode():返回变量的当前随机化状态
1 | class Register; |
禁用约束
- 禁用约束:
constraint_mode(),每个约束块都能被单独开启或关闭constraint_mode(0):禁用指定的约束constraint_mode(1):启用指定的约束constraint_mode():返回当前约束的启用状态
1 | class Bus; |
过程化随机
随机选择
randcase- 是一个过程化的加权随机选择语句,根据指定权重从多个分支中随机选择一条来执行
- 不像概率约束中权重分布用于随机化数据值,而是用于随机化控制流
- 下例为使用
randcase和随机化函数$urandom_range的随机控制
1 | initial begin |
随机序列
-
randsequence- 是一个过程化的随机序列生成语句,可以在执行过程中逐步调试
- 不像迭代约束中的随机序列只能通过调用
randomize()得到随机化结果而无法知道执行过程
-
两种过程化随机语句的比较
randsequence也能像randcase一样实现加权选择,但从代码可读性、编译速度等方面都逊于randcase- 反过来看,
randsequence生成复杂、有序、多层次的序列是randcase无法做到的
1 | task do_something(); |
randsequence语法
1 | randsequence ( main ) // 从'main'产生式开始 |
- 下例为使用
randsequence进行递归操作的命令发生器- 定义了一个名为
stream的随机序列,其产生式定义了三种操作的权重分布 - 各操作的产生式都包含了两个选项,不指定权重时默认各占50%概率
cfg_read操作的第一个选项为执行一次cfg_read_task()后结束- 第二个选项为执行一次任务后,递归调用自身
cfg_read - 因此
cfg_read操作至少会执行一次cfg_read_task(),其余两个操作同理
- 定义了一个名为
1 | initial begin |
种子与函数
随机化种子
- 随机化算法是伪随机的,由一个初始的种子值驱动,相同的种子会产生完全相同的随机数序列
srandom(seed)方法- 为一个特定的对象实例设置随机数生成器的种子
- 每次运行仿真,该对象产生的随机序列都将完全一致,便于复现失败的测试用例
1 | class Generator; |
- 仿真参数控制
- VCS允许通过命令行参数指定全局种子:
+ntb_random_seed=12345 - 如果不手动指定种子,仿真器通常会使用系统时间作为默认种子,每次运行都会得到不同结果(类似手动指定
+ntb_random_seed=$$(date +%N)的效果)
- VCS允许通过命令行参数指定全局种子:
随机化函数
- 对于SV随机化,除了使用CRT机制创建对象和定义约束,也可以直接调用仿真器内置的系统函数快速生成随机数,或在CRT中调用
dist_*系列函数完成复杂随机化的建模
标准函数
random():返回一个32位有符号的随机整数urandom():返回一个32位符号的随机整数urandom_range(max,min):返回一个指定范围内的无符号整数- 参数
min的缺省值为0 - 如果
max比min小,参数列表会自动反向
- 参数
1 | int signed_var; |
分布函数
$dist_*系列概率分布函数,使用局部种子生成具有特定统计特性的随机序列- 用于模拟真实世界的噪声、延迟、故障间隔等场景
- 都需要种子
seed作为参数,控制随机序列
- 由于SV CRT的约束块是声明式的,而随机化函数是一个过程化调用,故不能直接在约束块中使用随机化函数
1 | // ==== 回调函数后处理 ==== // |
均匀分布
dist_uniform(seed, start, end):以实数形式返回一个区间内的随机整数start:范围起始整数end:范围结束整数
1 | // 模拟掷骰子 |
正态分布
dist_normal(seed, mean, std_dev):经典“钟形分布”;返回一个符合正态分布的随机实数mean:分布均值(期望值)std_dev:分布标准差(大于0)
1 | // 模拟一个期望值为 100ns,标准差为 15ns 的延迟 |
泊松分布
dist_poisson(seed, mean):描述某个时间或空间范围内,某事件发生次的概率;以实数形式返回一个非负的随机整数mean:期望,等于标准差
1 | // 模拟一个小时内平均发生 3 次错误 |
指数分布
dist_exponential(seed, mean):描述泊松过程(即事件以恒定的平均速率连续且独立地发生的过程)中随机事件发生的时间间隔;返回一个非负的随机实数mean:单位时间内,事件发生的次数
- 模拟平均每秒到达 5 个数据包的流量
1 | int seed = 789; |
卡方分布
dist_chi_square(seed, degree_of_freedom):个服从标准正态分布的随机变量的平方和,构成新的随机变量的分布规律;返回一个非负的随机实数degree_of_freedom:自由度,自由度越大,分布曲线越扁平,越接近正态分布
- 在验证中较少用于生成激励,更多用在测试平台分析组件或记分板进行统计检验
- 下例是用卡方分布函数比较期望频数与实际观测频数之间的差异,如果根据这个统计量计算出的概率非常小,说明在原假设成立的前提下,观察到
1 | // 假设检验一个随机数生成器(0-9) |
T分布
dist_t(seed, degree_of_freedom):模拟出现极端值概率更高的随机现象;返回一个随机实数degree_of_freedom:自由度
- 常用于对小样本或高方差过程进行建模,或模拟具有高不确定性的测量过程
- 下例为模拟不稳定的传感器读数,
$dist_t生成的误差值出现 -4、+5 等极端值的概率,远高于$dist_normal;这使得测试可以更容易地捕获到设计在处理异常输入时的潜在问题
- 下例为模拟不稳定的传感器读数,
1 | module sensor_model; |
埃尔朗分布
dist_erlang(seed, k, mean):指数分布的广义形式,描述的是次独立事件所需的总时间;返回一个非负的随机实数k:形状参数(阶数,整数)mean:分布的平均值
- 常用在通信和排队论中模拟总服务时间或总等待时间
- 下例为模拟网络数据包的多级跳转传输延迟:假设一个数据包要依次经过 3 个网络节点(路由器)才能到达目的地;每个节点的处理延迟是随机的,且平均延迟为 1 个时间单位
1 | class NetworkPacket; |