Verilator PINCONNECTEMPTY 显式空接排查:Cell pin connected by name with empty reference
更新时间:2026-10-30。FAQ 速查页,属于 EDA 报错排查系列。
%Warning-PINCONNECTEMPTY表示例化端口表中写了.debug()这类显式空接:端口名存在,括号里却没有表达式。它与 Verilator PINCONNECTEMPTY 的近邻 PINMISSING 不是同一个码,后者是整个端口项都没写。
首屏答案:看到 Cell pin connected by name with empty reference 不要直接全局消音。输出端口确实不用时,可接 unused_debug 这样的具名线网;输入端口则必须确认悬空是否符合设计,通常应接真实信号或规格规定的常量。只有第三方代码等无法修改连接的场景,才在该实例周围局部使用 lint_off PINCONNECTEMPTY。
这张图的关键是不要从告警直接跳到豁免。中间两次确认决定了修复是否正确:先看方向,再回答“不接为什么仍然正确”。最后的复跑必须使用原来的参数,否则关掉 -Wall 得到的干净输出不算修复。
本文要回答的问题
- Verilator PINCONNECTEMPTY 的完整报错应该看哪几个字段?
- 显式
.pin()空接与完全不写端口项有什么区别? - 输入和输出端口分别该怎样处理?
- 什么时候可以用局部
lint_off,什么时候不该豁免? - 修复后怎样用同一条命令确认告警真正消失?
一、完整报错:端口名写了,连接表达式却是空的
最小例子里,child 有一个正常输出 out 和一个调试用输出 debug。顶层只需要 out,于是把 debug 写成空括号:
module top_bad (
input wire a,
output wire y
);
child u_child (
.in(a),
.out(y),
.debug()
);
endmodule在容器内执行 ./run.sh,脚本分别检查报错版和修复版。终端记录保留了同一轮的两份结果:
告警行 top_bad.v:8:8 精确指向 .debug() 的端口名,而不是子模块声明;'debug' 给出具体端口;empty reference 则说明语法关联已经存在,缺的是引用表达式。末尾 Exiting due to 1 warning(s) 和 broken_exit_code: 1 表明这次检查确实失败,不是只打印了一条提示。
二、工具版本:这是 -Wall 打开的风格与意图检查
本篇使用 Docker 镜像 geek-eda:0.2 中的 Verilator 5.020。PINCONNECTEMPTY 默认不启用,加上 -Wall 后才会检查,因此旧工程第一次把严格 lint 接入持续集成时,往往集中看到它。
这条告警不等于“电路一定错误”。Verilog 允许空连接,某些输出端口不接也是正常设计;工具在严格模式下要求你把意图处理得更明确。相对而言,空接输入更值得警惕:它不会被自动当成 0,仿真语义仍是不连接的端口。不要为了让 lint 变绿,随手给输入填一个看似无害的常量,常量值必须来自接口规格。
| 场景 | 严格 lint 的含义 | 优先处理 |
|---|---|---|
| 输出暂时不用 | 主动丢弃一个输出 | 接具名未用线网,保留可读意图 |
| 输出本应使用 | 连接表达式漏写 | 接回正确的顶层信号 |
| 输入永久不用 | 端口悬空,不是常量 0 | 按规格接固定电平并记录理由 |
| 输入暂时不用 | 功能可能尚未完成 | 补真实驱动,不把豁免当完成 |
三、根因:空接、漏接与写错名字是三种情况
三个告警都出现在例化附近,但工具看到的端口表完全不同。按“端口项是否存在、括号内是否有表达式”分类,比只记报错文案可靠。
读这张图只看左到右的映射:.debug() 对应本篇文章;完全删去这一行才进入 PINMISSING 排查;把 debug 拼成 debg 则是另一类问题。把三者都归结为“端口悬空”会选错修复,例如给 PINMISSING 补一个空括号,只是把漏接告警换成空接告警,并没有证明设计正确。
常见成因还有接口重构:原来 .debug(debug_net),删除上层调试网络时只删了括号里的名字;或者复制模板时保留了 .pin() 占位。它们都属于“显式写法还在,设计意图没有收尾”。
四、排查清单:先确认意图,再决定豁免
- 定位端口项:按文件名、行列号跳到
.pin(),确认确实是空括号,不是宏展开后为空。 - 对照子模块定义:核对端口方向、位宽和注释,别只凭端口名猜用途。
- 追一次真实用途:输出是否给验证、调试或上层状态使用;输入是否影响功能、功耗或安全状态。
- 选择连接方式:该用的接真实信号;确认不用的输出接具名未用线网;不用的输入按规格接常量。
- 限制豁免范围:无法改第三方或生成代码时,只在对应实例前后写
lint_off/lint_on,注释说明端口和理由。 - 全局检查同模块例化:搜索同一模块的其他实例,避免只修工具这一次指出的位置。
- 原参数复跑:保留
--lint-only -Wall和相同顶层,退出码 0 才结束。
如果告警只在某个宏配置下出现,还要展开该配置再判断。空的宏实参可能让源码表面上的 .debug(debug_net) 在预处理后变成 .debug();这时修宏调用或配置,比给所有配置加豁免更准确。团队评审时也可以直接追问一句:这个端口在未来的验证、调试或量产模式中是否仍需观察?答案若不确定,先保留具名连接更稳妥。
局部豁免的形式如下。它能压住 PINCONNECTEMPTY,但不会替你检查“输入能否悬空”,所以审批重点仍是注释里的设计理由:
/* verilator lint_off PINCONNECTEMPTY */
// 第三方实例的调试输出确认不使用,仅此实例豁免。
child u_child (.in(a), .out(y), .debug());
/* verilator lint_on PINCONNECTEMPTY */不要用全局 -Wno-PINCONNECTEMPTY 代替这段局部处理。全局开关会让以后新写的 .ready()、.valid() 空接也不再出现,失去严格 lint 的价值。
五、修复与复跑:具名未用信号拿到 PASS
本例的 debug 是输出,且顶层确认不用。修复不是删除端口项,也不是豁免,而是声明 unused_debug 并显式连接:
module top_fixed (
input wire a,
output wire y
);
wire unused_debug;
child u_child (
.in(a),
.out(y),
.debug(unused_debug)
);
endmoduleunused_ 前缀让读者一眼看出该线网有意不被消费;实际功能输出 y 的连接没有改变。若端口是输入,这种写法只回答了“信号叫什么”,没有回答“谁来驱动”,不能直接照搬。
$ docker run --rm -v "$PWD":/work -w /work geek-eda:0.2 verilator --lint-only -Wall --top-module top_fixed child.v top_fixed.v
# fixed_exit_code: 0
PASS: PINCONNECTEMPTY reproduced; named unused signal fixes lint这次复跑与报错版只有顶层模块和对应源文件不同,-Wall 等检查条件保持一致。fixed_exit_code: 0 证明工具接受修复,末尾 PASS 同时要求报错版非零、修复版为零,避免脚本把“两次都没跑对”误判为成功。
实验环境
- 机器/系统:Intel Mac / macOS 26.5.2,Docker 容器
geek-eda:0.2 - 工具版本:Verilator 5.020 2024-01-01 rev (Debian 5.020-1)
- 日期:2026-10-30
- 完整命令:在实验目录运行
./run.sh;脚本内部依次执行docker run --rm -v "$PWD":/work -w /work geek-eda:0.2 verilator --lint-only -Wall --top-module top_bad child.v top_bad.v和同一形式的top_fixed检查,并打印两者退出码。
代码获取
完整源码、运行脚本、README 与原始输出在公开仓 https://github.com/derekzhuo/geek-doc.cn/tree/main/experiments/ts-verilator-warn-pinconnectempty。准备同名 Docker 镜像后,进入该目录执行 ./run.sh 即可复现告警并验证修复。
这一篇在知识体系里的位置
本篇处理显式空括号;整个端口项缺失看 Verilator PINMISSING 排查,端口名不存在看 Verilator PINCONNECTEMPTY 之后的 PINNOTFOUND 拼写检查。端口已经接上、只是表达式位宽不匹配时,转到 Verilator WIDTHTRUNC 排查。其他开源工具报错可从 开源 EDA 报错排查导航 继续定位。
总结
Verilator PINCONNECTEMPTY 指的是 .pin() 这种“端口项存在、连接引用为空”的显式空接,不等于完全漏写的 PINMISSING。处理时先按报错行定位,再核对端口方向和真实意图:该用的接真实信号,确认不用的输出可接具名未用线网,不用的输入应按规格驱动;仅在无法修改连接且已确认无功能影响时做局部 lint_off。最后保留 -Wall 原样复跑,以修复版退出码 0 和完整 PASS 作为闭环。