nextpnr 布线卡死不动速查:跑几小时停在 placement/routing 怎么办
更新时间:2026-10-23。FAQ 速查页,属于 FPGA 工具报错排错系列。开源 FPGA 流程里最熬人的不是报错退出,而是 nextpnr-ice40 / nextpnr-ecp5 跑了几个小时、日志停在某个 iteration 不再滚动、CPU 单核 100% 却看不到任何推进迹象——不知道该等还是该杀。本篇分诊 nextpnr 布局布线阶段的卡死与超时。综合阶段(Yosys)就卡住的对照片见 Yosys 卡死/超时速查,商业工具侧同一类「跑几小时不出结果」的分诊口径见 Quartus 编译卡死速查。
本文要回答的问题
- nextpnr 日志停在
Router1 iteration N或 placement 某一步几小时,怎么分清是难解设计在收敛还是真挂死? - 利用率多少以上布线时间会指数膨胀,怎么快速看当前设计挤不挤?
- 时序约束(
--freq目标)定得过紧会怎样拖死 timing-driven 布线? - 为什么换个
--seed就过了,seed 到底改变了什么? - 机器内存不足、verbose 日志刷屏,分别会怎样伪装成「卡死」?
一、现象与报错原文
nextpnr 卡死现场通常没有报错,只有停住的日志和一颗跑满的核。以下三类形态最典型,设计名与路径均占位。
1. 日志停在布线迭代某一行不再滚动,CPU 单核 100%:
Info: Routing..
Info: Router1: iteration 45: 1873 nets left to route
Info: Router1: iteration 46: 1851 nets left to route
Info: Router1: iteration 47: 1849 nets left to route
<- 之后几小时没有下一行,CPU 一直 100%注意迭代行里 nets left to route 的数字:如果它每隔一段时间还在缓慢下降,说明 PathFinder 路由器在收敛,只是慢;如果几十分钟数字纹丝不动、或反而在涨,就是陷入了振荡,再等下去大概率也不会过。
2. 布局阶段反复打印 timing 信息,cost 不下降:timing-driven placer 为了压一条关键路径反复搬动单元,heap delta 趋近于零,日志满屏都是同一组路径的 slack 报告——约束定得比物理极限还紧时的典型表现。
3. 内存占用一路涨、系统开始 swap,整机变卡,nextpnr 的 RSS 逼近物理内存——它不是在布线,是在换页。
二、现象 → 区分点 → 处置速查表
| 现象 | 区分点 / 最常见原因 | 处置 |
|---|---|---|
| nets left 缓慢下降、CPU 100% | 利用率高,路由器在难解设计上正常收敛 | 看 routing 报告利用率;95% 以上考虑削规模或换更大封装 |
| nets left 几十分钟不动或回升 | 路由器振荡,当前 seed 落在不可布区 | Ctrl+C 换 --seed 重试,扫 5-10 个种子 |
| placer 满屏 timing 报告、slack 不收敛 | --freq 目标定得过高,timing-driven 无解重布 | 放宽频率目标或给假路径加约束,先求布通再追时序 |
| 卡死在 placement 早期、报 clock 相关 warning | 时钟资源冲突,placer 找不到合法位置 | 检查全局时钟网络分配与 PLL/专用时钟引脚使用 |
| RSS 逼近内存上限、磁盘狂转 | 内存不足 swap 抖动,越跑越慢 | 关其他进程、换大内存机器;ECP5 大 die 按 8GB+ 预算 |
| verbose 日志疯狂刷屏、终端/CI 卡 | --verbose/--debug 输出量拖慢整体 | 去掉 verbose 重定向到文件,日志量大时禁实时 tee |
| 同一设计同一命令时快时慢 | seed 初值敏感性 | seed sweep 制度化,不要死磕单个种子 |
三、排查决策树
分诊只问三件事:nets left 数字动不动、内存涨不涨、约束紧不紧。三个答案把现场切成「在收敛」「在振荡」「在换页」三条通道:
读这张图抓住三条分叉:nets left 在降走绿色通道,杀掉只会浪费已收敛的迭代;数字纹丝不动走振荡通道,别等了直接换 seed;内存逼近上限走换页通道,它在抖不是在算。 红色是入口现象与两类病态状态,蓝色是排查动作,绿色是「其实在干活」,橙色是修复,紫色是收口防复发。
四、逐条排查展开
先取证:数字、内存、尾行三样一起看。
tail -f nextpnr.log | grep -E "iteration|nets left"
ps -o pid,%cpu,rss,etime,cmd -p <pid>iteration 行里 nets left to route 是最诚实的进度指标,比任何进度条都可信。RSS 持续逼近物理内存就按换页通道处理,不要和收敛问题混着查。
利用率高:先看挤不挤,再决定等不等。 布线结束后(或上一次成功 run 的日志里)看 Device utilisation 段:逻辑单元、BRAM、布线资源任何一项超过 90%,PathFinder 的拆挤过程就会明显变慢;95% 以上基本是指数级,跑一晚上布不通很正常。应对:削掉可选逻辑、把大 buffer 改用 BRAM 实现、或者干脆换更大 die/封装。约束文件的引脚分配把同类信号打散在两个 bank 两侧,也会人为制造跨片布线压力——把相关信号收敛到相邻区域常常立刻见效。
约束过紧:timing-driven 模式会把「布不通」伪装成「还在算」。 --freq 100 跑不通的设计,--freq 50 可能十分钟布完。这不是玄学:频率目标直接决定 placer 和 router 的代价函数,目标越紧,工具越不肯接受次优解,反复重布。务实做法是先降频求布通、确认功能,再逐步收紧目标找设计真实的频率天花板。纯组合路径、跨时钟域路径记得在约束里声明 false path,否则工具会在不可能的路径上白费力气。
seed 运气差:这是 nextpnr 的特性不是缺陷。 布局从随机初值出发做模拟退火,同一设计不同 seed 的布线时间差 3-5 倍很平常,个别 seed 落在不可布区域直接振荡到天荒地老。处置就是制度化地扫:
for s in 1 2 3 4 5 6 7 8; do
timeout 30m nextpnr-ice40 --hx8k --json top.json --asc top_$s.asc \
--pcf top.pcf --seed $s > run_$s.log 2>&1 && echo "seed $s OK" && break
done哪个 seed 布通且时序达标就固定进 CI,不要在失败的 seed 上死等。
时钟资源冲突:placer 早期卡死的头号嫌疑。 多个时钟域争用有限的全局布线资源、或 PLL 输出接到不支持全局网络的引脚,placer 会在找不到合法位置时陷入漫长的局部搜索。日志早期若有 clock/PLL 相关 warning,先解决它们再谈别的;必要时显式指定全局网络(ice40 用 SB_GB 原语)。
verbose 与内存:两个伪装者。 --verbose/--debug 在大设计上能产出 GB 级日志,实时 tee 到终端或 CI 控制台时 I/O 本身就成了瓶颈,看起来像卡死——去掉 verbose、日志重定向落盘即可。内存侧,ECP5 大 die(85F)布线峰值内存按 8GB 以上预算,小内存机器换页后速度掉一个数量级,处置顺序:关同机大进程、换大内存机器,其次才是降规模。
五、预防与纪律
- 先求布通再追时序:频率目标从松到紧逐步收紧,不要一上来就定极限值。
- seed sweep 制度化:CI 里固定扫 5-10 个种子取最优,把「换 seed 就过」从运气变成流程。
- 利用率看板化:每次构建记录逻辑/BRAM/布线三项利用率,逼近 90% 就提前规划升级或削规模。
- 时钟资源先审:多时钟域设计动手前先核对全局网络预算,PLL 与专用时钟引脚用法一次到位。
- CI 分级超时 + 日志落盘:placement 与 routing 分开限时,日志写文件不刷控制台,超时任务保留完整日志与 seed 号,便于复盘是收敛慢还是振荡。
这一篇在知识体系里的位置
本篇是 FPGA 排错速查簇中「nextpnr 布局布线卡死」节点的 FAQ 页:综合阶段卡死(Yosys 跑不动)见 Yosys 卡死/超时速查;商业工具侧同类问题的分诊框架见 Quartus 编译卡死速查——三篇的分诊口径一致(日志尾行 + CPU/内存三态),但根因轴不同:nextpnr 侧独有 seed 初值敏感、PathFinder 振荡、--freq 代价函数这一套手段。
一句话总结
nextpnr 布线卡死不动的分诊起点是日志里 nets left 数字、内存占用、频率约束三件事:数字在降就是正常收敛,按利用率决定继续等还是削规模;数字不动是振荡,直接换 seed 重扫;内存将满 swap 在涨是换页,先止血内存。根治靠约束从松到紧、seed sweep 制度化、利用率看板与 CI 分级超时,把无期限卡死改造成带日志现场的快速失败。