4、门级仿真环境搭建:综合后网表、SDF文件、库文件设置、门级仿真脚本示例
好,咱们进入正题。门级仿真,说白了就是拿综合后的网表来跑仿真。这跟RTL仿真完全是两码事。RTL仿真你关心的是功能对不对,门级仿真你关心的是时序能不能满足、有没有竞争冒险。
我个人习惯把门级仿真环境拆成四个部分:网表、SDF、库文件、仿真脚本。一个一个来聊。
4.1 综合后网表——你的设计变成了什么样子
综合后的网表,就是工具把你的RTL代码翻译成了标准单元库里的门电路。你想想看,原来写的 always @(posedge clk) 变成了什么?变成了一个D触发器加上一堆组合逻辑。
网表文件一般长这样:
// 综合后的Verilog网表
module top (
input clk,
input rst_n,
input [7:0] data_in,
output [7:0] data_out
);
// 一个D触发器的实例化
DFFRX1 \data_out_reg[0] (
.D(n1),
.CK(clk),
.RN(rst_n),
.Q(data_out[0]),
.QN()
);
// 组合逻辑
AND2X1 U3 (
.A(data_in[0]),
.B(data_in[1]),
.Y(n1)
);
endmodule
嗯,这里要注意。网表里全是标准单元的名字,比如 DFFRX1、AND2X1。这些名字来自你用的工艺库。不同工艺库,名字不一样。我在项目中遇到过,换了个工艺库,网表里所有单元名字都得重新映射,那叫一个头疼。
4.2 SDF文件——时序的灵魂
SDF(Standard Delay Format)文件,就是门级仿真的核心。它记录了每个门、每根连线的延迟信息。没有SDF,门级仿真跟RTL仿真没区别。
SDF文件长这样:
(CELL
(CELLTYPE "DFFRX1")
(INSTANCE \data_out_reg[0])
(DELAY
(ABSOLUTE
(IOPATH CK Q (0.12::0.15) (0.10::0.13))
(IOPATH RN Q (0.08::0.11) (0.07::0.09))
)
)
(TIMINGCHECK
(SETUP D CK (0.05::0.06))
(HOLD D CK (0.03::0.04))
)
)
你看,这里写了CK到Q的延迟是0.12到0.15纳秒,setup time是0.05到0.06纳秒。仿真器就是靠这些数据来判断时序是否违例。
4.3 库文件设置——仿真器得认识这些门
仿真器不认识 DFFRX1 是什么东西。你得给它提供库文件,告诉它每个标准单元的行为模型。
库文件一般有两种:
- Verilog库文件:用Verilog写的标准单元行为模型。最常见。
- VHDL库文件:用VHDL写的,比较少用。
库文件里定义了每个单元的:
- 端口方向(输入、输出、双向)
- 功能逻辑(比如D触发器的行为)
- 时序参数(setup、hold、delay)
我曾经犯过一个低级错误:库文件版本跟综合用的工艺库版本不一致。结果仿真跑出来一堆X态,查了两天才发现是库文件不匹配。嗯,从那以后我每次都要核对库文件的版本号。
4.4 门级仿真脚本示例——把一切串起来
好,现在咱们把网表、SDF、库文件都准备好了。怎么跑仿真?写个脚本。
我用的是Synopsys VCS,但其他仿真器思路一样。给你看个完整的脚本:
// 门级仿真脚本 (vcs_gate_sim.tcl)
// 设置库文件路径
set LIB_PATH "/home/design/libs/tsmc28nm"
set LIB_FILES "$LIB_PATH/verilog/tsmc28nm.v"
// 编译网表和库文件
vlogan -full64 -work work \
-v $LIB_FILES \
-v $LIB_PATH/verilog/tsmc28nm_udp.v \
../netlist/top_synth.v \
../tb/tb_top.v
// 加载SDF文件
vcs -full64 -debug_access+all \
-sdf min:tb_top.u_top:../sdf/top_synth.sdf \
-P $LIB_PATH/synopsys/synopsys_sim.db \
work.tb_top
// 运行仿真
./simv -l sim.log +maxdelays +mindelays +typdelays
这里有几个关键点:
-sdf min:tb_top.u_top:../sdf/top_synth.sdf:指定SDF文件,min表示用最小延迟模式。你也可以用max或typ。-P:指定工艺库的仿真模型,用于SDF反标。+maxdelays:仿真时使用最大延迟模式,检查setup是否违例。
+maxdelays(检查setup)、+mindelays(检查hold)、+typdelays(典型情况)。三种都过了,才算稳。
4.5 避坑指南——我踩过的那些坑
门级仿真环境搭建,坑不少。我列几个常见的:
- SDF反标失败:网表里的实例路径跟SDF里的路径不匹配。检查一下顶层模块名和实例名是否一致。
- 库文件缺失:有些标准单元在库文件里没定义,仿真器报
Unknown module。去工艺库目录下找找,一般都有。 - X态传播:门级仿真里X态特别多。别慌,先检查是不是SDF没反标成功,再检查是不是有未初始化的寄存器。
- 仿真速度慢:门级仿真比RTL仿真慢10倍以上。我一般只跑几个关键case,不会全量回归。
我曾经遇到一个特别诡异的bug:门级仿真跑出来一个信号一直为X,但RTL仿真完全正常。查了两天,发现是综合工具把某个组合逻辑优化掉了,导致SDF里没有对应的延迟信息。最后我加了dont_touch约束才解决。
4.6 总结一下
门级仿真环境搭建,说白了就是四步:
- 拿到综合后的网表
- 准备好SDF文件
- 配好库文件
- 写个脚本把上面三个串起来
嗯,听起来简单,但每一步都有坑。我建议你第一次搭环境时,先跑一个最简单的case,比如只检查一个寄存器的setup/hold。确认环境没问题了,再跑全量case。
下一章咱们聊聊门级仿真常见的错误和调试技巧。到时候我会分享一些我调试X态的心得。