跳转至

SAED32 PDK 装载与验证 —— 变更 SOP

  • 主题:把 Synopsys 大学计划 SAED32(32/28nm)EDK 装载进集群 NFS,并纳入 module 体系
  • 执行日期:2026-09-29
  • 交付物目录:synopsys_pdk_saed32_20260929/(本文档位于 docs/)
  • 实现体:main.py / deployer.py(配套 utils/ 与 artifacts/)

1. 背景

集群已有 Synopsys 2018 批次工具(VCS/Verdi/DC/PT/ICC2/Formality/StarRC/HSPICE 等, 见项目根 docs/HANDOFF.md)与在线 license 服务,但没有任何可用于数字全流程的工艺库: /pdk 下仅有 FreePDK15/FreePDK45/ncsu-cdk 等学术工艺,无法支撑综合、时序、仿真、 物理实现的真实跑通。

SAED32_EDK(19G,8 个库:stdcell rvt/lvt/hvt、sram、sram_lp、io_std、io_sp、pll) 此前放在操作机工程目录 /home/rain/Documents/eda_tools_ins/Synopsys/SAED32_EDK, 尚未进入共享存储,七台节点看不到、也无法通过 module 引用。

触发条件:需要一套七台节点一致可用、可被 module 引用、且经工具实测跑通的工艺库。

2. 目标

变更完成后应达到以下可验证状态:

  1. /data/nfs/pdk/SAED32_EDK 存在,属主 root:root,目录 0755 / 文件 0644,内容与源树一致(17742 文件 / 9603 目录 / 19G)。
  2. /data/nfs/modulefiles/pdk/saed32/1.0.lua 存在,module load pdk && module load saed32 后得到 PDK=saed32、PDK_ROOT=/pdk、SAED32_PATH=/pdk/SAED32_EDK。
  3. 七台节点(31.28 + 六台 work)无需任何变更即可读到该库(经既有 /pdk ro 挂载)。
  4. 工具级实测通过:DC 综合、PT 时序、VCS 仿真、ICC2 读库四件套在 31.28 上跑通。
  5. 重复执行装载 deploy 命令零变更、全跳过(幂等)。

3. 前置条件

以下每一条都已落为可执行检查(precheck 子命令,作为 deploy/verify 的门禁第一步)。

# 条件 检查方式 级别
1 操作机为 NFS 服务端(192.168.31.249),/data 可用空间 ≥ 25G df -PB1 /data(按字节解析) BLOCK
2 /data/nfs/pdk 存在且已写入 /etc/exports test -d + grep -E '^/data/nfs/pdk[[:space:]]' /etc/exports BLOCK
3 操作机有 rsync rsync --version BLOCK
4 源树存在且非空 test -d + find -type f -print -quit BLOCK
5 当前身份为 root,或免密 sudo -n 可用 sudo -n true BLOCK
6 七台节点 SSH 免密可达、身份 root、Rocky 9.x 逐台 hostname / id -u / cat /etc/os-release BLOCK
7 七台已挂载 /pdk 与 /opt/modulefiles mountpoint -q BLOCK
8 31.28 已挂载 /tools mountpoint -q /tools BLOCK
9 license 端口可达(工具验证需要) /dev/tcp/192.168.31.29/2700 WARN
10 调度器上有作业的节点不动 Slurm/LSF 查询 BLOCK

预检查实测(2026-09-29 01:44):BLOCK 0 项 / WARN 0 项 / INFO 58 项。

