进阶随机化:权重、蕴含、双向、soft 与内联约束
更新时间:2026-10-01。CRV 基础篇 讲了怎么描述合法空间,这一篇讲怎么“精细调控”随机:让常见场景多出现、条件联动、分层覆盖默认约束。
本文要回答的问题
- 怎么让随机不是均匀分布,而是贴合真实流量的权重?
- 字段之间有条件关系(只有写命令才有数据)怎么写?
- 想在某次用例临时加/关约束怎么办?
- 数组、队列这些“变长随机”怎么约束?
一、dist:控制出现权重
rand op_t op;
constraint c_op {
op dist { READ := 70, WRITE := 25, IDLE := 5 }; // 权重和=100
}:= 给出每项绝对权重;:/ 是权重在列表里平分({[0:3]:/40} 表示这 4 个值共享 40,各占 10)。用 dist 让激励分布贴近真实场景,而不是均匀浪费在用不到的组合上。
二、蕴含与条件约束
rand bit rw; // 0=读 1=写
rand bit [7:0] wdata;
constraint c_w {
rw -> wdata inside {[8'h00:8'hFF]}; // 写时才有数据约束
if (rw==0) wdata == 8'h00;
}a -> b 表示 a 成立时 b 必须成立;也可用完整 if/else。这解决了“某字段只在特定模式下才有意义”的联动。注意 -> 是单向触发,不是双向等价。
三、双向约束与求解顺序
约束默认双向:求解器把所有关系联立,不区分先后。这通常更好(减少无解),但当两个随机变量存在概率依赖时,需要 solve...before 指定先后:
rand bit en;
rand bit [3:0] x;
constraint c { en -> x > 0; solve en before x; }没有 solve before 时求解器可能让 x 先随机,en 被压成几乎总为 0;加了之后 en 按 50% 先决定。它改变分布,不改变合法解集。
四、soft 软约束与分层覆盖
constraint c_def { soft addr inside {[0:255]}; } // 默认值
...
t.randomize() with { addr == 32'hFFFF_FFFF; }; // 外层直接覆盖soft 约束是“默认值”,外层非 soft 约束或内联 with 可覆盖它,不会报冲突。适合在基类给保守默认、子类/用例按需收紧。
五、内联约束与动态开关
t.randomize() with { len inside {[1:4]}; rw == 1; }; // 仅本次生效
t.c_bad.constraint_mode(0); // 关闭某条约束
t.c_bad.constraint_mode(1); // 再打开
t.rand_mode(0); // 让某字段不再随机randomize() with {}临时叠加,是写场景用例最常用的方式。constraint_mode(0)关闭命名约束,专门构造非法激励。pre_randomize()/post_randomize()是随机化前后自动回调,可修正非随机字段、做收尾。
六、数组随机化
rand bit [7:0] payload[];
rand int idx[];
constraint c_arr {
payload.size() inside {[1:16]};
foreach (payload[i]) payload[i] inside {[0:127]};
idx.size() == 4;
unique { idx }; // 元素互不相同
}约束 size() 定长度、foreach 约束每个元素、unique 保证不重复(常用于选互不相同的端口/地址)。
七、约束分层图

八、常见坑
- 用
->当双向等价,漏了反向条件,产生非法组合。 - 缺
solve before导致条件变量几乎总不成立,覆盖打不到。 - soft 与硬约束冲突报求解失败,或该 soft 没 soft 导致无法覆盖。
- 数组忘了约束
size(),可能随机出超大数组拖慢仿真。 constraint_mode(0)关了忘记打开,后续用例激励全错。
小结
总结
进阶随机化用来精细调控激励:dist(:= 绝对权重、😕 平分权重)让分布贴合真实流量,蕴含 ->/if-else 表达字段条件联动(单向非等价),约束默认双向联立、用 solve...before 只改变概率分布而不改合法解集,soft 提供可被外层/内联 with 覆盖的默认值,constraint_mode/rand_mode 动态开关以构造非法或场景用例,数组用约束 size()、foreach 逐元素、unique 去重,配合 pre/post_randomize 钩子收尾。