2. DC启动环境与工作目录

Design Compiler 在启动时并不是“空手”进入交互界面的,它会按一套固定的顺序去读取初始化脚本,把工艺库、搜索路径、链接库、目标库等关键变量准备好。如果这一步没配对,后面无论写多漂亮的约束脚本,都会在 link、compile 阶段报出 “Cannot find the library” 或 “Unable to resolve reference” 之类的错误。因此理解 .synopsys_dc.setup 的加载顺序,是 DC 工程化的第一课。

一、.synopsys_dc.setup 的三级加载顺序

DC 启动时会依次查找三个位置的同名文件,后加载的会覆盖先加载的同名变量,形成“系统默认 → 用户偏好 → 项目定制”的叠加效果:

  1. 安装目录:$SYNOPSYS/admin/setup/.synopsys_dc.setup,由 EDA 管理员维护,通常只放公司级默认值,普通工程师不应修改。
  2. 用户主目录:$HOME/.synopsys_dc.setup,放个人习惯,例如默认编辑器、常用别名、个人 search_path 前缀。
  3. 当前工作目录:./.synopsys_dc.setup,即启动 dc_shell 时所在的目录,放项目专属配置,优先级最高。

关键点在于:加载顺序是固定的,与文件是否存在无关。如果当前目录没有该文件,DC 不会报错,只是跳过。因此工程上推荐把项目配置放在工作目录,把个人偏好放在 $HOME,两者互不干扰。可以用 echo $HOME 和 pwd 确认这两个位置,再用 ls -la 检查文件是否真的存在、是否有读权限。

若不确定某个变量最终来自哪个文件,可在 dc_shell 中用 printvar search_path、printvar link_library 查看生效值,再对照三个文件逐一排查。

二、search_path:让 DC 找得到文件

search_path 是一个目录列表,DC 在 read_verilog、read_db、link 等命令中遇到相对路径时,会按列表顺序逐个目录去查找。它不负责“选哪个库”,只负责“去哪里找”。典型写法:

set search_path [list . ./rtl ./libs ./libs/slow \
    /pdk/tsmc28/db /pdk/tsmc28/synopsys]

# 追加而不覆盖已有值
set search_path [concat $search_path ./extra_libs]

顺序很重要:DC 采用“先命中先使用”。如果两个目录下有同名 .db,排在前面的会被选中。因此建议把项目本地库放在前面,PDK 公共库放在后面,避免误用旧版本。路径中不要出现空格和中文,Windows 移植过来的脚本尤其要注意反斜杠问题,统一用正斜杠。

三、link_library 与 target_library 的分工

这两个变量最容易混淆,必须分清:

  • target_library:综合时真正用来“映射”的工艺库,即标准单元库,DC 会把 RTL 逻辑映射成其中的单元。通常只写一个或少数几个 .db。
  • link_library:链接阶段用来解析设计层次中所有引用的库,包括标准单元库、IO 库、存储器宏库、IP 库,以及用 * 表示“当前已加载的设计”。
set target_library [list /pdk/tsmc28/db/sc9_cln28lp_base_rvt_ss_0p81v_125c.db]

set link_library [list * \
    /pdk/tsmc28/db/sc9_cln28lp_base_rvt_ss_0p81v_125c.db \
    /pdk/tsmc28/db/sc9_cln28lp_base_rvt_ff_0p99v_m40c.db \
    /pdk/tsmc28/db/io_28lp_ss_0p81v_125c.db \
    /pdk/tsmc28/db/sram_2048x32_ss_0p81v_125c.db]

注意 * 必须放在 link_library 中,否则 DC 无法把当前设计自身作为可解析对象,层次化设计会报 “unresolved reference”。另外,target_library 中的库通常也应出现在 link_library 中,保证映射和链接使用同一套单元定义。

四、.db 与 .lib 的识别与映射

工艺库有两种常见形态:.lib 是可读的 Liberty 文本,.db 是 DC 内部使用的二进制格式。DC 综合时只认 .db,因此需要先用 Library Compiler 把 .lib 编译成 .db:

lc_shell> read_lib sc9_cln28lp_base_rvt_ss_0p81v_125c.lib
lc_shell> write_lib sc9_cln28lp_base_rvt_ss_0p81v_125c \
    -format db -output ./db/sc9_cln28lp_base_rvt_ss_0p81v_125c.db

编译完成后,用 read_db 或直接在 link_library 中引用该 .db 即可。判断库是否被正确识别,可在 dc_shell 中执行:

list_libs
# 输出示例:
# sc9_cln28lp_base_rvt_ss_0p81v_125c
# io_28lp_ss_0p81v_125c
# sram_2048x32_ss_0p81v_125c

如果 list_libs 里没有你期望的库,说明路径或文件名写错;如果库在列表里但 link 仍失败,多半是 link_library 缺少 * 或缺少某个宏库。此时可用 report_lib <lib_name> 查看库内单元、引脚、时序信息是否完整。

DC 启动环境加载与库映射关系 ① 安装目录 setup $SYNOPSYS/admin/setup ② 用户主目录 setup $HOME/.synopsys_dc.setup ③ 当前工作目录 setup ./.synopsys_dc.setup 覆盖 覆盖 关键变量 search_path 目录列表,按序查找 target_library 映射用标准单元库 link_library 含 * 与所有引用库 工艺库文件 .lib(Liberty 文本) 可读,需编译 .db(二进制) DC 直接读取 lc_shell 编译 验证与排障 printvar 查看变量生效值 list_libs 确认库已加载 report_lib 检查库内容完整性 常见错误:link 失败 → 检查 link_library 是否含 * 及宏库;映射失败 → 检查 target_library 路径

五、一个可复用的项目配置模板

把上述内容整理成工作目录下的 .synopsys_dc.setup,可直接作为项目起点:

# 项目根目录
set PRJ_ROOT [pwd]

# 搜索路径:本地优先,PDK 在后
set search_path [list . $PRJ_ROOT/rtl $PRJ_ROOT/libs \
    /pdk/tsmc28/db]

# 目标库:仅标准单元
set target_library [list sc9_cln28lp_base_rvt_ss_0p81v_125c.db]

# 链接库:* + 标准单元 + IO + SRAM
set link_library [list * \
    sc9_cln28lp_base_rvt_ss_0p81v_125c.db \
    io_28lp_ss_0p81v_125c.db \
    sram_2048x32_ss_0p81v_125c.db]

# 可选:符号库、综合库
set symbol_library [list generic.sdb]
set synthetic_library [list dw_foundation.sldb]

启动后建议按顺序执行三条检查:printvar search_path 确认路径顺序,list_libs 确认库已加载,read_verilog 读入一个最小模块后执行 link,观察是否出现 unresolved reference。若 link 通过,说明启动环境与库映射已经就绪,可以进入约束编写阶段。

不要把 target_library 写成多个工艺角库的集合。DC 只会用其中一个进行映射,多写容易造成单元来源混乱。多工艺角应通过 link_library 提供,并在时序分析时用 set_operating_conditions 指定。