4. 影响范围

  • 变更主机 1(数据):操作机 192.168.31.249(NFS 服务端)——写入 /data/nfs/pdk/SAED32_EDK 与 /data/nfs/modulefiles/pdk/saed32/1.0.lua。
  • 变更主机 2(系统包):192.168.31.28(工具级验证节点)——幂等安装 make、gcc(VCS 编译所需;实测其原本缺失)。只作用于 nodes.tools 组。
  • 验证主机:7 台 —— 192.168.31.28(工具级验证)+ .18/.19/.20/.25/.26/.27(库可见性抽查)。六台计算节点不做任何变更(/pdk 为 ro 挂载,新增目录对其立即可见)。
  • 是否停服:否。不改服务、不改 fstab/exports、不重启任何单元。
  • 窗口期:无特定要求。落盘为纯新增,不覆盖既有 PDK;/data 为本地盘,写 19G 期间不影响 NFS 上其他导出的正常读写(实测写速约 117 MB/s,全程约 3 分钟)。
  • 在跑作业:本次不触碰计算节点配置,调度器作业不受影响;工具级验证在 31.28(交互节点)执行,占用少量 CPU。
  • 磁盘增量:/data 由 578G 增至约 597G(+19G),剩余约 1.2T。

5. 分步操作

实现体:main.py(子命令 precheck / deploy / drift / verify)。 下列命令与实现体等价,供阅读、复核与手工复现;幂等与错误处理由实现体保证,不在代码块里展开。

步骤 1:门禁预检查(只读)

在做任何变更前证明环境与配置合格。检查项覆盖第 3 章全部前置条件, 并输出 reports/precheck-<时间戳>.md。全部只读(mountpoint / df / grep / SSH 探测)。

cd synopsys_pdk_saed32_20260929
.venv/bin/python main.py --config config/pdk.yaml precheck

预期:结论:BLOCK 0 项,退出码 0。有 BLOCK 则终止,不进入后续步骤(--dry-run 下降级为告警)。

步骤 2:预演(零改动)

.venv/bin/python main.py --config config/pdk.yaml --dry-run deploy

预期:输出待变更项清单(首次为 sync_tree + write_modulefile),不产生任何落盘; 清单落盘为 reports/plan-<时间戳>.yaml。核对该清单与实际预期是否一致。

步骤 3:数据落盘(高危:写入 19G + 整树改属主)

做什么:把源树同步到 NFS 导出目录,并统一属主与权限。 为什么这么写:

  • --no-owner --no-group 让 rsync 不比对属主:源文件属 rain:rain,目标要求 root:root, 若让 rsync 接管属主会在每次预演时判定"仍有差异",幂等判据永远不收敛;属主改由 chown -R 单独负责。
  • --chmod=D755,F644 把权限差异一并收进 rsync 判据,避免"内容一致但权限漂移"漏检。
  • 目标目录是 NFS 导出根的子目录,属 root,故整体经 sudo -n 提权执行;不使用 sudo 交互提示 (无 tty 时会挂住),提权可用性已在步骤 1 校验。
# 高危:新增 19G 数据并整树改属主(仅作用于 <dest_dir>,不使用通配删除)
sudo -n mkdir -p /data/nfs/pdk/SAED32_EDK
sudo -n rsync -rlptD --no-owner --no-group --chmod=D755,F644 \
  /home/rain/Documents/eda_tools_ins/Synopsys/SAED32_EDK/ \
  /data/nfs/pdk/SAED32_EDK/
sudo -n chown -R root:root /data/nfs/pdk/SAED32_EDK

预期:rsync 结束无报错;du -sh 显示 19G,find -type f | wc -l 为 17742。 失败判断:空间不足或中断 → 目标可能为半份数据;直接重跑步骤 3 即可(rsync 增量补齐), 无需先删除;若源树本身异常 → 见第 7 章。

步骤 4:写入 modulefile(高危:覆盖既有文件前自动备份)

做什么:把渲染后的 modulefile 落到 module 树,使七台节点可 module load。

