nextpnr 时钟/约束缺失:no clocks found 与时序约束写法速查
更新时间:2026-10-25。FAQ 速查页,属于 FPGA 开源工具链排错系列。nextpnr 布线结束打时序报告时蹦出
Warning: no clocks found,很多新手直接略过——流程没报错、比特流也生成了。但这句警告的含义是:时序分析一个时钟都不认识,报告里的 setup/hold 数字全是没按你的频率目标算的。设计实际跑 100 MHz,工具按不知道多松的目标放行了,上板后间歇性出错却查不到原因。相邻问题见 yosys 时钟约束缺失 与 Quartus 时钟约束缺失。
本文要回答的问题
Warning: no clocks found到底意味着什么,可以不管吗?--freq参数、PCF/LPF 频率约束分别怎么写、优先级谁高?- 时钟明明进了芯片,为什么工具还是说找不到?
- 多时钟域设计在开源流程里怎么把每个域都约束上?
一、报错原文与现象
Warning: no clocks found in design
Info: Max frequency for clock 'clk': 48.23 MHz (PASS at 12 MHz)
Warning: No frequency constraint specified for clock 'clk', using default 12 MHz
ERROR: Failed to find clock net 'sys_clk' in design第二、三条放一起看最能说明问题:设计实际最高能跑 48 MHz,你目标是 100 MHz,但没写约束,工具按默认的 12 MHz 判定「PASS」——报告一片绿,实际离目标差一倍多。这就是时钟约束缺失的危害形态:不是报错,是给了你一个虚假的通过。第四条则是反过来的情况:约束写了、名字对不上,直接 ERROR。
二、可能原因总览
| 报错/现象 | 可能原因 | 处置 |
|---|---|---|
| no clocks found | 全程没写任何频率约束 | 按板子实际频率补约束 |
| using default 12 MHz | 约束缺省,工具用默认值 | 显式给 --freq 或约束文件频率 |
| Failed to find clock net | 约束名与网表时钟名不符 | 从 JSON 网表抄实际时钟名 |
| 频率 PASS 但裕量巨大 | 约束比设计目标松 | 核对约束数值是否写对 |
| 只有主时钟有报告 | 派生时钟/第二域没约束 | 每个时钟域单独约束 |
| 经 PLL 后时钟无约束 | PLL 输出频率工具推不出 | 手工约束 PLL 输出时钟 |
| 约束写了但 Warning 仍在 | 约束文件没被流程读到 | 核对命令行 -–pcf/--lpf 参数 |
三、逐条排查展开
先搞清楚这句警告的代价。 nextpnr 的时序驱动布局布线依赖频率目标:约束多紧,布线就多努力。没有约束时它按一个保守默认值干活,高扇出路径不会得到优先照顾。所以「no clocks found」不是礼貌性提醒,是「这次布线没有按你的性能目标优化」。凡是准备上板跑的设计,这句警告必须清零。
--freq 是最省事的单时钟约束。 单时钟设计直接在命令行给目标频率(单位 MHz):
nextpnr-ice40 --hx8k --package ct256 --pcf top.pcf --json top.json --asc top.asc --freq 100这一行等价于告诉工具「主时钟按 100 MHz 做时序驱动布线并检查」。对只有一个时钟的小设计,这是最推荐的方式,写进 Makefile 就不容易丢。
约束文件里写频率,适合多时钟。 PCF 语法支持按网络名约束频率:
set_frequency clk 100
set_frequency clk_slow 25LPF(Lattice 系)对应写法是 FREQUENCY NET "clk" 100.0 MHz;。注意名字是综合后网表里的时钟网络名,不是 RTL 里的信号名——综合可能改名或加缓冲,名字对不上就会触发上面第四条 ERROR。稳妥做法:布线前从 JSON 网表或上一轮报告里把实际时钟名抄出来。
时钟为什么「进了芯片却找不到」。 三种典型:一是时钟没走全局缓冲(没经 BUFG/PLL,工具不认它是时钟网络),需要在 RTL 例化对应原语或让 yosys 正确推断;二是约束写的是端口名而网表里时钟网络名是内部 net 名;三是时钟由组合逻辑生成(分频器输出),工具不会自动把它当时钟——生成时钟要显式约束,更规范的做法是用 PLL 派生。
多时钟域要逐个约束。 报告里只有主时钟一行的,八成是其他域没写约束。每个时钟域(包括 PLL 每个输出)都要有频率条目,跨域路径再按情况加伪路径或异步组约束。约束写完后验收方法很简单:时序报告里每个时钟域都要有一行 Max frequency,缺一行就是漏约束一个。
约束文件没生效的低级坑。 Makefile 改了、约束写了,Warning 还在——多半是命令行没把约束文件传进去,或传了旧路径。nextpnr 命令行里核对 --pcf/--lpf 参数指向的文件就是刚改的那份。这类「流程没读到我改的文件」的通用排查思路和 nextpnr 路径/文件不存在 一致。
时序报告要看「按谁算的」。 报告顶部的目标频率与每个时钟域的 Max frequency 是两回事:前者是你给的约束,后者是布线实际达到的能力。验收一个设计能不能跑在目标频率,看的不是「有没有 PASS 字样」,而是 Max frequency 那一行的数值是否大于等于你的目标值、且约束值确实是你想要的那个数。见过团队把约束写成 50 MHz、实际目标是 100 MHz,报告 PASS 就合板,回来联调才发现时序根本没验到位。约束数值本身写错,和没写约束是同一类事故。
换板子换晶振后约束要跟着换。 同一份 RTL 烧到晶振频率不同的两块板子上,约束文件若照抄,轻则性能目标虚设、重则时序结论全错。把约束文件按板型分目录管理,构建脚本按目标板型选约束,是从流程上防这类错配的办法。晶振频率、PLL 倍频比、目标频率三者写进同一份板型配置,改板子只改一处。
四、排查决策流程
主线按「先数清楚有几个时钟,再逐个补约束」走:红色是警告本身,蓝色三步是盘点与核对,橙色按单时钟/多时钟分两路修法,绿色验收标准很明确——时序报告里每个时钟域都有一行 Max frequency,紫色是把这套检查固化进脚本。
五、预防与纪律
- 频率目标进 Makefile:
--freq或约束文件路径写死在构建脚本里,不靠人肉记命令行。 - 每域一行约束:多时钟设计每个域(含 PLL 各输出)显式写频率,报告里缺一行就视为失败。
- 约束名以网表为准:时钟网络名从 JSON 网表或上一轮报告抄,不凭 RTL 印象。
- 生成时钟走 PLL:不要用组合逻辑分频出时钟,派生时钟用 PLL 并显式约束输出频率。
- no clocks found 零容忍:这句警告出现在 CI 日志里即判失败,与 ERROR 同级处理。
这一篇在知识体系里的位置
本篇是 FPGA 开源工具链排错簇中「时序约束」节点的 FAQ 页:与 yosys 时钟约束缺失(综合前端同名警告)、Quartus 时钟约束缺失(商业工具对照)、nextpnr 位宽/类型不匹配(同属「警告当结果」的静默偏离)互补;约束基础写法见 XDC 引脚与时序约束,系列总览见 FPGA 知识版图。
一句话总结
nextpnr 报 no clocks found 的本质是「布线没按你的频率目标优化,报告里的 PASS 是假的」:单时钟用 --freq 给目标值,多时钟在 PCF/LPF 里按网表实际时钟名逐域写 set_frequency,PLL 输出与生成的时钟也要显式约束;验收标准是时序报告里每个时钟域都有一行 Max frequency;最后把频率约束固化进 Makefile、把这句警告列入 CI 失败条件,让约束缺失在烧板之前就被拦住。