写在前面。我一直觉得,开源芯片设计这几年真正让人兴奋的,不是某个单点工具又多了一个功能,而是整条从前端到后端的链路终于能用手边的电脑跑通了。三年前我想在Linux笔记本上把一个RISC-V的小核做成GDS版图,翻遍资料发现要么用商业EDA,要么只能靠学校实验室的服务器。现在情况完全不同了,OpenROAD这套开源工具链把综合、布局、时钟树、布线、甚至DRC检查串成了一条相对完整的路径,配合SkyWater 130nm PDK,个人电脑上就能完成你的第一个SoC物理实现。
这篇文章我打算完全站在实操角度写。我默认你懂一点Verilog和数字电路基础,但对后端流程可能比较陌生。我会从一个最小SoC示例出发,先讲工具链怎么选型、怎么装,再逐步拆解综合、物理实现、时钟树和布线每一步要做什么、配置文件怎么填,最后把我自己踩过的坑和最常见的报错整理成表格。内容会比较长,因为我尽量把“为什么这么做”也写清楚,而不只是丢给你一串命令。
1. 为什么选OpenROAD:开源EDA工具链的完整度已经够用了
1.1 OpenROAD在开源芯片流程中的位置
先给整个流程定个位。一个数字芯片从RTL到能送去流片的GDSII,中间要经过逻辑综合、DFT插入、floorplan、布局、时钟树综合、布线、寄生参数提取、时序签核、物理验证等一大堆步骤。商业EDA里这些功能分散在Synopsys、Cadence、Siemens EDA的工具中,而开源世界里,目前最接近“一站式”的,就是OpenROAD。
OpenROAD本身并不是从零发明的一个软件,它把很多原本独立的研究项目吸收整合,形成一个统一的命令行工具。它做的事情覆盖了从网表进来之后的大部分数字后端步骤。至于逻辑综合这一步,通常还是要靠Yosys来完成,Yosys和OpenROAD是配合关系,不是竞争关系。流片前的物理验证,比如DRC和LVS,又需要KLayout、Magic、Netgen这些工具来兜底。所以你真正要搭建的,是一条链,OpenROAD是这条链的中后段主力。
我个人的理解是:OpenROAD更像是那个“把流程串起来的人”。它自己实现了全局布局、详细布局、时钟树综合、全局布线、详细布线,还集成了很多时序优化和拥塞修复的逻辑。它的核心价值在于,当你跑完Yosys拿到门级网表后,后面那一整套让人头皮发麻的物理实现工作,可以在一个工具里按顺序执行完,并在最后输出DEF和GDS文件。这在五年前的开源世界里是完全不敢想的。
1.2 一套完整的开源工具链由哪些角色组成
先列一个工具角色表,这样你心里有数,不至于装到一半搞不清哪个软件是干嘛的。
| 流程环节 | 开源工具 | 主要职责 |
|---|---|---|
| RTL仿真 | Icarus Verilog / Verilator | 功能验证,跑testbench |
| 逻辑综合 | Yosys | RTL到门级网表,逻辑优化和映射 |
| 物理实现 | OpenROAD | floorplan、布局、CTS、布线、时序修复 |
| 版图查看/编辑 | KLayout / Magic | 查看GDS、手工修补、DRC运行 |
| 物理验证 | KLayout / Magic + Netgen | DRC检查、LVS比对 |
| PDK | SkyWater SKY130 / Google GF180 | 工艺库文件、规则文件、器件模型 |
值得一提的是,OpenROAD官方维护了一个叫openroad-flow-scripts的仓库,把Yosys、OpenROAD、KLayout以及多个开放PDK集成到了一起,理论上你拉下来配置好环境变量,就能一键跑一个从RTL到GDS的完整流程。这个脚本仓库特别适合第一次接触开源后端的人,它的设计方式也值得学习,整个流程拆分得很清楚,每一步都有独立的脚本目录。
但我要说的是,如果只想“能跑通”,直接套ORFS的默认流程就够了;如果想真正理解后端每一步在干什么、以后想换工艺或者改策略,还是建议自己把脚本像搭积木一样拼一遍。这篇文章接下来的内容,就是我按照“手工拼流程”的思路来写的,我会把每个关键步骤的配置和参数都摊开讲。
1.3 这套工具链适合谁,不适合谁
很多人问我,开源工具链能做商业级芯片吗?我的判断是,在特定场景下接近可用,但不是所有场景都适合。
适合的人群很明确:学生、做体系结构和RISC-V研究的科研人员、想验证自己写的IP能不能被物理实现的小团队、还有预算不够但需要完整走一遍后端流程的初创公司。对这些人来说,OpenROAD能给你提供从RTL到GDS的完整体验,虽然结果不一定像商业工具调得那么极致,但流程能闭环,数据能看,这本身就非常值钱。
不适合的场景也很明确:动辄上亿门、需要多时钟域复杂约束、高频CPU核心、对功耗和面积极其敏感的先进工艺项目。不是说开源工具完全做不了,而是你需要花大量时间去调优,最终可能仍然达不到商业工具几十年的经验积累。我建议这类场景继续选择商业EDA,至少目前还是这样。
2. 搭建OpenROAD开发环境:安装方式选择与版本坑位提醒
2.1 源码编译还是直接下载二进制发布包
OpenROAD的安装,历来是新手的第一道坎。它更新很频繁,master分支经常有变动,不同版本之间的命令兼容性偶尔会有小问题。所以我不推荐新手直接拉master编译,最好优先选择带版本号的发布包,或者直接用官方的预编译二进制。
如果你用的是Ubuntu 20.04或22.04,而且机器是x86_64,可以直接去OpenROAD项目的GitHub Releases页面下载对应版本的预编译包,通常是一个压缩包,解压后设置一下环境变量就能用。这是最省力的路径。
要是你非要自己从源码编译,我建议先装好依赖。以Ubuntu 22.04为例,基本的编译工具链和库如下:
sudo apt update sudo apt install -y build-essential cmake bison flex swig \ libboost-all-dev libeigen3-dev libgflags-dev libgoogle-glog-dev \ libspdlog-dev libtcl8.6-dev tcllib libreadline-dev \ libssl-dev libtool autoconf automake pkg-config \ libgmp-dev libmpfr-dev然后克隆仓库,切到稳定release版本再编译:
git clone --recursive https://github.com/The-OpenROAD-Project/OpenROAD.git cd OpenROAD git checkout <某个release tag> mkdir build && cd build cmake .. make -j$(nproc)实际上编译时间取决于你的机器,我自己在8核笔记本上从头编过,大概需要半小时到一小时,过程比较顺,但前提是依赖版本别冲突。尤其是Boost和Eigen,如果系统里版本过新,个别组件编译会报错。所以我一直觉得,对新手来说“能用预编译就别自己编译”,省下来的时间多跑几个demo更有价值。
2.2 装完怎么确认工具链可用
安装完成后,先检查openroad命令是否能正常执行:
openroad -version如果你看到类似OpenROAD v2.0-xxxx-gxxxxxxx的输出,说明基本可用了。接着跑一个最迷你的验证,直接用命令行读取自带的测试设计,确认整个Tcl解析引擎没问题:
openroad -no_init -exit进入交互模式后可以输入help,看一堆commands列表能列出来,就说明安装没问题。另外一个值得做的事,是单独验证OpenROAD和Yosys能不能正常联动。我会在下一节用真实的小例子来做这件事。
2.3 PDK准备:以SkyWater SKY130为例
跑设计之前,必须先把工艺库准备好。这里我推荐用SkyWater SKY130,这是目前开源生态里最成熟的PDK,包含标准单元库、IO库、各种模拟器件,而且有完整的KLayout DRC deck。另一个选择是Google和GlobalFoundries合作的GF180,但SKY130的生态和文档更全,适合第一次跑后端。
从SkyWater的官方仓库获取:
git clone https://github.com/google/skywater-pdk.git cd skywater-pdk git submodule update --init libraries/sky130_fd_sc_hd/latest这一步会下载SKY130标准单元库。真正在OpenROAD里用得上的文件主要是这几个:
sky130_fd_sc_hd.lef:标准单元的LEF抽象,包含每个cell的尺寸、pin位置、障碍信息,这是布局布线必须的。sky130_fd_sc_hd__tt_025C_1v80.lib:典型工艺角、25摄氏度、1.8V电源下的标准单元时序库。sky130_fd_sc_hd__ss_100C_1v60.lib:慢工艺角、100摄氏度、1.6V下的时序库,用于setup分析。sky130_fd_sc_hd__ff_100C_1v95.lib:快工艺角、100摄氏度、1.95V下的时序库,用于hold分析。
这里要强调一下,LEF文件和Liberty库文件里的标准单元名称必须完全匹配,如果你用了不同版本的标准单元库,OpenROAD读入link_design阶段经常会报warning或者单元找不到,这类问题八成是库版本不匹配造成的。
除了标准单元的LEF,SKY130还需要tech LEF文件。这个文件通常叫sky130_fd_sc_hd__tech.lef,它定义了布线层、通孔、间距规则、最小线宽等信息,没有它OpenROAD根本没法做绕线。
3. 设计输入:从RTL到门级网表的综合流程
3.1 一个最小SoC示例长什么样
为了把整个流程讲具体,我定义了一个小芯片,名字就叫myso_top。它包含一个简化的RISC-V CPU核、一个UART发送模块、一个SPI主控、一块SRAM控制器。这只是个教学性质的设计,重点是让大家理解流程,而不是设计本身多复杂。
顶层模块的接口我故意不做太多约束,就留了时钟、复位、UART的tx/rx、SPI的四个信号、以及一组内存总线。实际综合时,IO pad我先不加,直接用core的顶层端口来接,这样在floorplan阶段手动摆pin会更容易理解。
我把RTL文件按模块拆开:
rtl/myso_top.vrtl/cpu_core.vrtl/uart_tx.vrtl/spi_master.vrtl/sram_ctrl.v
RTL仿真我建议你至少先跑一遍,确认功能没问题再进综合。后端的痛苦之处在于,功能验证都没过的设计,跑完物理实现回来调试,你会同时面对功能问题和时序问题,排查难度成倍上升。别问我怎么知道的,都是教训。
3.2 用Yosys完成逻辑综合的流程
Yosys是开源世界里最主流的逻辑综合工具,它的功能非常强大,这里我只讲和标准单元映射相关的用法。
我先给出一份可以直接用的Yosys脚本,保存为run_yosys.ys:
read_verilog -sv rtl/myso_top.v rtl/cpu_core.v rtl/uart_tx.v rtl/spi_master.v rtl/sram_ctrl.v read_liberty -lib ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib synth -top myso_top dfflibmap -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib abc -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib clean write_verilog ./out/myso_top_netlist.v write_json ./out/myso_top_netlist.json stat解释一下这几条命令的逻辑。read_verilog是把RTL读进去,我加了-sv参数,因为很多RTL里用了SystemVerilog的语法。read_liberty把标准单元库的时序信息读进去,Yosys依靠它来做逻辑映射,知道哪些布尔逻辑可以映射到哪个单元。synth -top myso_top是执行默认的综合流程,包括编译、优化、技术映射前的逻辑整理。dfflibmap专门把设计中的触发器映射到标准单元库的DFF单元上。abc是Yosys调用ABC工具做逻辑优化和门级映射,这一步决定了综合质量。最后的stat会输出一个面积统计表,可以帮你粗略评估设计有多大。
我遇到很多新手在这步搞不清楚一个概念:synth其实已经包含了一套默认的映射流程,为什么还要单独调dfflibmap和abc?因为synth -top默认不知道你最终要用哪个工艺库,它只能做逻辑层面的综合。只有当你用read_liberty读入库、然后显式执行dfflibmap和abc之后,输出的网表才是真正基于SKY130标准单元的门级网表。缺了任意一步,你得到的可能是Yosys内部通用逻辑单元,OpenROAD拿到这种网表会直接报错。
执行方式很简单:
yosys -s run_yosys.ys跑完之后,out/myso_top_netlist.v就是我们要拿去给OpenROAD的门级网表。我建议你打开这个网表看一眼,感受一下RTL被映射成门级后的样子,对理解后端流程有帮助。
3.3 SDC时序约束文件的写法与陷阱
时序约束是整个流程最容易埋雷的地方。很多新手因为觉得后端工具会“自动约束”,所以在综合阶段随便写个时钟就往下冲,结果到布线完一看时序报告全是violation,根本不知道从哪里修起。
SDC文件的标准写法其实不复杂,但每一行都有讲究。我这里给出一份适用于myso_top的约束文件,保存为myso_top.sdc:
create_clock -name clk -period 20 [get_ports clk] set_clock_uncertainty 1.5 [get_clocks clk] set_input_delay 2 -clock clk [get_ports data_in] set_input_delay 2 -clock clk [get_ports cs_n] set_input_delay 2 -clock clk [get_ports sdi] set_output_delay 2 -clock clk [get_ports tx] set_output_delay 2 -clock clk [get_ports sdo] set_clock_transition 0.5 [get_clocks clk]同样是20ns的时钟周期,综合阶段Yosys只关心逻辑映射和面积,但物理实现阶段,20ns会决定你所有寄存器的setup和hold能不能满足。SKY130标准单元在1.8V典型角下,20ns的周期对这个小设计来说是相当宽松的,所以跑通比较容易。如果你做的是高频设计,比如3~5ns周期,那后面布局布线阶段你会花大量时间做时序修复。
有几个SDC细节我想多说两句。set_clock_uncertainty用于模拟时钟抖动和偏斜的影响,这在一开始就加上,可以让工具在布局和布线时留出余量。set_input_delay和set_output_delay是从外部接口视角约束数据到达和离开的时间,如果没有这两项,工具默认外部信号无延迟,会导致端口的时序计算过于乐观。另一种常见做法是在sdc里加set_false_path,但除非你非常确定这条路径不需要时序分析,否则不要乱加false_path,否则容易把关键路径“假”掉,导致流片回来的芯片实际性能远低于预期。
综合完的网表和约束文件都准备好之后,就可以进入OpenROAD的主场了。
4. 物理实现核心:读入数据、floorplan、布局、时钟树、布线
4.1 读入PDK数据与网表,搭建初始设计环境
打开OpenROAD,整个流程用一个Tcl脚本串联。我建议把脚本拆成几个文件,比如openroad_setup.tcl、openroad_place.tcl、openroad_cts_route.tcl,这样阶段性问题能快速定位。
先看openroad_setup.tcl:
# 设置库文件路径变量 set LIB_TYP "./lib/sky130_fd_sc_hd__tt_025C_1v80.lib" set LIB_SS "./lib/sky130_fd_sc_hd__ss_100C_1v60.lib" set LIB_FF "./lib/sky130_fd_sc_hd__ff_100C_1v95.lib" set LEF_TECH "./pdk/sky130_fd_sc_hd__tech.lef" set LEF_CELL "./pdk/sky130_fd_sc_hd.lef" set NETLIST "./out/myso_top_netlist.v" set SDC_FILE "./constraints/myso_top.sdc" # 读入时序库 read_liberty -min $LIB_FF read_liberty -max $LIB_SS read_liberty $LIB_TYP # 读入LEF read_lef $LEF_TECH read_lef $LEF_CELL # 读入门级网表并link设计 read_verilog $NETLIST link_design myso_top # 读入时序约束 read_sdc $SDC_FILE这里有个值得注意的点:read_liberty我读了三个库,并用-min和-max分别指定了快角库和慢角库。在OpenROAD里,时序分析是双角的,max路径(setup)一般用慢角库,min路径(hold)一般用快角库。典型角库则作为默认参考。如果你只读了一个库,OpenROAD也能跑,但时序分析会少一个维度,对后续修复不利。
link_design这步很关键。OpenROAD会根据你指定的顶层模块名,把网表里的所有实例与标准单元库中的单元对应起来。如果之前read_liberty漏了某些单元,或者LEF文件不全,这步就会报错或者警告,一定要全部消干净再进入下一步。
4.2 floorplan设计:决定芯片尺寸与IO摆放
floorplan是整个物理实现中最有“设计感”的一步。你要决定芯片的die面积多大、core区域留多少、IO pad怎么摆、电源网络怎么规划。对小设计来说,简单粗暴的做法是直接给一个正方的die,根据网表的规模估计core利用率。
OpenROAD的floorplan脚本如下:
# 单位是微米 initialize_floorplan -die_area {0 0 600 600} \ -core_area {60 60 540 540} \ -site unithddie_area是芯片的物理边界,core_area是标准单元可以摆放的区域,中间留出的边缘空间要给IO、电源环和布线资源。-site unithd指定标准单元行的高度类型,SKY130高密度库的行site名称就是unithd。
我工作里习惯先跑一次粗略的global_placement,然后用report_utilization看看利用率是多少。如果利用率太高,比如超过70%,我建议加大die尺寸,否则后面拥塞问题会让你头疼。对于第一次跑通流程,把core利用率控制在50%~60%是比较舒适的范围。
IO pin的摆放取决于你最终怎么封装。如果是简单的测试芯片,用探针台或者焊线封装,IO pad最好均匀分布在四个边。OpenROAD里可以用edit_pad_edges或者手动指定pin位置,但更省事的方式是先用默认分布,让工具自动把端口放在芯片边缘。
4.3 布局阶段:全局布局与详细布局,密度参数别乱调
布局分两步,先是全局布局,再做详细布局。全局布局的目标是把所有标准单元摊到整个core区域,同时让线长尽量短、拥塞尽量低。OpenROAD的命令很简单:
global_placement -density 0.65-density 0.65代表期望的布单元面积密度,即标准单元总面积占核心区域面积的65%。密度越高,芯片越小,但布线拥塞风险越大。很多新手追求小面积,一上来就设0.9,跑完detailed_route发现到处都是DRC short,其实这是密度设置过高导致的典型结果。
全局布局完成后,紧接着跑详细布局:
detailed_placement详细布局会检查标准单元的legalize问题,也就是所有单元必须落在site网格上,不能重叠。多数时候OpenROAD能自动修好,但如果之前floorplan的core区域设置不合理,比如高度不是标准单元行的整数倍,这步就会报告错误。
布局结束后,我习惯先存一份DEF看一下单元分布。用KLayout打开DEF文件,可以直观看到是否有大片空白或者异常拥挤的区域。这一步的可视化检查,比看任何报告都更能建立你的空间感。
4.4 时钟树综合:让时钟同时到达每个触发器
时钟树综合(CTS)是后端流程里非常核心的一步。设计里寄存器数量少,布线资源充裕,CTS相对好做;但如果时钟网络很长、寄存器很多,时钟偏斜会成为时序收敛的大敌。
OpenROAD的CTS命令大致长这样:
clock_tree_synthesis \ -root_buf CLKBUFX3 \ -buf_list {CLKBUFX3 CLKBUFX6} \ -wire_unit 20-root_buf指定时钟树根节点使用的缓冲器单元,-buf_list是允许用来做时钟树中间节点的缓冲器列表,-wire_unit是估计的单位长度电阻电容值,这个参数可以从工艺库中提取,但大多数情况下给一个经验值20就行。
CTS跑完之后,OpenROAD会自动把生成的时钟树网表整合回设计中。这时候别急着布线,先跑一次时序优化:
repair_timingrepair_timing的作用是修setup和hold,工具会根据当前时序分析结果插入缓冲器、调整单元尺寸,尽可能把所有violation修干净。这一步的完成质量直接决定后面布线流程好不好收尾。
4.5 布线:全局布线与详细布线,DRC是最终裁判
布线是整个流程最费时间的一步,也最考验工具配置。OpenROAD的布线也拆成两步:
global_route全局布线负责规划每条线的大致走向,在网格上分配资源,它不生成真实的金属图形,但会评估拥塞。跑完这步后,一定要看日志里的拥塞报告。如果出现大量overflow,说明前面的布局或者密度设置有问题,这时候回头调比等详细布线失败再调要省得多。
确认拥塞可接受后,执行详细布线:
detailed_route详细布线会在真实工艺规则约束下,为每一条net生成实际的金属走线,并检查DRC。跑完后,OpenROAD会在日志里给出DRC违规数的统计。第一次跑通,有几条DRC违例是很正常的,比如short或者spacing,可以尝试用repair_antennas和一些修short的指令去修,但如果violation数量上百,基本就是设计或者配置层面的问题,别硬修,回头检查密度和布局才是正路。
布线完成后,输出最终结果:
write_def ./out/myso_top.def write_gds ./out/myso_top.gds write_verilog ./out/myso_top_netlist.apt.v report_checks -path_delay max -digits 4 report_checks -path_delay min -digits 4 report_powerwrite_gds是把你整个设计导出成GDS版图文件,这个文件就可以拿去做DRC/LVS或者直接送去流片。write_verilog导出的带时序修复后的网表,是带缓冲器插入的版本,用于LVS比对和后仿真。
5. 报告解读、问题排查与几条真实的调优心得
5.1 一版布局跑完先看哪几个报告
很多新手拿到OpenROAD日志,看到满屏输出根本不知道从哪看起。我的习惯是按固定顺序查三样东西。
首先是时序报告。运行report_checks后,重点看最差负裕量(WNS)和最差保持时间余量(THS)。WNS是负数,说明在你定义的20ns周期下,存在setup违例,需要知道违例路径在哪个模块、经过了多少逻辑级。在OpenROAD里可以用report_checks -path_delay max -endpoint_count 10看最差的前10条路径。
然后是拥塞报告。global_route和detailed_route日志中间有congestion相关统计,重点找overflow的net数量。如果overflow不为0,哪怕很小,都可能在后续DRC阶段转成short。
最后是DRC报告。detailed_route之后日志里会列出不同DRC类型的数量。最常见的两种是short和min spacing。如果数量在个位数,可以尝试让工具自动修;如果数量很大,比如几十上百,基本说明布局质量不行,工具硬修是修不完的。
5.2 完整的OpenROAD一键式运行脚本示例
为了让你能对照着跑,我把这个流程整理成一个可以直接执行的Shell脚本run_openroad.sh。你可以根据实际路径稍作修改:
#!/bin/bash set -e PDK_DIR=./pdk LIB_DIR=./lib CONST_DIR=./constraints OUT_DIR=./out mkdir -p $OUT_DIR openroad -no_init -exit <<EOF # 读入库文件和设计 read_liberty -min $LIB_DIR/sky130_fd_sc_hd__ff_100C_1v95.lib read_liberty -max $LIB_DIR/sky130_fd_sc_hd__ss_100C_1v60.lib read_liberty $LIB_DIR/sky130_fd_sc_hd__tt_025C_1v80.lib read_lef $PDK_DIR/sky130_fd_sc_hd__tech.lef read_lef $PDK_DIR/sky130_fd_sc_hd.lef read_verilog $OUT_DIR/myso_top_netlist.v link_design myso_top read_sdc $CONST_DIR/myso_top.sdc # floorplan initialize_floorplan -die_area {0 0 600 600} -core_area {60 60 540 540} -site unithd # 布局 global_placement -density 0.65 detailed_placement # 时钟树 clock_tree_synthesis -root_buf CLKBUFX3 -buf_list {CLKBUFX3 CLKBUFX6} -wire_unit 20 repair_timing # 布线 global_route detailed_route # 输出 write_def $OUT_DIR/myso_top.def write_gds $OUT_DIR/myso_top.gds write_verilog $OUT_DIR/myso_top_netlist.apt.v # 报告 report_checks -path_delay max -digits 4 report_checks -path_delay min -digits 4 report_power report_utilization EOF echo "OpenROAD flow completed successfully."从实际经验来看,这个流程跑完,输出文件的完整度已经足够让你去做物理验证了。如果你想在KLayout里直观看到最终版图,可以直接打开生成的GDS文件。第一次看到自己写的RTL变成了真实的版图,那个感觉还是挺奇妙的。
5.3 我踩过的三个坑,希望你能绕开
第一个坑是密度设置过高。我第一次用OpenROAD跑一个稍微复杂的RISC-V核,为了追求小面积把global_placement -density设成了0.85,结果detailed_route之后short成百上千,修了一下午没修完。后来把密度降到0.65,重新跑一遍,DRC干净利落就过了。这个教训告诉我,对第一版设计,面积永远不该是第一优先级,可收敛性和可调试性才是。
第二个坑是SDC约束写得太简单。我早期只写了create_clock,没有加set_input_delay和set_output_delay,结果所有接口路径在时序报告里看起来都很乐观,但实际到了板级联调的时候,发现芯片和外部设备的接口时序完全不对。后来我把接口约束补齐,重新综合一遍,多修了十几条路径,真正拿回板子上测才稳定。所以SDC真的会在物理实现阶段直接影响你的芯片能不能用。
第三个坑是忘记检查电源网络。OpenROAD官方流程里,initialize_floorplan之后通常要加电源环和电源条带,尤其是给标准单元供电的VDD和VSS网络。如果你直接跳过电源规划就做布局布线,工具可能默认所有单元都接在理想电源上,这样在逻辑上没问题,但流片回来后电源网络会出大问题。我建议至少在floorplan阶段用add_global_connection指令,把标准单元的VDD和VSS端口连到对应的电源Net上,然后再往下走。
5.4 常见报错与排查速查表
下面这张表,是我在实际调试中整理出来的,覆盖了新手最容易撞到的几类问题。如果你遇到类似报错,可以直接按这个思路排。
| 报错或现象 | 可能原因 | 排查方向 |
|---|---|---|
link_design报找不到单元 | 网表里的模块实例名与标准单元库名字不一致 | 检查read_liberty和read_lef是否读了同一套PDK文件 |
global_placement结束大量overflow | 密度设置过高 | 下调-density,增大die面积 |
detailed_route报大量short | 拥塞严重或电源网络缺失 | 回头检查全局布线的overflow,确认电源Net已连接 |
read_sdc报端口不存在 | SDC里约束的pin名和网表顶层端口名不一致 | 打开网表查顶层端口列表,修正SDC |
clock_tree_synthesis报找不到root buffer | 库内没有对应缓冲单元 | 换成库里真实存在的单元,比如CLKBUFX3 |
report_checks全是hold violation | 只读了慢角库做max分析,忘了读快角库 | 补齐read_liberty -min $LIB_FF |
| 输出GDS后KLayout打不开 | GDS版本或文件损坏 | 确认OpenROAD版本和KLayout版本,必要时重写GDS |
写在最后的个人体会
如果让我给第一次跑OpenROAD的人一句建议,我会说:别急着追求一个完全DRC clean、时序全过的终极版图,先把整个流程完整跑通一遍,哪怕中间有一堆违规,先看看每个步骤输出什么、报告长什么样、KLayout里打开版图是什么效果。因为后端流程的难点从来不是某个工具不会用,而是你脑子里没有“流程全貌”。当你完整跑通一次,再回头调密度、调约束、修时序,每一步都会有的放矢。这个项目我前前后后跑了三个版本,第一版充满各种violation,但那一次给我建立的全局认知,比后来任何一次调优都值钱。