2. DC启动环境与工作目录
Design Compiler 在启动时并不是“空手”进入交互界面的,它会按一套固定的顺序去读取初始化脚本,把工艺库、搜索路径、链接库、目标库等关键变量准备好。如果这一步没配对,后面无论写多漂亮的约束脚本,都会在 link、compile 阶段报出 “Cannot find the library” 或 “Unable to resolve reference” 之类的错误。因此理解 .synopsys_dc.setup 的加载顺序,是 DC 工程化的第一课。
一、.synopsys_dc.setup 的三级加载顺序
DC 启动时会依次查找三个位置的同名文件,后加载的会覆盖先加载的同名变量,形成“系统默认 → 用户偏好 → 项目定制”的叠加效果:
- 安装目录:
$SYNOPSYS/admin/setup/.synopsys_dc.setup,由 EDA 管理员维护,通常只放公司级默认值,普通工程师不应修改。 - 用户主目录:
$HOME/.synopsys_dc.setup,放个人习惯,例如默认编辑器、常用别名、个人 search_path 前缀。 - 当前工作目录:
./.synopsys_dc.setup,即启动dc_shell时所在的目录,放项目专属配置,优先级最高。
关键点在于:加载顺序是固定的,与文件是否存在无关。如果当前目录没有该文件,DC 不会报错,只是跳过。因此工程上推荐把项目配置放在工作目录,把个人偏好放在 $HOME,两者互不干扰。可以用 echo $HOME 和 pwd 确认这两个位置,再用 ls -la 检查文件是否真的存在、是否有读权限。
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> 查看库内单元、引脚、时序信息是否完整。
五、一个可复用的项目配置模板
把上述内容整理成工作目录下的 .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 指定。