Yosys chparam 参数覆盖失败:参数名不存在的 defparam 报错与 stat 复核修复
更新时间:2026-11-11。长尾速查篇,属于 EDA 报错排查系列,汇总入口见 开源 EDA 报错排查导航。在综合脚本里用
chparam -set改模块参数,却收到一条带defparam字样的 ERROR,是 Yosys 用户常见的困惑:命令明明写的是 chparam,报错为什么提 defparam?本文用 Yosys 0.33 的最小设计把这条报错跑透,并给出可照抄的复核流程。
首屏答案:chparam -set DEPTH 8 param_mod 失败,是因为模块 param_mod 只声明了参数 WIDTH,根本没有 DEPTH 这个对象。chparam 在派生阶段按参数名查找对象,找不到就抛出 ERROR: Can't find object for defparam \DEPTH`!并以退出码 1 中止。把名字改成真实参数chparam -set WIDTH 8 param_mod,再用 stat看到Parameter \WIDTH = 8` 与 32 个 wire bit,即确认覆盖生效。
这张漏斗对应本文的排查顺序:先确认报错发生在哪个 pass,再核对模块里真实存在的参数对象,最后才动脚本改名字。跳过中间核对直接试名字,往往会把拼写错误、模块名错误和类型错误混在一起改。
本文要回答的问题
chparam -set覆盖一个不存在的参数名时,Yosys 0.33 的完整报错原文是什么,退出码是多少?- 命令写的是 chparam,为什么报错信息里出现的是 defparam?
- 修复后如何用
stat的输出证明参数确实生效,而不是只看脚本有没有报错? - 命令行的
-D宏定义能不能替代 chparam 做参数覆盖,两者边界在哪?
一、完整报错原文
最小设计只有一个带默认参数的加法器模块,参数名是 WIDTH,默认值 4:
module param_mod #(
parameter WIDTH = 4
) (
input wire [WIDTH-1:0] a,
input wire [WIDTH-1:0] b,
output wire [WIDTH-1:0] y
);
assign y = a + b;
endmodule出错的综合脚本故意去覆盖一个模块里不存在的名字 DEPTH:
read_verilog param_mod.v
chparam -set DEPTH 8 param_mod
stat在容器内执行 yosys -s chparam_bad.ys,read_verilog 阶段一切正常,失败发生在脚本第 2 步。下面是日志中从脚本执行到进程退出的原样摘录:
-- Executing script file `chparam_bad.ys' --
1. Executing Verilog-2005 frontend: param_mod.v
Parsing Verilog input from `param_mod.v' to AST representation.
Generating RTLIL representation for module `\param_mod'.
Successfully finished Verilog frontend.
2. Executing AST frontend in derive mode using pre-parsed AST for module `\param_mod'.
input:0: ERROR: Can't find object for defparam `DEPTH`!
exit code: 1读这段输出抓住两个细节。其一,Verilog 前端已经成功结束,说明源码语法和模块声明没有问题,错误不属于解析期;其二,报错位置是 input:0,阶段名是「AST frontend in derive mode」,也就是 chparam 触发的参数派生阶段,而非 stat——脚本实际上根本没有走到第 3 步。
二、工具与版本
本次全部实验在 Docker 镜像 geek-eda:0.2(Debian bookworm)内完成,Yosys 版本字符串与日志头部一致:
Yosys 0.33 (git sha1 2584903a060)版本信息之所以要先固定,是因为 chparam 的诊断措辞和 pass 编排随版本演进过。本文的报错原文、stat 字段名和退出码只对 Yosys 0.33 这个构建负责;换到其他大版本时,应保留当次完整输出再对照,不能凭本文原文反推。宿主机只负责启动容器,不参与综合。
三、根本原因:chparam 按参数名查找对象
3.1 为什么 chparam 的报错提 defparam
chparam 不是直接改写 RTLIL 里的常量,而是把一次参数覆盖登记到模块的 AST 上,等 hierarchy 派生参数化模块时统一生效。日志里的 $paramod\param_mod\WIDTH=... 命名就是派生模块的产物。这套「稍后在 derive 阶段施加的参数赋值」机制,内部复用的正是 defparam 语义通道。因此当 chparam 给出的名字在目标模块的参数对象表里查不到时,底层抛出的就是 defparam 找不到对象的错误,文案原样带上 defparam 字样。
换句话说,Can't find object for defparam \DEPTH`!的准确含义是:在param_mod的参数对象集合里,没有名为DEPTH的成员。它与源码里是否手写defparam` 语句无关,chparam 只是这条通道的另一个入口。defparam 语句本身在 Yosys 中的行为与版本差异,另见 Yosys defparam 警告/报错排查。
3.2 名字对了,值不对是另一类错误
参数名存在但传入值与参数声明类型不兼容时,Yosys 不会报「找不到对象」,而是在派生求值时给出类型或宽度相关的诊断,排查方向完全不同。这类情况的判据与复现见 Yosys 参数类型不匹配报错排查。先区分「名字查不到」与「名字查到但值不合法」,可以避免在正确的参数名上反复改数值试错。
3.3 chparam 与命令行 -D 的边界
read_verilog -D KEY=VALUE(或等价的命令行 -D)定义的是预处理宏,在 Verilog 前端词法阶段做文本替换,只影响源码中的 `KEY 宏引用与 `ifdef 条件编译。它不知道模块、参数和层次的存在,无法给 parameter WIDTH 赋值。两者的边界可以压成一句话:-D 改的是编译器看到的源码文本,chparam 改的是读入之后模块上的参数对象。需要同一份源码综合出多个参数变体时,正道是 chparam 或实例处的 #() 具名传参,而不是堆叠宏开关。
四、排查清单:先 stat 看名字,再覆盖,再复核
图中蓝色是信息收集动作,灰色菱形位是名字判定,红色是本次故障的失败分支,橙色是修复动作,绿色是复核闭环。对照这张图,落地清单如下:
- 先跑一次只读的 stat:脚本只保留
read_verilog加stat,确认目标模块里参数的准确拼写和默认值,不要凭记忆写 chparam。 - 确认模块名与参数名的归属:chparam 的最后一个位置参数是模块名,参数名必须属于该模块;参数定义在子模块里时,要对子模块名施加覆盖。
- 覆盖后必须再 stat:没有复核的覆盖只是「脚本没报错」,参数值、派生模块名和端口位宽都可能与预期不符。
- 保留失败脚本做对照:坏脚本与修复脚本同仓存放,复跑时两条路径的退出码同时可见,防止以后重命名参数后回归。
五、修复脚本与复跑确认
把参数名改成模块里真实存在的 WIDTH,修复版脚本如下:
read_verilog param_mod.v
chparam -set WIDTH 8 param_mod
stat一次 bash run.sh 顺序执行坏脚本与修复脚本,两相对照。失败路径的终端记录:
修复路径完整跑通,终端记录如下:
修复输出里有三处证据要一起读。第一,chparam 执行时回显 Parameter \WIDTH = 8,随后生成派生模块 $paramod\param_mod\WIDTH=32'...1000,常量编码的低四位正是 8;第二,stat 中 Number of public wire bits: 24,对应三个公开端口 a、b、y 各 8 bit,而默认 WIDTH=4 时只有 12 个公开 bit,位宽随参数一起放大;第三,脚本走到 End of script 并以 exit code: 0 结束。三处同时成立,才能判定覆盖真正生效。
实验环境
- 机器/系统:macOS 宿主机启动 Docker 容器,容器内为 Debian bookworm
- 工具版本:Yosys 0.33(git sha1 2584903a060),镜像
geek-eda:0.2 - 日期:2026-11-11
- 完整命令:在实验目录执行
bash run.sh,脚本依次运行yosys -s chparam_bad.ys与yosys -s chparam_fixed.ys,并打印各自退出码。
代码获取
完整源码、两个 .ys 脚本与复现脚本位于公开仓 https://github.com/derekzhuo/geek-doc.cn/tree/main/experiments/ts-yosys-chparam-override-fail。本地装有 Docker 并取得 geek-eda:0.2 镜像后,在该目录执行 bash run.sh 即可原样复现失败与修复两次运行。
这一篇在知识体系里的位置
本篇属于 开源 EDA 报错排查导航 的 Yosys 参数处理分支,回答「chparam 为什么报 defparam 错」。同簇的 Yosys defparam 警告/报错排查 处理源码中 defparam 语句的版本行为,Yosys 参数类型不匹配报错排查 处理参数名正确但值不合法的情形,三篇合起来覆盖参数覆盖的「名字、语义、类型」三个故障面;Yosys 综合产物的回读核对可参考 Yosys JSON 写回与读回验证,全系列入口见 EDA 报错排查系列。
总结
Yosys chparam 参数覆盖失败,本质是参数名查表失败:chparam 复用 defparam 语义通道在 derive 阶段施加覆盖,模块里没有 DEPTH 这个参数对象时,Yosys 0.33 抛出 ERROR: Can't find object for defparam \DEPTH`! 并以退出码 1 中止。修复不是换写法而是换名字——chparam -set WIDTH 8 param_mod之后,用 stat 同时核对参数回显、派生模块名和公开 wire bit 数,确认位宽从默认 4 放大到 8。命令行-D` 只是预处理宏,替代不了参数对象级别的覆盖。