nextpnr 未定义符号报错速查(unknown cell type / port not found)
更新时间:2026-10-23。FAQ 速查页,面向第一次用 yosys + nextpnr 开源链路撞上「名字找不到」类报错的同学。综合阶段(yosys 侧)就报找不到符号的场景请先看姊妹篇 Yosys 未定义符号速查;本篇收口的是 yosys 已经产出 .json、nextpnr 读进来之后报「cell 类型不认识 / 端口名不存在」的家族。版本差异引起的命名规则变化与 nextpnr 版本不匹配速查 有交叉,可对照着看。
报错原文长什么样
nextpnr 的「找不到」类报错辨识度很高,先对号入座:
ERROR: unknown cell type '$dff' at cell '$auto$simplemap.cc:442:simplemap_dff$123'
ERROR: unknown cell type 'SB_DFF_X2' at cell 'u_cnt$42'
ERROR: port 'led[0]' not found on cell 'top' (constrained in file blinky.pcf line 3)
ERROR: top-level module 'blinky_top' not found in design
ERROR: unknown cell type 'FDRE' at cell 'u_reg$7'三种形态对应三个不同层面:unknown cell type 是 json 里的 cell 类型名在目标器件的 chipdb 里查不到;port not found 是约束文件(PCF/LPF)里写的引脚名在 netlist 顶层端口表里没有;top-level module not found 是 -top 指定的名字和 json 里实际顶层不符。三类根因不同,修法完全不同,先分流再动手。
一句话根因
nextpnr 未定义符号 = 它在把 yosys 给的网表往器件资源上放的时候,引用了一个名字,但这个名字既不在器件 cell 库(chipdb)里,也不在综合后 netlist 的端口/模块表里。 根因几乎总落在六类:yosys 没把通用 cell 映射到目标器件、cell 名带参数化后缀与 chipdb 对不上、约束文件引脚名拼错或用了综合前名字、-top 顶层名指错、yosys/nextpnr 版本差导致 cell 命名规则变化、混用了别的器件家族的 cell 名。
排查决策流程
读这张图抓住一条主线:红色是入口现象,蓝色判定节点按「cell 层 → 约束层 → 顶层/版本层」三级分流,每个蓝节点只回答一个 yes/no 问题,命中就走对应橙色修复,最后汇到绿色「重新 place 通过」和紫色防复发。不要跳过判定直接改 RTL——先确认报错名字落在哪一层,一次只修一处。
原因速查表
| 根因 | 典型报错 | 快速验证 | 处置 |
|---|---|---|---|
| 1 通用 cell 未映射 | unknown cell type '$dff' / $mul 等美元符开头 | grep -o '"type": *"[^"]*"' design.json | sort -u 看有没有美元符开头的类型名 | 回 yosys 跑完整 synth_ice40(或对应器件),别只跑 proc; opt 就 write_json |
| 2 cell 名带参数化后缀 | unknown cell type 'SB_DFF_X2' 之类库里不存在的变体名 | 报错名字在 chipdb 文档/源码里搜不到完全一致的串 | 综合流程里不要手动改名/拼接 cell 类型,用标准 synth 脚本输出 |
| 3 约束引脚名拼错 | port 'led[0]' not found ... in file blinky.pcf | grep '"led"' design.json 确认综合后端口真实名字与位宽 | PCF 里改成综合后 netlist 的名字(大小写、下划线逐字一致) |
| 4 约束用了综合前名字 | 同上,但 json 里端口名被改了 | hierarchy 展平后名字变(如 u_top.led 或名字被 opt 合并) | 约束一律以综合后 json 里的端口名为准,不以 RTL 源码为准 |
| 5 -top 顶层名指错 | top-level module 'xxx' not found | grep -o '"top": *"[^"]*"' design.json 或看 json 顶层 modules 键名 | 改 -top 参数,或 yosys 端 synth_xxx -top 正确名 重新综合 |
| 6 版本命名差异 | 升级后突然报 unknown cell,老工程正常 | yosys 与 nextpnr 各自 --version 对拍,核对组合是否官方搭配 | 对齐到配套版本;详见 nextpnr 版本不匹配速查 |
| 7 混用别家 cell 名 | unknown cell type 'FDRE'(Xilinx 原语) | 报错名字是别的器件家族的原语名 | RTL 里的厂商原语换成目标器件的,或改用通用写法让 yosys 自动映射 |
逐条排查步骤
第 1 条「通用 cell 未映射」是 beginner 命中率最高的一类。 yosys 的综合是分阶段的:proc 把 RTL 变成内部进程、opt 做优化、techmap 把通用 cell(以美元符开头的内部名)换成目标器件的真实 cell。只跑了前几步就 write_json,json 里就全是美元符开头的通用类型名,nextpnr 一个都不认识。正确姿势是直接用一条 synth_ice40 -top top -json design.json(ice40 为例,ECP5 对应 synth_ecp5,Gowin 对应 synth_gowin),这条宏命令把映射全流程打包跑完。验证手段:综合末尾 yosys 会打 === 统计 === 段,列出 SB_DFF、SB_LUT4 这类真实 cell 的用量——看到的还是美元符名字,就说明映射没跑全。
第 2 条参数化后缀常见于手写 techmap 或从老脚本抄来的流程:cell 类型名被拼上了参数后缀(比如按位宽生成 SB_DFF_X2),而 chipdb 里只有不带后缀的原名。这类问题不要在 nextpnr 侧修,回 yosys 侧把映射脚本改回标准流程,让 cell 名由官方 techmap 产生。
第 3、4 条约束引脚名有一个反直觉的点:PCF/LPF 约束的对象是综合后的 netlist,不是你的 RTL 源码。 RTL 里叫 led 的端口,综合后可能因为 hierarchy 展平、opt 合并、位宽拆分而改名或消失。排查手法固定两步:
grep -o '"led[^"]*"' design.json | sort -u # 综合后真实的端口名
grep led blinky.pcf # 约束文件里写的名字两个输出逐字对拍,不一致就改约束文件。名字完全搜不到时,多半是端口被优化掉了(比如该信号实际没被任何逻辑使用),先解决「为什么被优化」再谈约束。还有一个低概率但坑人的变体:总线端口的下标写法。综合后 json 里 led[0] 和 led_0 是两代命名习惯的产物,不同 yosys 版本/不同 flatten 选项输出不同,约束文件写下标形式时先确认 json 里到底是哪种,别照抄网上例程的写法。
第 5 条顶层名的坑和 Quartus 家类似:工程从别人处拷来,-top 参数指向旧模块名。json 里顶层模块的真实名字可以在文件头部 modules 键下直接看到,或者综合时显式 -top 指定,两端保持一致即可。注意 yosys 的 -top 与 nextpnr 的 --top 是两个独立参数:yosys 端决定综合时以哪个模块为根展开层级,nextpnr 端决定从 json 里挑哪个模块当顶层,只改一端不改另一端会出现「综合成功但 nextpnr 找不到顶层」的错觉。
第 7 条混用原语常见于从 Vivado/Quartus 工程移植代码:RTL 里直接例化了 FDRE、IBUF 这类 Xilinx/Intel 原语,yosys 当成黑盒原样写进 json,nextpnr 的 ice40 库当然不认识。移植纪律:能写成通用 RTL 的不要例化厂商原语;必须用原语的地方,换成目标器件的对应件(如 ice40 的 SB_IO、SB_GB)。
修复后验证
处置完别直接跑完整 place & route,先让 nextpnr 把 json 读进去做静态检查:
nextpnr-ice40 --hx8k --package ct256 --json design.json --pcf blinky.pcf --no-route--no-route 只做加载和放置前检查,秒级出结果,不再出现 unknown cell / port not found 才算名字链完整。确认通过后再去掉开关跑全流程。
防复发
- 综合永远用一条
synth_<器件>宏命令,不拆步骤手动跑,从源头杜绝「映射没跑全」。 - 约束文件以综合后 json 为唯一事实源:CI 里加一步 grep 对拍(json 端口名 vs 约束名),改名即报警。
- yosys 与 nextpnr 版本成对固定:用同一次官方构建(如 oss-cad-suite 同一日期包),升级成对升级。
- 厂商原语进移植清单:代码库里
grep -rn "FDRE\|IBUF\|OBUF" rtl/定期扫,混用早发现。 - json 进临时产物目录、不入库但可重建:Makefile 固定
yosys → nextpnr → icepack顺序,任何环节报错先重跑上游。
一句话总结
nextpnr 未定义符号报错的本质是「它引用的 cell 类型名或端口名在器件库与综合后 netlist 里都不存在」:按「json 里有没有美元符开头的未映射 cell → cell 名是否带参数化后缀 → 约束名与综合后端口名逐字对拍 → -top 与 json 顶层对拍 → yosys/nextpnr 版本对拍 → 是否混用了别家原语」六类根因逐条收敛,修复后用 --no-route 秒级验证;防复发靠一条 synth 宏命令、约束以综合后为准、工具版本成对固定三条纪律。