4. 权重与分布:dist关键字、:=与:/操作符的区别、权重分配实战、常见陷阱
各位同学,咱们今天聊一个非常实用的话题——权重与分布。
做随机约束仿真,说白了就是让验证工具帮我们“掷骰子”。但问题来了:有时候我们希望某些值出现的概率高一些,某些值出现的概率低一些。这时候就需要用到 dist 关键字了。
我个人习惯把 dist 叫做“加权随机”。它不像 inside 那样均匀分布,而是允许你手动控制每个值的“中奖概率”。
4.1 dist 关键字的基本用法
dist 用在约束块里,后面跟一个分布列表。每个分布项由值和权重组成。看个例子:
class Packet;
rand int addr;
constraint c_addr {
addr dist {
0 := 1,
[1:10] := 5,
[11:20] := 10
};
}
endclass
这个约束的意思是:addr 取 0 的概率是 1 份,取 1~10 的概率是 5 份,取 11~20 的概率是 10 份。注意,这里的“份”是相对权重,不是绝对概率。
嗯,这里要注意:dist 只能用于 rand 变量,不能用于 randc。我在项目中遇到过有人把 dist 用在 randc 上,结果仿真器直接报错。你想想看,randc 是循环随机,跟权重分布天生冲突。
4.2 := 与 :/ 操作符的区别
这是新手最容易搞混的地方。我刚开始学的时候也绕了半天。
:= 操作符:表示“每个值分配相同的权重”。
比如 [1:10] := 5,意思是 1 到 10 这 10 个值,每个值都分到 5 份权重。总权重就是 10 × 5 = 50 份。
:/ 操作符:表示“整个范围分配一个总权重,内部均匀分配”。
比如 [1:10] :/ 5,意思是 1 到 10 这个范围总共分到 5 份权重,每个值分到 5/10 = 0.5 份。
看个对比表格就清楚了:
| 写法 | 含义 | 每个值权重 | 总权重 |
|---|---|---|---|
[1:3] := 6 |
每个值 6 份 | 6 | 18 |
[1:3] :/ 6 |
总共 6 份 | 2 | 6 |
说白了,:= 是“按值分配”,:/ 是“按范围分配”。
我个人建议:如果你想让某个范围内的每个值概率差不多,用 :=;如果你只想控制整个范围的总概率,用 :/。我曾经在一个项目里用 :/ 给地址空间分配权重,结果发现地址分布太稀疏了,后来改成 := 才解决问题。
4.3 权重分配实战
光说不练假把式。咱们来一个实际场景:
假设你要验证一个网络包处理器。包的长度有几种情况:
- 最小包(64字节):偶尔出现
- 正常包(128~512字节):经常出现
- 最大包(1518字节):偶尔出现
- 超长包(1519~2000字节):极少出现
用 dist 可以这样写:
class Packet;
rand int pkt_len;
constraint c_len {
pkt_len dist {
64 := 1,
[128:512] := 10,
1518 := 2,
[1519:2000] :/ 1
};
}
endclass
这里我用了 :/ 处理超长包范围,因为我不想让 1519~2000 这 482 个值每个都占 1 份权重——那样概率就太大了。用 :/ 1 表示整个范围只占 1 份,每个值出现的概率极低。
你想想看,如果不小心写成 [1519:2000] := 1,那超长包的总权重就是 482 份,比正常包还多,仿真结果就完全偏离实际了。
4.4 常见陷阱
做验证这么多年,我在 dist 上踩过的坑还真不少。下面几个是高频雷区:
有些同学想“让某个值永远不出现”,就把权重设为 0。但 dist 不支持 0 权重。正确的做法是用 solve...before 或者干脆不写这个值。
我曾经见过有人写 addr dist { 0 := 0, [1:10] := 1 },结果仿真器报了个奇怪的警告,然后 addr 还是偶尔取 0。嗯,别这么干。
理论上权重可以是任意正整数,但太大的权重(比如 1000000)会导致仿真器计算概率时出现精度问题。我一般控制在 1~100 之间。
dist 列表里的范围不能重叠。比如你不能同时写 [1:10] := 5 和 [5:15] := 3。仿真器会报错,因为 5~10 这个区间不知道该听谁的。
如果你需要让某个值出现的概率是另一个值的两倍,直接写权重 2 和 1 就行。不需要算百分比,dist 会自动归一化。
另外,调试时可以用 $urandom_range 配合 dist 做快速验证。我经常写个小 testbench,跑 10000 次随机,统计一下分布是否符合预期。
4.5 总结一下
权重分布这东西,说白了就是让随机更有“人性”。
dist是加权随机,:=按值分配,:/按范围分配- 权重值用 1~100 就够了,别搞太大
- 范围不能重叠,权重不能为 0
- 实战中多用
:/控制大范围的总概率
下一章咱们聊聊约束的优先级和 solve...before,那也是个容易翻车的地方。到时候见。