坑(本次实测踩到,务必注意):

  1. modulefile 内不得再声明 family("eda_pdk")。家族标识由家族入口 Core/pdk.lua 声明; 若实体 modulefile 重复声明同族,Lmod 会判定家族冲突并自动卸载 pdk 入口, 连带撤销 MODULEPATH 与已设变量——表现为 module load saed32 之后 SAED32_PATH 为空。 既有 pdk/sky130 亦不声明 family,本工程保持一致。
  2. 模块名是 saed32,不是 pdk/saed32。Core/pdk.lua 会把 /opt/modulefiles/pdk 追加进 MODULEPATH,此后模块名即相对该路径;正确加载序列是 module load pdk && module load saed32。
  3. 目标属 root,须提权写入。实现体先在工程 logs/ 下生成暂存文件(普通用户可写), 再 install -D 提权安装到目标同目录的临时名,最后 mv -f 原子替换—— 避免 module load 读到半写文件。
  4. Lmod 目录缓存可能滞后(共享文件系统上常见)。若加载时报 unknown, 先试 module --ignore_cache avail;仍不可见则需清理客户端缓存或重登。
# 高危:覆盖前先备份(实现体自动完成并登记 backup/README.md)
sudo -n install -D -m 0644 -o root -g root \
  <渲染后的 modulefile 暂存文件> \
  /data/nfs/modulefiles/pdk/saed32/.1.0.lua.tmp
sudo -n mv -f /data/nfs/modulefiles/pdk/saed32/.1.0.lua.tmp \
  /data/nfs/modulefiles/pdk/saed32/1.0.lua

预期:/data/nfs/modulefiles/pdk/saed32/1.0.lua 属主 root:root、权限 0644。 失败判断:Permission denied 说明未走提权 → 检查 sudo -n true 是否可用。

步骤 5:工具验证节点补齐系统包

做什么:在工具级验证节点(nodes.tools)幂等安装 make、gcc。 为什么:VCS 编译末期需用 make + 编译器构建 rmapats.so,实测该节点缺这两个包, 报 Failed to make rmapats.so。这是工具运行依赖,与 PDK 数据无关,但缺它则 VCS 用例无法验证。

坑:不同节点软件源配置不一致(31.28 为阿里云源,六台仍为国外官方 mirrorlist)。 实测六台 dnf install 卡在 Downloading Packages 十余分钟无进展——因此本步只作用于 工具验证节点,六台留作待办(见附录 B 第 2 条)。

# 幂等:已装即跳过(rpm -q 探测);加超时与重试避免镜像挂着不动
ssh root@192.168.31.28 'rpm -q make gcc || dnf --setopt=timeout=60 --setopt=retries=3 \
  --setopt=minrate=1000 install -y make gcc'

预期:rpm -q make gcc 输出两个版本号。失败判断:仓库不可达 → 检查该节点软件源。

步骤 6:一次执行完成 3+4+5

.venv/bin/python main.py --config config/pdk.yaml deploy

预期:状态: success,随后自动跑第 6 章验证;退出码 0。 再次执行应输出 状态一致,无需变更,跳过备份与执行(状态: skipped,退出码 0)——这就是幂等验收。

6. 验证

6.1 变更完整性(本机 NFS 侧)

# 与源树逐项比对:输出为空即完全一致
.venv/bin/python main.py --config config/pdk.yaml drift

预期:## 无漂移:本机 NFS 侧与期望态一致,退出码 0。

# 属主与权限抽样核对(应输出 0 与 0)
find /data/nfs/pdk/SAED32_EDK \( ! -user root -o ! -group root \) | wc -l
find /data/nfs/pdk/SAED32_EDK \( -type d ! -perm 0755 -o -type f ! -perm 0644 \) | wc -l

6.2 七台节点库可见性

# 任取一台(或逐台执行)
ssh root@192.168.31.18 'bash -lc "
  module load pdk && module load saed32
  echo SAED32_PATH=\$SAED32_PATH
  ls \$SAED32_PATH/lib/stdcell_rvt/db_ccs/saed32rvt_tt0p85v25c.db"'

预期:打印 SAED32_PATH=/pdk/SAED32_EDK 且文件存在。实测七台全部通过。

6.3 工具级验证(四件套 + 抽查)

.venv/bin/python main.py --config config/pdk.yaml verify

若需手工复现单个工具(以 DC 为例):

