4. 激励生成与场景建模
激励是验证平台真正“驱动”DUT 的部分。一个验证环境即使连接器、监视器、参考模型都齐全,如果激励无法覆盖协议允许的组合、无法命中边界条件、无法复现失败场景,覆盖率仍然会停在低位。本节围绕 UVM sequence 机制,说明如何用 SystemVerilog 构建定向激励与随机激励,并借助 Synopsys VC SpyGlass 对激励代码做静态检查,提前发现约束冲突、死代码和不可达分支。
一、激励的两个来源:定向与随机
定向激励(directed stimulus)指明确指定每个字段取值的激励,例如固定发送一个长度为 1 的短包、一个 CRC 错误的包、一个地址越界的访问。它的优点是意图清晰、可复现,适合验证复位序列、错误注入、协议违例等“必须发生”的场景。缺点是手工枚举组合,覆盖有限。
随机激励(constrained random)指通过 rand/randc 声明随机变量,用 constraint 描述合法取值范围,由求解器在约束空间内产生激励。它的优势是能在合法空间内自动探索,配合覆盖率驱动可以持续逼近未覆盖区域。工程实践中两者不是二选一,而是“随机为主、定向为辅”:随机负责广度,定向负责深度和特定错误路径。
二、UVM sequence 的层次结构
UVM 把激励组织成 sequence item、sequence、sequencer、driver 四层。item 是事务对象,sequence 是 item 的集合与生成逻辑,sequencer 负责仲裁与转发,driver 把 item 转换成引脚级信号。理解这个层次,才能知道约束应该写在哪里、随机化应该在哪个阶段发生。
三、用 SystemVerilog 写约束:从合法到有意图
约束不是“随便写几条”,而是把协议规则翻译成求解器能理解的形式。以一个 AXI 风格写事务为例,假设地址 4KB 对齐、突发长度 1~16、数据宽度 32 位:
class axi_wr_item extends uvm_sequence_item;
rand bit [31:0] addr;
rand bit [7:0] len; // 1~16 beats
rand bit [2:0] size; // 2^size bytes per beat
rand bit [31:0] data[];
constraint c_addr_align {
addr[11:0] == 0; // 4KB 对齐
}
constraint c_len_range {
len inside {[0:15]}; // 实际 beats = len+1
}
constraint c_size_fixed {
size == 3'd2; // 4 bytes
}
constraint c_data_size {
data.size() == len + 1;
}
constraint c_data_dist {
foreach (data[i])
data[i] dist { 32'h0 := 2, [32'h1:32'hFFFF_FFFE] :/ 8, 32'hFFFF_FFFF := 2 };
}
endclass
这里 dist 权重让全 0 和全 F 各占约 20%,其余值均分剩余权重,目的是让边界数据更容易被命中。inside 用于范围约束,foreach 用于数组元素约束。注意 data.size() == len + 1 把动态数组长度与 len 绑定,避免求解出长度不匹配的非法事务。
四、定向激励与随机激励的编排
在 body() 中,可以先用定向 sequence 完成复位后的一次基准写读,再用随机 sequence 做批量探索,最后用定向 sequence 注入错误。典型写法:
class wr_scenario extends uvm_sequence #(axi_wr_item);
`uvm_object_utils(wr_scenario)
task body();
axi_wr_item it;
// 1) 定向:单拍写,地址 0
`uvm_do_with(it, { addr == 0; len == 0; })
// 2) 随机:200 次随机写
repeat (200) `uvm_do(it)
// 3) 定向:越界地址,验证错误响应
`uvm_do_with(it, { addr == 32'hFFFF_F000; })
endtask
endclass
这种“定向—随机—定向”的编排,既保证基准场景可复现,又让随机部分覆盖大量合法组合,最后用定向激励命中错误路径。实际项目中,随机次数、定向场景数量应根据覆盖率缺口动态调整,而不是固定写死。
五、VC SpyGlass 对激励质量的静态检查
激励代码本身也可能有缺陷,而且这些缺陷往往在仿真中表现为“随机化失败”或“某些分支永远不命中”,排查成本高。Synopsys VC SpyGlass 可以在不运行仿真的情况下对 SystemVerilog/UVM 代码做静态分析,重点检查以下几类问题:
- 约束冲突:两条约束对同一变量给出互斥范围,求解器永远无解。例如同时要求
len == 0和len inside {[1:15]}。 - 不可达分支:约束把某变量限定在固定值,而后续
if分支却判断该变量为其他值,形成死代码。 - 随机稳定性:未固定 seed 时,同一 sequence 在不同仿真中分布差异过大,导致覆盖率波动。SpyGlass 可提示随机变量的分布依赖。
- 覆盖率可达性:coverpoint 的 bin 在约束空间内无法被命中,例如约束要求
addr[11:0]==0,但 coverpoint 却采样addr[11:0]的非零值。
使用方式通常是在项目脚本中调用 SpyGlass 的 lint/CDC/约束检查规则集,把激励文件加入分析列表,输出报告后逐条确认。对于约束冲突和不可达分支,应直接修改约束或分支条件;对于随机稳定性问题,应在测试中固定 seed 或使用 uvm_top.set_report_id_action 记录随机种子,便于复现。
六、一个可执行的检查清单
| 检查项 | 检查内容 | 判断依据 |
|---|---|---|
| 约束可解性 | 所有 constraint 是否存在互斥范围 | SpyGlass 无冲突告警,随机化成功 |
| 分支可达性 | if/else、case 分支是否被约束排除 | SpyGlass 无 unreachable 告警 |
| 随机分布 | dist 权重是否覆盖边界值 | 覆盖率报告中边界 bin 命中 |
| seed 可复现 | 失败用例能否用同一 seed 复现 | 记录 seed 后重跑结果一致 |
| 覆盖率反馈 | 未覆盖 bin 是否可通过调整约束命中 | 调整后覆盖率提升 |
把上述检查嵌入日常流程:每次修改 sequence 或 constraint 后,先跑 SpyGlass 静态检查,再跑随机仿真,最后看覆盖率报告。这样激励质量不再依赖个人经验,而是有明确的检查点和判断依据。