%Error-PINNOTFOUND: Pin not found 排查:Verilator 例化端口名不存在修复
更新时间:2026-10-29。FAQ 速查页,属于 EDA 报错排查系列。
%Error-PINNOTFOUND: Pin not found是 Verilator 在例化(instantiation)阶段抛的硬错误:你在上层模块里按名字连了一个端口,但这个名字在被例化模块的定义里根本不存在。和「端口存在但你没连」的%Warning-PINMISSING不同,PINNOTFOUND 是 Error 级别——连的是个假名字,电路根本建不起来,编译直接中止。模块改名重构后忘了同步上层例化点,是它最高频的来历;隐式线网类的名字问题则看 iverilog 隐式线网定义排查。
首屏答案:PINNOTFOUND 的意思是按名连接(.portname(signal))里的 portname 在子模块定义里查无此口。九成原因是两种:拼写错误(data_a 写成 date_a),或者子模块接口改过名、上层例化点没跟上。修法永远是打开子模块定义核对真实端口名,把例化点改回来;改完顺手检查是否因此漏连了真端口(伴随的 PINMISSING 告警会告诉你),复跑同一条 lint 命令到退出码 0 才算闭环。
本文要回答的问题
%Error-PINNOTFOUND报错串里的行号和端口名各指向什么?- 它和结伴出现的
%Warning-PINMISSING是什么关系? - 哪些高频场景会写出不存在的端口名?
- 修完怎么确认真的闭环、没有留下漏连的端口?
一、报错原文与现象
最小复现:子模块 adder 的真实端口叫 a,上层例化时却写成了 data_a:
// adder.v —— 子模块定义,端口是 a/b/cin/sum/cout
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 —— 例化时把 .a 写成了 .data_a
module top_bad (
input wire [7:0] x,
input wire [7:0] y,
output wire [7:0] z,
output wire carry
);
adder u_adder (
.data_a (x), // 模块定义里叫 a,不叫 data_a
.b (y),
.cin (1'b0),
.sum (z),
.cout (carry)
);
endmodule对这个设计跑 lint,真实报错与修复后复跑结果如下:
读这段输出抓三个字段:第一,主行 %Error-PINNOTFOUND: top_bad.v:8:8: Pin not found: 'data_a' 的行号指向例化点里写错的那一行,单引号里的 data_a 就是查无此口的名字;第二,上面结伴出现的 %Warning-PINMISSING: ... Cell has missing pin: 'a' 是同一块硬币的另一面——你写了个假名 data_a,真端口 a 自然没人连,于是 Verilator 用 PINMISSING 把「真正该连的口」也点了出来,两条合起来读,正确答案其实已经摆在日志里;第三,末尾 Exiting due to 1 error(s) 说明这是中止编译的硬错误,不是能带着跑的告警。修复版把 .data_a 改回 .a 后复跑同一条命令,零输出、退出码 0。
二、工具与版本
本篇实验在 Linux 容器环境用 Verilator 5.020(2024-01-01,Debian 打包版)实测,命令统一为 verilator --lint-only -Wall --top-module <top> <files...>。PINNOTFOUND 是 Error 不是 Warning,不需要 -Wall 也会报——只要端口名对不上,任何 lint 或编译命令都会中止在这里。报错文案的三要素(文件名:行号 + Pin not found + 单引号端口名)从 4.x 到 5.x 保持一致,排查方法通用。
顺带理清它和 PINMISSING 的分工,两者经常被误当成同一个问题:
| 对比维度 | %Error-PINNOTFOUND | %Warning-PINMISSING |
|---|---|---|
| 语义 | 你写的端口名子模块里没有 | 子模块有的端口你没连 |
| 级别 | Error,编译中止 | Warning,默认继续 |
| 典型来历 | 拼错、改名没同步、粘错模板 | 新增端口后上层没补连接 |
| 修复方向 | 把假名改回真实端口名 | 把真端口补连或显式留空 |
写错一个名字时两条往往同时出现:假名触发 PINNOTFOUND,被顶替的真端口触发 PINMISSING。看到这对组合不要当两个独立 bug 修——改掉假名,两条一起消。
三、根本原因:名字为什么会对不上
按名连接的本质是一次「查表」:Verilator 拿你写的端口名去子模块定义的端口列表里找,找到就接线,找不到就报 PINNOTFOUND。对不上的高频场景按命中率排序:一是重构改名没跟上——子模块接口把 a 改成了 data_a(或反过来),上层十几处例化点只改了一部分;二是拼写/记忆偏差——凭印象写 clk_i 而定义里叫 clock,或大小写笔误,Verilog 标识符大小写敏感,Sum 和 sum 是两个名字;三是复制粘贴模板串味——从别的模块例化点抄过来一段,端口名是上一个模块的接口,忘了换成当前模块的。排查收敛路径一张卡看全:
这张流程卡的读法是:PINNOTFOUND 不需要「推理」,它是个纯核对题——报错给了假名,PINMISSING 给了真名,打开子模块定义确认一眼就能改。真正值得花时间的环节是第三步之后的追问:这个名字为什么会对不上?如果是改名没同步,立刻全局搜一遍其他例化点(grep -rn "u_adder\|adder (" --include="*.v"),别让同一个坑在别的文件里再炸一次;大小写敏感这条也要记住,跨平台协作时尤其容易踩。
四、排查清单
拿到 PINNOTFOUND 后按这份清单机械执行:
- 抄下假名与行号:报错行指向例化块里写错的那一条连接,单引号里就是查无此口的名字。
- 打开子模块定义:核对真实端口列表,注意大小写、下划线位置、单复数(
sum/sums)。 - 看结伴的 PINMISSING:它点名的就是被你顶替掉的真端口,多数情况直接把真名告诉你了。
- 全局搜同模块的其他例化点:改名没同步的场景很少只错一处,同一模块的所有例化点都要过一遍。
- 区分「写错名」与「删错口」:如果子模块最近删过端口,报错也可能是上层还连着已被删除的旧口——这种时候改上层才是对的,不要反过来把端口加回去。
- 收口复验:改完重跑同一条命令,看到退出码 0、无 PINNOTFOUND/PINMISSING 字样才算闭环。
五、修复代码与复跑确认
本例属于「写错名」,修法是把例化点里的假名改回子模块定义里的真实端口名:
// top_fixed.v —— .data_a 改回 .a,两条报错一起消失
module top_fixed (
input wire [7:0] x,
input wire [7:0] y,
output wire [7:0] z,
output wire carry
);
adder u_adder (
.a (x), // 改回模块定义里的真实端口名
.b (y),
.cin (1'b0),
.sum (z),
.cout (carry)
);
endmodule对修复后的文件重跑同一条 lint 命令,零告警、退出码 0(见第一节 termshot 末尾两行)。三个防复发习惯:一是例化一律用按名连接,不要按位置连接——位置连接在接口加端口时静默错位,比 PINNOTFOUND 这种当场报错的形态危险得多;二是接口改名后立刻全仓搜例化点,把「改定义」和「改所有上层」当成一个原子动作;三是确实要留空的端口显式写 .cout(),让意图可见,把 PINMISSING 留给真正漏连的情况报警。反面做法只有一个:用 /* verilator lint_off PINMISSING */ 把结伴告警消音然后假装没事——PINNOTFOUND 是 Error 消不掉,而消了 PINMISSING 等于拆掉「真端口漏连」这盏唯一的提示灯。
实验环境
- 机器/系统:Linux 容器环境(docker 镜像 geek-eda:0.2)
- 工具版本:Verilator 5.020 2024-01-01 rev (Debian 5.020-1)
- 日期:2026-10-29
- 完整命令:
verilator --lint-only -Wall --top-module top_bad top_bad.v adder.v(报错复现,退出码 1);verilator --lint-only -Wall --top-module top_fixed top_fixed.v adder.v(修复后复验,退出码 0)
代码获取
复现用源码(adder.v 子模块、top_bad.v 报错版、top_fixed.v 修复版)与完整 lint log 在公开仓 https://github.com/derekzhuo/geek-doc.cn/tree/main/experiments/verilator-warn-pinnotfound。装好 Verilator 后跑 verilator --lint-only -Wall --top-module top_bad top_bad.v adder.v 复现报错,再对 top_fixed.v 跑同一命令验证修复。
这一篇在知识体系里的位置
本篇是 EDA 报错排查系列中 Verilator 例化连接簇的一员:端口名写错报 PINNOTFOUND 看本篇;信号根本没人驱动的告警看 %Warning-UNDRIVEN 排查;case 分支覆盖不全看 %Warning-CASEINCOMPLETE 排查;iverilog 侧的名字类问题看 iverilog 隐式线网定义排查。整个系列的目录与分流入口在 开源 EDA 报错排错中心。
总结
%Error-PINNOTFOUND: Pin not found 就是例化时写的端口名在子模块定义里查无此口——拼错或接口改名没同步占了九成;它是中止编译的硬错误,报错行给假名、结伴的 PINMISSING 给真名,打开子模块定义核对一眼即可改回;改完全局搜同模块其他例化点防止同坑再炸,复跑 lint 到退出码 0 才算闭环;日常坚持按名连接、接口改名与改上层例化作为同一个动作提交,这个报错就基本与你绝缘。