Verilator PINMISSING 例化漏接端口排查:Cell has missing pin 速查
更新时间:2026-10-29。FAQ 速查页,属于 EDA 报错排查系列。
%Warning-PINMISSING: Cell has missing pin是 Verilator 开-Wall后对「模块例化时少接了端口」的告警。它和 %Warning-UNDRIVEN 是邻居——一个是例化时端口根本没连,另一个是信号声明了没人驱动;同一 lint 家族的位宽问题见 Verilator WIDTH 告警。
首屏答案:PINMISSING 的意思是某个例化单元(cell)的端口列表比模块定义少了——子模块声明了 5 个端口,你 .a() .b() .sum() .cout() 只接了 4 个,剩下的 cin 悬空。悬空输入在仿真里是不定态 X,在综合后可能被优化成常量也可能引入不可预期的结构,属于典型的「能编译但有坑」。修法只有两条:把该接的信号接上(本例 .cin(1'b0)),或显式写 .cin() 置空告诉工具「我知道它没接,是故意的」。绝不要用 lint_off PINMISSING 把整个告警关掉——那会顺带放过以后真正的漏接。
本文要回答的问题
%Warning-PINMISSING报错串里的行号指向哪里?- 漏接的端口在仿真和综合里分别有什么后果?
- 补接信号和显式
.pin()置空怎么选? - 怎么在 CI 里把这类漏接拦在提交前?
一、报错原文与现象
最小复现:子模块 adder 有 5 个端口,顶层例化时漏写 .cin:
// adder.v:带进位输入的 8 位加法器
module adder(
input wire [7:0] a,
input wire [7:0] b,
input wire cin,
output wire [7:0] sum,
output wire cout
);
assign {cout, sum} = {1'b0, a} + {1'b0, b} + {8'd0, cin};
endmodule
// top_bad.v:例化漏接 cin
module top_bad(
input wire [7:0] a, input wire [7:0] b,
output wire [7:0] sum, output wire cout
);
adder u_adder(
.a(a), .b(b),
// .cin 漏接:进位输入悬空
.sum(sum), .cout(cout)
);
endmodule跑 verilator --lint-only -Wall,真实输出如下:
读这段输出抓三个字段:第一,主行 top_bad.v:8:9 指向例化语句的位置(adder u_adder( 那一行的实例名),不是子模块定义处——排查时去父模块找例化点;第二,告警文案 Cell has missing pin: 'cin' 直接报出漏掉的端口名,不用自己对比端口列表;第三,末尾 %Error: Exiting due to 1 warning(s) 表示 lint 模式把告警提升为退出错误,CI 里这一条就卡住构建。提示行里的 lint_off PINMISSING 是消音开关,第四节讲什么时候能用、什么时候是坑。
二、工具与版本
本篇所有现象在 Verilator 5.020 上实测,容器镜像 geek-eda:0.2。PINMISSING 属于 -Wall 才会开启的告警档(不加 -Wall 的默认 lint 不报它),所以「没开 Wall 的工程第一次开 Wall」时会成片冒出来——这是它最常见的出场方式。同名告警在 Icarus Verilog(iverilog)里没有对应检查,它默认容忍漏接端口,这也是很多从 iverilog 转到 Verilator 的工程第一次见这个告警的原因。
三、根本原因
漏接端口的本质:实例的端口连接表是模块定义端口列表的子集。Verilog 标准允许这种「部分连接」,语义上等价于悬空。三个高频成因:
这张漏斗按命中率从上往下排:版本漂移占大头——子模块迭代加了端口(比如加法器后来加了 cin),调用方几十处例化没人同步改;复制残留次之——从别的例化点粘代码时把「这边用不到」的端口连接行删了;认知盲区最少见但最危险——以为输入不接就默认 0,实际仿真里它是 X,会顺着组合逻辑把输出染成一片 X。漏接的输出端口危害小得多(只是没人用,可能再叠一条 %Warning-UNUSEDSIGNAL),漏接的输入端口才是真正的功能风险。
四、排查清单
- 定位例化点:告警行号在父模块的例化语句上,直接跳过去看。
- 对端口列表:打开子模块定义,逐个比对接了哪些、漏了哪些。
- 判意图:漏掉的端口是「忘了接」还是「故意不用」?忘了接就补上正确信号;故意不用走下一步。
- 判方向:漏的是输入还是输出?输入必须处理(接常量或显式置空),输出不接一般无害。
- 全局搜同款:
grep -n "u_adder\|adder u_"找出所有例化点,一次改全,别只修告警指出的那一处。 - 复跑验证:
verilator --lint-only -Wall零告警退出码 0 才算闭环。
五、修复与验证
本例的 cin 是「忘了接」里最简单的情形:顶层没有进位概念,固定接常量 0 即可:
module top_fixed(
input wire [7:0] a, input wire [7:0] b,
output wire [7:0] sum, output wire cout
);
adder u_adder(
.a(a), .b(b),
.cin(1'b0), // 补接:无进位场景显式接常量 0
.sum(sum), .cout(cout)
);
endmodule如果端口确实用不上又不想接线(比如子模块的调试输入),写显式置空 .cin()——空括号告诉 Verilator「这个端口我故意不接」,PINMISSING 立即消音,且语义上比 lint_off 精确:只豁免这一个端口,其他端口漏接照样报。对修复后的文件重跑同一条 lint 命令,输出干净、退出码 0(见第一节 termshot 下半段 # exit_code: 0)。要强调的是:显式置空只适用于确认无功能影响的端口,别拿它当「快速消音器」批量糊——每个置空都该能回答「这个输入不接,功能为什么还对」。
实验环境
- 机器/系统:Mac mini(Apple Silicon)/ docker 容器 geek-eda:0.2
- 工具版本:Verilator 5.020
- 日期:2026-10-29
- 完整命令:
docker run --rm -v .:/work -w /work geek-eda:0.2 verilator --lint-only -Wall --top-module top_bad adder.v top_bad.v(报错复现);同一命令换--top-module top_fixed ... top_fixed.v(修复后复验)
代码获取
复现用源码(adder.v、top_bad.v 报错版、top_fixed.v 修复版)与完整 lint 记录在公开仓 https://github.com/derekzhuo/geek-doc.cn/tree/main/experiments/verilator-warn-pinmissing。装好 docker 后按 README 两条命令即可复现告警并验证修复。
这一篇在知识体系里的位置
本篇是 EDA 报错排查系列中 Verilator lint 告警簇的一员:例化端口漏接看本篇;信号声明了没人驱动看 %Warning-UNDRIVEN 排查;端口接上了但位宽不符看 Verilator WIDTH 告警;一根信号多处驱动看 %Warning-MULTIDRIVEN 排查。开源工具链报错的总入口见 开源 EDA 报错排查导航,整个系列的目录在 EDA 报错排查系列。
总结
%Warning-PINMISSING: Cell has missing pin 就是模块例化时端口连接表比定义少了端口,告警行号指向父模块的例化语句、文案直接报出漏掉的端口名;根因按命中率排序是子模块改版加端口、复制粘贴删行、误以为不接默认 0 三种;漏接输入端口在仿真里是不定态 X 会污染输出,必须补接正确信号或显式 .pin() 置空,漏接输出端口一般无害;修复后全局搜同款例化点一次改全,重跑 -Wall 零告警退出码 0 才算闭环,不要用 lint_off PINMISSING 整片消音代替修复。