Verilator PINNOCONNECT 端口未连接:位置参数空槽排查与修复
更新时间:2026-10-31。本文属于 EDA 报错排查系列,聚焦 Verilator 例化端口检查中的一个容易混淆的告警。
首屏答案:Verilator PINNOCONNECT 端口未连接通常不是模块缺少端口,而是位置连接表里给端口留了位置,却没有填连接表达式,例如 child u_child(in_data, , out_data) 的第二个空槽。.in_valid() 是命名空接,对应 PINCONNECTEMPTY;命名连接表完全漏写 in_valid,才对应 PINMISSING。修复时优先改成命名连接:确实不用的端口显式空接并局部说明,需要参与逻辑的端口则接上真实信号,最后用相同参数复跑 lint。
本文要回答的问题
Cell pin is not connected: '__pinNumber2'指向哪里?- PINNOCONNECT、PINCONNECTEMPTY、PINMISSING 的写法边界是什么?
- 位置参数里的逗号空槽为什么容易在改接口后出现?
- 显式空接和补齐真实信号分别怎样通过复验?
处理这类告警的关键不是立刻关闭告警,而是先辨认“未接、空接、漏接”三种源码形态。下面六步把定位、分码和复跑串成一条路径;其中第三步与第四步虽然都表示端口没有有效信号,告警码却不同。
这张图最容易被忽略的是第二步:位置连接依赖端口顺序,子模块中间新增一个端口后,旧实例里的后续实参可能整体错位。命名连接多写几个端口名,却能消除这种顺序耦合,也让“有意空接”与“漏写端口”在代码评审中可直接分辨。
一、用最小实例复现 PINNOCONNECT
复现使用一个两输入、一输出的子模块。in_valid 是第二个端口,只有它为有效值时,in_data 才传到输出:
module child (
input logic in_data,
input logic in_valid,
output logic out_data
);
always_comb begin
out_data = in_data & in_valid;
end
endmodule顶层只声明了 in_data 和 out_data,实例仍使用位置连接,并在第二个实参的位置留下一个空槽:
module top (
input logic in_data,
output logic out_data
);
child u_child (in_data, , out_data);
endmodule对这两个文件运行 verilator --lint-only -Wall -Wwarn-PINNOCONNECT --top-module top child.sv bad_positional.sv。PINNOCONNECT 默认关闭,-Wall 可以打开这类代码风格检查;命令里再写 -Wwarn-PINNOCONNECT,是为了让实验意图明确,也避免外部 lint 配置差异影响复现。下面的输出省略了文件名检查,只保留端口问题。
告警列号是 29,插入符正好落在两个逗号之间。__pinNumber2 不是设计里真实存在的信号,而是 Verilator 给第二个位置实参生成的内部称呼。末尾 Exiting due to 1 warning(s) 与退出码 1 表明:在当前 lint 设置下,警告会使命令失败。这里的根因不是 child 没有声明 in_valid,而是 top 没有给这个已声明端口提供连接表达式。
二、三个端口告警的边界
三种告警都在例化边界附近出现,但源码证据不同。判断时看实例本身,不必先钻进子模块内部:
| 告警 | 最小写法 | 端口项是否存在 | 实际含义 |
|---|---|---|---|
| PINNOCONNECT | child u(a, , y) | 位置槽存在,表达式为空 | 位置参数未连接 |
| PINCONNECTEMPTY | .in_valid() | 命名项存在,括号为空 | 明确写出命名空接 |
| PINMISSING | 只写 .in_data(a) 等其他端口 | 命名项不存在 | 命名连接表漏掉端口 |
实验对后两种写法也分别复跑。.in_valid() 得到 %Warning-PINCONNECTEMPTY: Cell pin connected by name with empty reference;完全删去这一项,则得到 %Warning-PINMISSING: Cell has missing pin。两者都在同一份记录的对应段落出现,说明它们不是 PINNOCONNECT 的不同文案,而是三个独立检查。
这个边界也决定修法。如果告警来自旧式位置连接,不建议只把第二个逗号换成另一个空表达式就结束;改成 .in_valid() 虽然能表达意图,但在 -Wall 下仍可能触发 PINCONNECTEMPTY。若设计其实需要有效信号,仅把空槽换一种写法更是在掩盖接口缺线。先回答“这个端口在功能上应不应该有驱动”,再选修复路径。
三、为什么位置连接容易留下空槽
位置连接按声明顺序一一对应,可读性依赖读者同时记住两份列表。以下改动都可能让原本能跑的实例突然报警:
- 子模块新增
in_valid,调用方暂时用空槽占位,后来忘记补线; - 复制旧实例后删掉了中间实参,却保留了分隔逗号;
- 调整端口顺序,只修改子模块声明,没有逐个检查上层实例;
- 自动生成连接表时,可选端口被渲染成空字符串。
前两种是直接的空槽,后两种还可能伴随更危险的错位连接。尤其当相邻端口位宽相同、方向也相同,编译器无法从类型上发现接反。排查时应把子模块端口声明和实例并排核对,不要只看告警所在的一行。
工程上可以把命名连接作为默认写法。端口名本身就是接口文档,新增端口时 PINMISSING 会明确指出缺哪一项;确实不连接的端口也能通过 .pin() 被 reviewer 看见。位置连接并非始终非法,但只适合端口很少且接口稳定的简单实例。
四、两种修复及复跑结果
路径 A:端口确实不用,显式空接并局部豁免。 把位置连接改成命名连接,让 in_valid 的未使用意图可见。由于 -Wall 仍检查 PINCONNECTEMPTY,只在这个实例周围局部关闭该告警,完成后立即恢复:
/* verilator lint_off PINCONNECTEMPTY */
child u_child (
.in_data (in_data),
.in_valid (),
.out_data (out_data)
);
/* verilator lint_on PINCONNECTEMPTY */局部豁免只适用于已经确认不影响功能的端口,不推荐在全局关闭 PINNOCONNECT 或 PINCONNECTEMPTY。否则下一处真正的漏接也会一起被隐藏。
路径 B:端口需要参与功能,补齐真实连接。 给顶层增加 in_valid,再接入同名端口:
module top (
input logic in_data,
input logic in_valid,
output logic out_data
);
child u_child (
.in_data (in_data),
.in_valid (in_valid),
.out_data (out_data)
);
endmodule两个版本分别用与报错时相同的 lint 参数复跑。下面逐字保留修复命令、退出码和检查结果;两条命令都没有产生诊断,退出码均为 0:
$ verilator --lint-only -Wall -Wwarn-PINNOCONNECT -Wno-DECLFILENAME --top-module top child.sv fixed_empty.sv
# exit_code: 0
PASS: fixed_empty.sv lint clean
=== fixed_connected.sv: expect clean lint ===
$ verilator --lint-only -Wall -Wwarn-PINNOCONNECT -Wno-DECLFILENAME --top-module top child.sv fixed_connected.sv
# exit_code: 0
PASS: fixed_connected.sv lint clean因此,PASS 不代表两种设计等价。显式空接只证明“有意的未使用”已被清楚标注,真实连接才保留 in_valid 对输出的控制。选择哪条路径必须由接口功能决定,而不是看哪一种最容易让告警消失。
五、提交前的检查清单
- 搜索实例中是否存在连续逗号
, ,,逐一确认不是占位残留。 - 新实例优先使用命名端口,并对照子模块声明检查所有必需输入。
- 对有意不用的端口保留
.pin(),豁免范围限定到对应实例。 - 修复后使用原命令复跑,不能一边修端口一边临时去掉
-Wall。 - 若实例由脚本生成,同时修正模板,避免下次生成时空槽复发。
这几项检查关注的是连接意图是否完整。仅看当前文件没有告警还不够,子模块接口变化后,所有上层实例都应重新经过同一套 lint。
实验环境
- 机器/系统:macOS 主机,Docker
geek-eda:0.2容器。 - 工具版本:Verilator 5.020 2024-01-01 rev (Debian 5.020-1)。
- 日期:2026-10-31。
- 完整命令:
docker run --rm -v "$PWD:/work" -w /work geek-eda:0.2 bash run.sh;脚本对每个源码执行verilator --lint-only -Wall -Wwarn-PINNOCONNECT -Wno-DECLFILENAME --top-module top child.sv <文件>,同时核对告警码与退出码。
代码获取
完整子模块、三个告警复现文件、两个修复版本及运行脚本位于公开仓 https://github.com/derekzhuo/geek-doc.cn/tree/main/experiments/ts-verilator-warn-pinnoconnect。进入该目录后执行 make run;三个复现项出现各自预期告警、两个修复项退出码为 0 时,脚本整体返回 0。
这一篇在知识体系里的位置
本篇处理位置参数空槽;命名空接的专项说明见 Verilator PINCONNECTEMPTY 排查,命名连接表漏项见 Verilator PINMISSING 排查。如果问题已经越过例化边界、变成同一信号被多处驱动,则继续看 Verilator MULTIDRIVEN 排查。
总结
Verilator PINNOCONNECT 端口未连接的核心证据是位置连接表中的空槽,__pinNumber2 指向第二个位置实参,而不是某个真实信号名。.in_valid() 属于 PINCONNECTEMPTY,命名表漏写端口属于 PINMISSING,三者不能混用修法。确认端口不用时改成命名空接并做最小范围豁免;端口有功能需求时补齐真实信号。保留原 lint 参数复跑并取得退出码 0,才算完成修复。