Yosys select 命令匹配不到对象:空选择集静默成功与 -assert-min 硬断言排查
更新时间:2026-11-11。长尾速查篇,属于 EDA 报错排查系列,汇总入口见 开源 EDA 报错排查导航。在综合脚本里写
select top/u_missing/*想圈定一批对象做后续处理,Yosys 既不中止也不报错,脚本一路绿灯跑完——等到下游命令对着空选择集干活,结果才悄悄走样。这正是 Yosys select 命令匹配不到对象时最反直觉的地方。
首屏答案:Yosys 0.33 里普通 select 匹配不到对象不是硬错误,只输出一行 Warning: Selection "u_missing/*" did not match any object.,进程退出码仍是 0;接上 stat 也一样,只警告、不出统计。想让空匹配当场失败,必须显式加 select -assert-min 1 <表达式>,此时空选择集才会抛出 ERROR: Assertion failed: selection contains 0 elements, less than the minimum number 1 并以退出码 1 中止。本例根因是 top 模块内根本没有 u_missing 这个子层级,把表达式改成真实层级 top/* 后同一断言通过。
这张漏斗对应本文的排查顺序:先分清你看到的是软警告还是硬错误,再判断设计里到底有没有加载模块,最后才核对 select 表达式的层级拼写。跳过前两层直接改路径,容易把「设计为空」和「路径写错」两类不同问题混在一起。
本文要回答的问题
- Yosys select 命令匹配不到对象时,0.33 版本的真实输出是什么,退出码是多少?
- 为什么脚本里 select 写错了路径,整条综合流程依然返回成功?
select -assert-min的硬断言文案长什么样,怎样让空匹配在 CI 里当场失败?top/u_missing/*这种层级表达式按什么规则匹配,和「设计本身是空的」怎么区分?
一、完整报错原文
实验设计只有一个模块 top,内部是一级反相加一级触发器,没有任何子模块例化,自然不存在 u_missing 这个层级:
module top(input clk, input d, output q);
wire n1;
assign n1 = ~d;
reg r;
always @(posedge clk) r <= n1;
assign q = r;
endmodule针对同一个不存在的路径 top/u_missing/*,依次跑四种命令,行为分成三档。第一档,普通 select 静默落空,日志尾部只有一条警告,进程成功退出:
Warning: Selection "u_missing/*" did not match any object.
Warnings: 1 unique messages, 1 total
End of script. Logfile hash: e06a833024, CPU: user 0.03s system 0.00s, MEM: 10.12 MB peak
exit code: 0注意警告文案里引用的是 "u_missing/*",前缀 top/ 被省略,排查时别拿这个串去全文搜路径。第二档,把空选择集传给 stat,Yosys 依然只给软警告,Printing statistics. 之下没有任何统计内容,退出码还是 0:
Warning: Selection "u_missing/*" did not match any object.
3. Printing statistics.
Warnings: 1 unique messages, 1 total
End of script. Logfile hash: afe94baf1a, CPU: user 0.03s system 0.00s, MEM: 10.12 MB peak
exit code: 0第三档才是真正的硬错误。加上 -assert-min 1 要求选择集至少含一个对象,空匹配被断言拦下,脚本立即中止:
ERROR: Assertion failed: selection contains 0 elements, less than the minimum number 1: top/u_missing/*
Selection contains:
exit code: 1Selection contains: 后面一片空白,是断言机制在回显当前选择集的内容——0 个对象,连一行都列不出来。四种行为的对照汇总如下:
| 命令 | 匹配数 | Yosys 反应 | 退出码 |
|---|---|---|---|
select top/u_missing/* | 0 | 一行 Warning 后正常结束 | 0 |
stat top/u_missing/* | 0 | 同款 Warning,无统计输出 | 0 |
select -assert-min 1 top/u_missing/* | 0 | ERROR 断言失败,脚本中止 | 1 |
select -assert-min 1 top/* | 非 0 | 断言通过,脚本跑完 | 0 |
二、工具与版本
本组实验在 Docker 镜像 geek-eda:0.2 内完成,容器系统为 Debian bookworm,Yosys 版本 0.33(git sha1 2584903a060),四条命令统一通过 yosys -p 传入,先 read_verilog top.v,再 synth -top top -run coarse 停在粗综合阶段,最后执行各自的 select 或 stat。
版本层面要记住一个口径:空选择集的静默策略是 select 机制的长期行为,并非 0.33 特有——普通 select 的职责是「设置当前选择集」,匹配不到对象时它认为自己如实完成了一次置空操作,警告只是提醒,不算失败;-assert-min、-assert-max 这类断言选项才是专门留给脚本做硬性校验的开关。换更新的 Yosys 版本,警告与断言的文案可能微调,但「默认软警告、断言才硬失败」的分流不变。
三、根本原因:选择集机制与层级语法
select 是 Yosys 里绝大多数面向对象命令的前置动作:它不修改设计,只按表达式从当前设计里圈出一组 cell、wire 或模块,供后续 stat、show、dump、opt_clean 等命令在这个子集上工作。表达式按路径逐层解析,top/u_missing/* 的含义是「模块 top 之下名为 u_missing 的对象里的全部成员」。解析器先找 top,再找它下面的 u_missing——本例 top.v 只有 assign 和 always,综合后模块内是 $dff 等单元与 wire,没有任何子模块实例,第二步就断了,通配符 * 作用在不存在的父对象上,结果只能是空集。
同一个空集,为什么三档命令反应不同,下图把分流画清楚:
读图抓两条出路:蓝色是正常求值过程,红色空集之后按「有没有断言选项」再分一次叉——不带断言走紫色软警告支路,进程成功返回;带 -assert-min 走红色硬错误支路,退出码 1。绿色支路只属于匹配成功的情况。这解释了为什么错误的 select 在脚本里能潜伏很久:下游命令拿到空选择集,多数同样不报错,只是什么都不做,等发现产出不对时,现场已经离写错路径那一步很远。
还要把「路径写错」和「设计为空」两种零匹配区分开,两者表面现象完全相同,修法却不一样:
红色节点是两类根因的分界:无参数 stat 如果连一个模块都列不出来,问题在设计加载阶段,常见于漏了 read_verilog,或顶层指错导致真模块被 hierarchy 当 unused 删掉,这种情况可对照 Yosys synth 未指定 top 模块 的场景;stat 能列出 top 模块,才是表达式本身的层级或拼写问题,进入紫色核对支路。子模块缺失引发的层级异常,另见 Yosys hierarchy -check 报错排查。
四、排查清单
拿到 did not match any object 警告或断言失败,按下面顺序机械执行:
- 先看退出码与命令形态:末尾
exit code: 0配 Warning 是软提醒,脚本其实没失败;出现Assertion failed加退出码 1 才是硬中止。CI 里只判退出码的话,软警告会被直接放过去。 - 无参数
stat确认设计非空:能列出模块和 wire bit,说明文件已读入、设计存在,问题锁定在 select 表达式;什么都列不出来,回头查read_verilog有没有执行、顶层有没有指对。 select -list <表达式>枚举匹配结果:-list把选择集包含的对象逐行打印,空集一行不出,是验证表达式最直接的手段;实验仓里的坏脚本就用它暴露空匹配。- 逐级拆路径核对层级:把
top/u_missing/*拆成top、top/u_missing两段分别试,哪一级开始空就是哪一级不存在;对照 RTL 源码确认该模块内是否真的例化了子模块——本例top内只有 assign 与 always,任何两级路径都注定落空。 - 检查通配符与对象名拼写:层级存在但对象名拼错时现象相同,注意警告回显的名字会去掉模块前缀,以源码和
select -list的枚举为准。 - 脚本化流程统一加断言:在
.ys脚本或yosys -p流水线里,凡是后续命令依赖某个选择集非空的位置,写成select -assert-min 1 <表达式>,让路径失效在出错的当步暴露,而不是拖到产出阶段。 - 修后复跑闭环:改完表达式必须重跑同一命令,断言通过并见到
End of script与退出码 0 才算完;顺手核对下游stat的统计行是否符合预期,避免「换了个路径但依旧选错对象」。
五、修复代码与复跑确认
坏脚本选择了不存在的层级,修复只动 select 表达式一处:把 top/u_missing/* 换成设计里真实存在的 top/*,断言要求保持不变。两份脚本对照如下:
# select_bad.ys:u_missing 层级不存在,空选择集触发断言失败
read_verilog top.v
synth -top top -run coarse
select -list top/u_missing/*
# select_fixed.ys:top 模块真实存在,top/* 命中模块内全部对象
read_verilog top.v
synth -top top -run coarse
select -list top/*失败路径的终端记录如下,断言把静默空匹配变成了显式 ERROR:
修复后对同一断言换真实层级复跑,脚本正常结束:
第二段记录里没有 Warning、没有 ERROR,End of script 之后退出码 0,与失败段的退出码 1 形成闭环对照。如果修复后 stat 的数字仍然反常(例如 cell 数为 0),那已经不是选择集问题,而是逻辑被优化删除,按 Yosys stat area 0 速查 的路子继续查。
实验环境
- 机器/系统:macOS 宿主机启动 Docker 容器,容器内为 Debian bookworm
- 工具版本:Yosys 0.33(git sha1 2584903a060),镜像
geek-eda:0.2 - 日期:2026-11-11
- 完整命令:在实验目录执行
bash run.sh,脚本依次运行普通 select、stat 空选择、select -assert-min 1 top/u_missing/*(退出码 1)与select -assert-min 1 top/*(退出码 0)四步,并逐条打印退出码。
代码获取
复现用源码(top.v、select_bad.ys、select_fixed.ys、run.sh)与完整运行记录在公开仓 https://github.com/derekzhuo/geek-doc.cn/tree/main/experiments/ts-yosys-select-no-match。容器内一条命令复现全部四个场景:
docker run --rm -v "$PWD":/work -w /work/ts-yosys-select-no-match geek-eda:0.2 bash run.sh这一篇在知识体系里的位置
本篇是 EDA 报错排查系列中 Yosys 选择与层级簇的一员:select 表达式圈错对象看本篇;设计里压根没有加载到模块、顶层指错导致模块被删,看 Yosys synth 未指定 top 模块;子模块缺失触发 hierarchy 校验失败,看 Yosys hierarchy -check 报错排查;选择集没错但 stat 显示 cell 数为 0,看 Yosys stat area 0 速查。整个系列的目录在 开源 EDA 报错排查导航。
总结
Yosys select 命令匹配不到对象时,普通 select 与 stat 只给一行 did not match any object 软警告、退出码 0,空选择集会被脚本默默带走;加上 select -assert-min 1 才能把空匹配升级为退出码 1 的硬 ERROR。排查先用无参数 stat 区分「设计为空」与「路径写错」,再用 select -list 枚举对象、逐级核对层级,本例根因是 top 内没有 u_missing 子层级,改成真实路径 top/* 后同一断言复跑通过;凡是依赖选择集非空的脚本步骤,都应带断言选项,让路径错误当场显形。