ssh root@192.168.31.28 'bash -lc "
  module load synopsys && module load eda2018/1.0 && module load pdk && module load saed32
  cd /tmp/pdk_saed32_verify/dc_synth
  dc_shell -f synth.tcl"'

预期:各用例输出 PDK_VERIFY_OK。结果报告落盘 reports/tools-verify-<时间戳>.md, 各用例末段输出留档于 reports/verify-logs/。

实测结果(2026-09-29,报告见 reports/tools-verify-<时间戳>.md):

用例 工具 结果
dc_synth DC 综合(读 saed32rvt_tt0p85v25c.db,出网表) ✅ 通过
pt_timing PT 时序(读 .db + 读 DC 综合网表报时序) ✅ 通过
vcs_sim VCS 仿真(编译 saed32nm.v + 最小激励) ✅ 通过(见下:依赖 vcs-el7)
icc2_lib ICC2 物理(.tf 建库 + LEF 参考库) ✅ 通过
libs_verify 六台库可见性抽查 ✅ 全部通过

VCS 用例的前置:Rocky 9 上 VCS 编译需加载独立模块 vcs-el7 (el7 binutils + pthread_yield shim)。该问题与 PDK 无关,已单独解决, 详见主题 vcs_el7_binutils_20260929/docs/SOP.md。加载序列: module load synopsys && module load eda2018/1.0 && module load pdk && module load saed32 && module load vcs-el7

6.4 本次实测结论

  • DC:以 saed32rvt_tt0p85v25c.db 为 target/link library,read_verilog → link → compile 跑通,映射出层次单元并写出网表 pdktop_syn.v。
  • PT:read_db 读入同一 .db(get_lib_cells 可枚举单元),并读入 DC 网表完成时序分析。
  • VCS:编译 SAED32 的 348 个标准单元模型并跑通最小激励,输出 PDK_VERIFY_OK (仿真打印 AND2X1_RVT=1 OR2X1_RVT=1 INVX1_RVT=0)。
  • ICC2:以 tech/milkyway/saed32nm_1p9m_mw.tf 建库成功,标准单元以 LEF (lib/stdcell_rvt/lef/saed32nm_rvt_1p9m.lef)作为参考库读入并枚举成功。

    注:Milkyway 参考库路线不可用——ICC2 转换 Milkyway 需老 ICC 的 icc_shell (报 LIB-090)。IC Compiler 介质已上传(synopsys2018/ic_compiler_vO-2018.06-SP1), 待安装后可切换该路线。

  • 库可见性:七台(31.28 + 六台)module load pdk && module load saed32 后 关键文件 test -r 全部通过。

7. 回滚

备份位置

  • modulefile:覆盖前自动备份至 backup/data/nfs/modulefiles/pdk/saed32/1.0.lua.bak.<时间戳>,并登记在 backup/README.md。
  • 数据树:不做复制式备份——唯一来源是工程目录下的 SAED32_EDK/,可随时重新落盘。19G 复制两份无必要。

回滚步骤

# 1) 恢复 modulefile(幂等;无备份且目标不存在时视为无需回滚)
sudo -n .venv/bin/python main.py --config config/pdk.yaml --rollback

# 2) 删除数据树(不可逆,需显式 --force 确认;实现体先做安全判定:
#    必须位于 /data/nfs/pdk 之下、不等于导出根、目录名含 pdk.name)
sudo -n .venv/bin/python main.py --config config/pdk.yaml --rollback --force

手工等价命令(删除类操作路径写全,不用通配):

sudo -n rm -rf --one-file-system /data/nfs/pdk/SAED32_EDK

--one-file-system 可防止误删跨文件系统内容;路径已由实现体安全判定,不安全时拒绝执行。

回滚后验证

test -d /data/nfs/pdk/SAED32_EDK && echo 仍存在 || echo 已删除
ssh root@192.168.31.18 'bash -lc "module load pdk && module load saed32"'   # 预期报错(模块已随文件移除)

