3. 门级仿真库与模型准备

门级仿真的第一步不是写 testbench,而是把“库”和“模型”准备正确。RTL 仿真只依赖 Verilog 行为模型,而门级仿真要同时面对工艺库的时序信息、标准单元的仿真模型、IO 单元和存储器宏模型。任何一处配置错误,都会表现为 X 传播、时序全为 0、SDF 反标失败或仿真速度骤降。本节围绕 Synopsys 工艺库的组织方式、标准单元仿真模型的来源与选择、IO 与存储器模型的配置方法,以及最常见的陷阱展开。

一、Synopsys 工艺库的组成与 db 与仿真模型的关系

在 Synopsys 流程中,工艺库通常以 .db 形式提供给 DC/ICC 等综合与布局布线工具,而仿真需要的是 Verilog 仿真模型和 SDF 时序文件。二者来源相同但用途不同:.db 是二进制时序库,供综合工具计算路径延迟;仿真模型是标准单元的 Verilog 行为描述,供 VCS 等仿真器实例化并计算延迟。典型目录结构如下:

lib/
  sc9mc_logic_tt_1v0_25c.db          # 综合用时序库
  sc9mc_logic_tt_1v0_25c.lib         # 可读文本库
  sc9mc_logic_tt_1v0_25c.sldb        # 符号库
  verilog/
    sc9mc_logic.v                    # 标准单元仿真模型
    sc9mc_io.v                       # IO 单元仿真模型
    sc9mc_memory.v                   # 存储器仿真模型
  sdf/
    sc9mc_logic_tt_1v0_25c.sdf       # 时序反标文件

关键点在于:仿真模型必须与综合所用库的工艺角一致。若综合用 tt(typical)库,仿真却加载 ss(slow)模型,则时序分析结果与综合预期不符。常见做法是在 VCS 编译时通过 -y 指定库目录,并用 +libext+.v 让仿真器自动查找模块:

vcs -full64 -sverilog \
    -y $LIB_DIR/verilog \
    +libext+.v \
    +define+TSMC_CM_NO_WARNING \
    -top tb_top \
    -l compile.log

这里 -y 告诉 VCS 在指定目录中按模块名查找文件,+libext+.v 限定扩展名。若库文件命名与模块名不一致,或目录层级不对,VCS 会报 “module not found”,此时应检查文件内 module 名是否与文件名匹配。

二、标准单元仿真模型的来源与选择

标准单元仿真模型通常由 foundry 提供,常见形式有三种:行为级模型、带时序的 Verilog 模型、以及用于 SDF 反标的 specify 块模型。行为级模型只描述逻辑功能,延迟为 0,适合功能验证;带 specify 块的模型才支持 SDF 反标,用于时序验证。选择时需确认模型是否包含 specify 和 endspecify,以及是否支持 $sdf_annotate。

一个典型的带时序标准单元模型片段如下:

module NAND2X1 (A, B, Y);
  input A, B;
  output Y;
  nand (Y, A, B);
  specify
    (A => Y) = (0.12, 0.10);
    (B => Y) = (0.13, 0.11);
  endspecify
endmodule

其中 (0.12, 0.10) 表示上升延迟 0.12ns、下降延迟 0.10ns。若模型中没有 specify 块,SDF 反标会报 “no specify block” 警告,时序信息无法生效。另一个陷阱是模型中的 timescale 与 testbench 不一致,导致延迟被放大或缩小 1000 倍。建议在 testbench 顶部统一声明 `timescale 1ns/1ps,并确认库模型使用相同或兼容的时间单位。

三、IO 与存储器模型的配置

IO 单元模型比标准单元复杂,通常包含电源、地、上拉/下拉、施密特触发等行为。配置时需注意:IO 模型的端口顺序必须与网表中实例化一致,否则会出现电源短路或 X 传播。存储器模型则通常以 behavioral 或 functional 形式提供,部分 foundry 会提供带时序检查的 memory_model。配置存储器时,要确认地址位宽、数据位宽、深度与网表一致,并检查是否需要在仿真时加载初始化文件:

initial begin
  $readmemh("mem_init.hex", u_mem.mem_array);
end

若存储器模型内部已包含初始化逻辑,重复加载会导致冲突。此外,存储器模型往往有 setup/hold 检查,若 testbench 在时钟沿附近改变地址,会报 timing violation。此时应检查激励是否满足存储器数据手册的时序要求,而不是简单屏蔽检查。

四、常见陷阱与排查路径

门级仿真库配置的陷阱集中在四类:库版本不匹配、SDF 反标失败、模型缺失 specify 块、以及 timescale 不一致。下图给出从编译到反标的排查路径,帮助快速定位问题。

门级仿真库配置排查路径 编译阶段 module not found? 检查 -y 与 +libext 文件名=模块名? 确认库版本 tt/ss/ff 一致? SDF 反标 $sdf_annotate 报错? 检查 specify 块 模型是否含时序? 检查 timescale 1ns/1ps 一致? IO 模型 端口顺序匹配? 存储器模型 位宽/深度/初始化? 时序违例 setup/hold 检查? 统一原则:库版本一致、模型含 specify、timescale 统一、端口匹配 排查顺序:编译 → 反标 → 时序检查 → 功能验证

实际项目中,建议在编译脚本中固定库路径和工艺角,并在仿真日志中搜索 “Warning” 和 “Error” 关键字。若 SDF 反标成功,日志会显示 “SDF annotation completed”;若失败,会提示具体模块和原因。对于 IO 和存储器模型,优先使用 foundry 提供的版本,不要自行修改模型内部逻辑,否则可能掩盖真实时序问题。

实用检查清单:
  • 库文件目录是否包含 verilog/ 子目录,且文件名与模块名一致?
  • VCS 编译是否使用 -y 和 +libext+.v?
  • 标准单元模型是否包含 specify 块?
  • testbench 与库模型的 timescale 是否一致?
  • SDF 文件路径和工艺角是否与仿真库匹配?
  • IO 模型端口顺序是否与网表实例化一致?
  • 存储器模型是否需要 $readmemh 初始化,是否与内部初始化冲突?

完成库与模型准备后,下一步才是编写门级 testbench 和运行仿真。库配置的正确性直接决定后续时序分析的可靠性,因此建议在项目初期就建立固定的库目录结构和编译脚本,避免每次仿真都重新排查环境问题。