Yosys undriven signal 警告:Wire is used but has no driver 排查与修复
更新时间:2026-10-29。属于开源 EDA 排错系列,总入口见 开源 EDA 报错排错中心。用 Yosys 综合自己的 Verilog 设计时,
checkpass 报出一串Warning: Wire <模块>.\<信号> [n] is used but has no driver.——信号被下游消费了,却找不到任何驱动源。这不是可以忽略的噪音:undriven 信号会被当成常量处理,优化器顺着它把下游逻辑一路折叠掉,综合出的网表悄悄变成一坨常数。同系列还处理过 Yosys Warning: width mismatch 这类赋值宽度问题,undriven 比它更隐蔽——宽度不匹配至少逻辑还在,undriven 是逻辑整个消失。
本文要回答的问题
is used but has no driver警告的逐 bit 刷屏格式怎么读?- 复现和定位这条警告要用哪条 Yosys 命令组合?
- 信号怎么会「声明了却没有驱动」?三种常见来源是什么?
- undriven 信号对综合结果的实际伤害是什么?
- 修复时该补驱动还是删信号,怎么判断?
先给结论路径:声明残留 → check 逐 bit 报警告 → 顺着信号名找驱动源 → 补驱动或删信号 → 复跑归零。
一、报错原文与读法
复现设计是一个重构出事故的模块:data_sync 原本是打拍同步链的一级寄存器输出,重构时删掉了寄存器逻辑,但声明和下游的 assign 消费语句留了下来。跑 yosys -p 'read_verilog undriven_bad.v; hierarchy -top undriven_bad; proc; check',check pass 的输出如下。
读这段输出抓三个点。第一,警告按 bit 逐条报:data_sync [7] 到 data_sync [0] 共 8 条,所以一个 8 位悬空信号会刷出 8 行,位宽大的信号刷屏更凶——不要被行数吓到,信号其实只有一个。第二,每条警告带模块限定名 undriven_bad.\data_sync [7],层次设计里这个前缀告诉你信号在哪个模块实例里,直接拿信号名去 RTL 里 grep 就能定位。第三,结尾的 Found and reported 8 problems. 是本模块问题总数,这个数字不归零,设计就带着隐患往下走。
命令组合也值得说一句:read_verilog 读源码,hierarchy -top 钉住顶层模块(多文件工程里不可省,少了它 Yosys 不知道该以谁为根),proc 把 always 块等过程结构降级成通用逻辑——check 必须在 proc 之后跑,否则过程块里的驱动关系还没展开,该报的警告报不出来。这条 read_verilog; hierarchy; proc; check 序列是任何设计进综合前的最小体检,值得做成 alias 或写进 Makefile 的 lint 目标。
二、根本原因:信号怎么会「声明了却没有驱动」
check pass 的职责是找「明显有问题」的结构,undriven 是其中一类:一条 wire/reg 出现在表达式右值或端口连接里(被 used),但全设计没有任何 assign、always 块或子模块输出往它上面写(no driver)。真实项目里它几乎总是这三种来源:
| 来源 | 典型场景 | 判别特征 |
|---|---|---|
| 重构残留 | 删了驱动逻辑(寄存器/assign),声明和下游消费忘了清 | 信号有消费语句、找不到任何写它的代码 |
| 端口漏接 | 子模块实例化时某个输出端口没连,上层却用了同名信号 | 警告信号的驱动本该来自某个子模块端口 |
| 拼写错位 | 驱动写的是 data_syn、消费用的是 data_sync,隐式声明兜底 | 关掉隐式声明(default_nettype none)后变成报错 |
重构残留占绝大多数——删代码时人的注意力在「要删掉什么」,声明行和消费语句散落在文件两端,最容易漏。第三种拼写错位在没有 `default_nettype none 的老代码里尤其阴:Verilog 会给没声明的标识符隐式生成 1 位 wire,拼错的信号名不报错,只是永远没驱动,直到 Yosys check 把它揪出来。
还有一个边界情况要知道:既没驱动也没被消费的信号不会触发这条警告。check 报的是 is used but has no driver——「有人用」才报警;一条 wire 声明后既没人写也没人读,opt_clean 优化时就把它静默删掉了,日志里只有一行 Removed 1 unused wires,连 Warning 都不出。所以 undriven 警告的语义其实是「悬空的信号正在参与你的逻辑」——危险度比纯死代码高一级,这也正是它必须清零的理由。反过来说,如果删残留时把消费语句一起删干净了,信号根本轮不到 check 报警,优化器会自动收尾。
三、综合后果:不只是警告,逻辑会被常量折叠吃光
undriven 信号在综合里的语义是「值不确定」,优化器按最保守方式把它当常量处理,然后常量折叠顺着数据通路一路传染。把上面的坏设计走完整个 synth 流程,stat 的输出非常直观:
4. Printing statistics.
=== undriven_bad ===
Number of wires: 4
Number of wire bits: 25
Number of public wires: 4
Number of public wire bits: 25
Number of memories: 0
Number of memory bits: 0
Number of processes: 0
Number of cells: 0
Warnings: 8 unique messages, 8 total注意 Number of cells: 0——整个模块一个逻辑单元都没剩下。data_sync 没驱动,data_sync & 8'hFF 被折成常量,data_out 直接 tie 到常数,所有组合逻辑失去存在意义被优化器清空。更值得注意的是中间过程:opt_clean 先把悬空的 data_sync 删掉,警告对象随后转移成 data_out [7..0] is used but has no driver——悬空是会传染的,上游一条线没驱动,下游整条通路逐级塌陷。这就是为什么 undriven 警告不能攒着:网表能生成、流程不报错,但功能已经不对了,等到上板或仿真才发现就是数倍的排查成本。
四、排查与修复
拿到警告后的标准动作:
- 提信号名:从警告行提取模块名和信号名(去掉
[n]位选后缀)。 - grep 双向查:在 RTL 里分别搜这个信号的写点(
assign <sig>、always 块左值、子模块端口.port(<sig>))和读点。写点为零即坐实 undriven;多文件工程用grep -rn全目录搜,别只搜警告里那个模块的文件。 - 定性来源:对照上面三类来源判断——有消费无驱动是重构残留;驱动应在子模块端口上是漏接;信号名存在相似拼写是错位。
- 修复二选一:信号有真实功能需求,就把驱动逻辑补回来;信号本就是该删的残留,把声明行和消费语句一起删干净。
- 复跑 check 归零。
本例属于「有功能需求」,修复是把打拍寄存器补回来:
reg [7:0] data_sync;
always @(posedge clk) begin
data_sync <= data_in;
end
assign data_out = data_sync & 8'hFF;对修复版 undriven_fixed.v 复跑同一条 check 命令,问题数归零:
两个配套建议:一是 RTL 文件头加 `default_nettype none,把拼写错位从「隐式 wire + undriven 警告」升级为编译期硬报错,第三类来源直接绝育;二是把 proc; check 挂进 CI 的 lint 阶段,问题数非零即 fail,不让警告有机会攒成遗产。如果设计里出现「读了一个从来没赋值的地方」之外的怪警告——比如模块根本没例化上——参考 Yosys ERROR: no top module 的层次排查思路。
实验环境
- 机器/系统:Mac mini M4 / macOS 15
- 工具版本:Yosys 0.33 (git sha1 2584903a060),运行于
geek-eda:0.2docker 镜像 - 日期:2026-10-29
- 完整命令:
docker run --rm -v "$PWD":/work -w /work geek-eda:0.2 \
yosys -p 'read_verilog undriven_bad.v; hierarchy -top undriven_bad; proc; check'
docker run --rm -v "$PWD":/work -w /work geek-eda:0.2 \
yosys -p 'read_verilog undriven_bad.v; hierarchy -top undriven_bad; synth; stat'
docker run --rm -v "$PWD":/work -w /work geek-eda:0.2 \
yosys -p 'read_verilog undriven_fixed.v; hierarchy -top undriven_fixed; proc; check'代码获取:复现与修复源码在公开仓 geek-doc.cn/experiments/yosys-warning-undriven,含 undriven_bad.v、undriven_fixed.v 与逐条复现命令,本机装有 Yosys 时去掉 docker 前缀直接跑。
这一篇在知识体系里的位置
本篇是开源 EDA 排错簇中「Yosys 综合警告」节点的一页:警告的总入口与分流见 开源 EDA 报错排错中心;同属信号完整性类的 Yosys Warning: width mismatch 处理赋值两侧宽度不齐,undriven 处理的是更上游的问题——信号连驱动都没有。
总结
Yosys undriven signal 警告(Wire ... is used but has no driver)表示信号被消费却没有驱动源,check pass 按 bit 逐条报出;来源九成是重构残留、端口漏接和拼写错位三类。它不能忽略——undriven 信号综合时被 tie 成常量,常量折叠顺着数据通路传染,实测一个 8 位悬空信号能让整个模块综合成 Number of cells: 0。修复按「提信号名 → grep 双向查 → 补驱动或连声明带消费一起删 → 复跑 check 归零」走,配上 default_nettype none 与 CI 里的 proc; check 门槛,这类警告就攒不下来。