8. 风险说明

风险 影响 缓解
/data 空间不足 落盘中断,留下半份数据 门禁校验可用空间 ≥ 25G(实测 1.16T 可用);中断后直接重跑,rsync 增量补齐
误删/误写非目标路径 破坏其他 PDK 删除与属主修正前由实机事实判定:必须位于导出的 pdk 根之下、不等于该根、末段含 PDK 名;不满足即拒绝执行;删除用 --one-file-system
modulefile 家族冲突 加载后环境变量被撤销 实测定位并已规避(不声明 family);verify 用例包含加载后变量断言
Lmod 缓存滞后 module load 报 unknown 文档给出 --ignore_cache 规避;客户端重登或清缓存可彻底刷新
工具级验证失败(老库 + 新工具兼容性) 库可见但工具用不起来 结果按用例逐项记录;失败项写入交付说明与 HANDOFF 待办,不影响"库已可用"这一结论
落盘期间 NFS 客户端读到半份数据 工具读库报错 客户端 /pdk 为 ro 且本次为纯新增目录(SAED32_EDK 此前不存在),客户端不会读到中间态

附录

A. 交付物清单

路径 说明
main.py / deployer.py 入口与编排(继承共享库 BaseModule)
utils/config_validate.py 配置合法性校验(五类)
utils/pdk_state.py 领域三态探测(rsync 差异 / 属主权限 / modulefile 摘要 / 导出条目 / 空间)
utils/precheck.py 领域预检查(继承共享库 PreCheckBase)
utils/tool_verify.py 工具级验证执行器与报告渲染
config/pdk.yaml 站点配置(唯一真源)
artifacts/modulefiles/saed32-1.0.lua.tpl modulefile 模板(单一源,渲染后写入 NFS)
artifacts/{dc,pt,vcs,icc2}/ 工具级验证用例
backup/ 备份与台账(README.md 为登记表)
reports/ 预检查报告、变更清单、漂移报告、验证报告(19G 相关日志不落盘于仓库)

B. 后续收敛项(本次未做,单独提出)

  1. ~~VCS 编译失败~~ 已解决(2026-09-29):解法是 el7 binutils 兼容层 + 独立模块 vcs-el7,见主题 vcs_el7_binutils_20260929/docs/SOP.md;PDK 侧从无问题。
  2. 六台计算节点软件源:仍指向国外官方镜像(mirrorlist → nevacloud / krfoss 等), dnf install 实测卡在 Downloading 十余分钟无进展;31.28 已切阿里云源。 本次未改六台软件源(属基础设施变更,应由存储/节点部署工程统一处理), 故六台未安装 make/gcc——若要在六台上跑 VCS 仿真,需先统一换源再装包。
  3. 通用探测上移共享库:本工程 utils/pdk_state.py 中的挂载点探测、license 端口探测, 与 rocky9_eda_compat_20260928/utils/ 下的实现构成第二次实现,按共享库上移判据宜上移 (新增函数属非破坏性变更,但需回归全部挂载工程)。本次为控制变更面未做。
  4. pdk 家族纳入部署器声明:slurm_ins/config/slurm_deploy.yaml 的 module_env.families 目前只声明 sky130。本工程的 saed32 为手工维护(与 synopsys/eda2018/1.0.lua 同模式), 部署器复跑不会删除它(只补缺失、不清理额外文件),但也不受其管理。 若希望纳入声明式管理,需给该项补 NFS 路径模型(现 family 的 install_dir 为节点本地路径语义)。
  5. ICC2 的 Milkyway 路线:如需用 Milkyway 参考库(而非 LEF),需补装老 ICC 的 icc_shell 并设置 lib.configuration.icc_shell_exec。

来源:/home/rain/Documents/eda_tools_ins/Synopsys/synopsys_pdk_saed32_20260929/docs/SOP.md | 最后更新:2026-09-29 03:14(由 build/sync.py 同步,请勿在站点侧修改)