4、时序与仿真联动:从时序违例反推仿真激励、利用仿真复现时序路径、时序仿真模型
各位好,我是老李。今天聊的这个话题,是我个人觉得整个时序验证里最有意思的部分——时序和仿真怎么联动起来干活。
说实话,我刚入行那会儿,STA和仿真在我眼里是两码事。STA跑完,看到违例报告,我就去改约束、调buffer。仿真呢?那是功能验证的事。直到有一次,一个setup违例怎么都修不掉,我盯着报告看了半天,突然意识到——这个违例路径,仿真里根本就没跑到过。
嗯,从那以后,我就养成了一个习惯:时序违例,必须用仿真去复现。今天就把这套方法掰开揉碎讲给你听。
4.1 从时序违例反推仿真激励
你拿到一份STA报告,里面列了十几条违例路径。你怎么办?直接上手改约束?别急。
我建议你先问自己一个问题:这条路径,仿真里真的激活过吗?
为什么会这样问?因为STA是静态的,它枚举了所有可能的路径。但实际芯片工作时,很多路径根本不会被触发。比如一个多路选择器,你只选了通道0,那通道1到输出端的路径,就算有违例,也不会影响功能。
所以,第一步是反推激励。怎么做?
- 拿到违例路径的起点和终点:比如从寄存器A的时钟端到寄存器B的数据端。
- 分析路径上的组合逻辑:有哪些MUX、AND、OR?它们的控制信号是什么?
- 反推出激活条件:要让信号从A传到B,哪些控制信号必须为特定值?
- 构造仿真激励:让这些控制信号在仿真中满足条件。
核心思路:STA告诉你“可能有问题”,仿真告诉你“到底有没有问题”。
我记得有一次,一个setup违例出现在一个很深的加法器链路上。STA报告说违例了200ps。我反推了一下,发现这条路径只有在特定操作数组合下才会激活。我构造了一个仿真用例,专门喂那种数据。结果呢?仿真跑完,功能完全正确。为什么?因为那个加法器用了超前进位,STA分析的是最坏情况,但实际数据根本不会触发最坏路径。
我的习惯:对于每条违例路径,先花10分钟反推激励。如果仿真里跑不到,那就标记为“低优先级”。别一上来就改网表。
4.2 利用仿真复现时序路径
好,现在你确认了这条路径在仿真里能激活。下一步是什么?用仿真把这条路径的时序行为复现出来。
说白了,就是让仿真器告诉你:信号从起点到终点,到底走了多久。
怎么做?我一般用两种方法:
- 波形测量法:在波形里找到起点和终点的跳变沿,手动量一下时间差。简单粗暴,但路径多了就累死人。
- 断言检查法:写一个SystemVerilog断言,直接测量路径延迟。比如:
// 测量从clk到data_out的延迟
property check_path_delay;
@(posedge clk)
$rose(data_in) |->
##[0:10] $rose(data_out);
endproperty
// 或者用$time来精确测量
always @(posedge clk) begin
if ($rose(data_in)) begin
start_time = $time;
end
if ($rose(data_out)) begin
end_time = $time;
path_delay = end_time - start_time;
if (path_delay > 500) // 假设约束是500ps
$display("WARNING: Path delay %0t exceeds limit", path_delay);
end
end
我个人更推荐第二种。为什么?因为你可以批量检查。写一个通用的监测模块,把STA报告里的路径都导进去,仿真时自动报出实际延迟。
注意:仿真里的延迟是“功能延迟”,不包含PVT变化。所以仿真测出来的延迟通常比STA小。但没关系,我们要的是“趋势”——如果仿真里延迟都很大,那STA违例基本跑不掉。
我曾经在一个项目里,用这种方法抓出了一个隐藏很深的hold违例。STA报告里有一条hold违例,但仿真怎么都复现不出来。我仔细一看,原来那条路径上有个时钟门控,STA分析时假设门控一直打开,但实际仿真中门控大部分时间是关的。我调整了激励,让门控在特定时刻打开,hold违例立刻在仿真中出现了。
4.3 时序仿真模型
说到仿真模型,很多人觉得就是RTL代码。其实不对。时序仿真需要专门的模型,我称之为“时序感知模型”。
这类模型要干三件事:
- 模拟门级延迟:不是功能延迟,而是真实的单元延迟。
- 模拟信号转换时间:slew rate对延迟的影响。
- 模拟时序检查:setup/hold检查、脉冲宽度检查等。
怎么做?我一般用SDF反标。把综合后的门级网表,加上SDF文件,跑后仿真。这样仿真器就能知道每个单元的延迟是多少。
// 在仿真脚本中反标SDF
initial begin
$sdf_annotate("design.sdf", top.u_dut);
end
但这里有个坑——SDF反标后的仿真,速度会慢很多。你想想看,原来RTL仿真一秒跑完,现在可能要跑一小时。所以我不建议全芯片都做SDF反标。我通常只对违例路径所在的模块做反标,其他模块还是用RTL。
我的做法:建立一个“时序仿真分区”。把STA报告里违例最多的几个模块挑出来,单独做SDF反标。其他模块保持RTL。这样既保证了精度,又控制了仿真时间。
另外,还有一种模型叫“时序抽象模型”。说白了,就是把复杂的时序路径抽象成一个简单的延迟模型。比如一个加法器,你不需要知道里面每个全加器的延迟,只需要知道从输入到输出的最大延迟。这种模型适合用在系统级仿真中。
我记得有一次,一个SoC项目,全芯片SDF反标后仿真跑不动。我就把CPU核的时序路径抽象成几个关键延迟参数,其他模块保持RTL。结果仿真速度提升了10倍,而且关键路径的时序行为完全正确。
下面这张图,是我总结的时序与仿真联动流程:
这张图的核心逻辑就是:STA报告是起点,仿真验证是终点,中间用激励反推和延迟测量连接起来。如果仿真延迟超标,那就确认是真实违例,需要修改设计。如果仿真延迟不超标,那就标记为假违例,可以放宽约束。
最后说一句,时序仿真模型不是万能的。它只能告诉你“在当前激励下,路径延迟是多少”。但STA能告诉你“在所有可能激励下,路径延迟的最大值”。所以两者是互补的,不是替代关系。
我个人习惯是:STA做广度,仿真做深度。STA扫一遍所有路径,找出可疑的。仿真针对可疑路径,深入验证。这样既不会漏掉问题,也不会浪费时间。
避坑指南:我曾经在一个项目里,完全依赖STA,结果流片回来发现一个hold违例导致芯片在某些条件下死机。后来查出来,那条路径在STA里被标记为“假路径”,但实际仿真中它确实被激活了。从那以后,我坚持每条违例路径都要用仿真复现一遍。
好了,今天的内容就到这里。时序与仿真联动,说白了就是让STA和仿真互相验证。你中有我,我中有你,才能把时序问题彻底搞清楚。