Verilator TIMESCALEMOD:跨模块 timescale 不一致怎么修
Verilator TIMESCALEMOD 出现在同一次编译只有部分模块声明 timescale 时。它不是单纯提醒源码风格不统一:缺省模块里的 #1 究竟是一纳秒还是一皮秒,可能取决于前置指令、文件顺序或工具默认值。本文用 Verilator 5.020 复现并修复,与 Verilator TIMESCALEMOD 相邻的 NEEDTIMINGOPT 延时策略问题 分开讨论。
本文要回答的问题
- 为什么
-Wall下仍可能看不到TIMESCALEMOD,需要怎样显式启用? - 报错中的两个源码位置分别说明什么,文件顺序为何重要?
- 怎样给缺省模块补声明,并用最小延时测试证明时间语义正确?
--timing、-Wno-fatal和--timescale-override各自解决什么问题?
这张图强调第二步:不能直接复制离得最近的 timescale。单位应由设计时序约定决定;补上声明只是消除歧义,延时测试才负责确认这个选择与预期一致。
一、完整报错:缺省模块与已声明模块同时出现
最小工程有顶层 timescalemod_top 和叶子 timescalemod_leaf。顶层声明 1ns/1ps,叶子文件直接从 module 开始。调用时把叶子文件排在前面,使它之前没有可继承的时间单位指令,并显式启用告警:
verilator --lint-only -Wall -Wwarn-TIMESCALEMOD --timing \
--top-module timescalemod_top \
broken/timescalemod_leaf.sv broken/timescalemod_top.svVerilator 5.020 的完整诊断如下。主位置是缺少声明的叶子模块,附加位置指向拥有 timescale 的顶层;末尾说明一个告警在当前策略下使进程退出 1。
%Warning-TIMESCALEMOD: broken/timescalemod_leaf.sv:1:8: Timescale missing on this module as other modules have it (IEEE 1800-2017 3.14.2.3)
1 | module timescalemod_leaf (
| ^~~~~~~~~~~~~~~~~
broken/timescalemod_top.sv:3:8: ... Location of module with timescale
3 | module timescalemod_top;
| ^~~~~~~~~~~~~~~~
... For warning description see https://verilator.org/warn/TIMESCALEMOD?v=5.020
... Use "/* verilator lint_off TIMESCALEMOD */" and lint_on around source to disable this message.
%Error: Exiting due to 1 warning(s)
broken lint exit=1这个版本的 TIMESCALEMOD 默认关闭,单加 -Wall 的同一用例实测退出 0,因此要加 -Wwarn-TIMESCALEMOD。--timing 则是因为用例含 #delay;它负责启用时序调度,不会补全时间单位。没有它时出现的 NEEDTIMINGOPT 是另一个问题。
二、根因:timeunit 决定数值,timeprecision 决定刻度
`timescale 1ns/1ps 的斜杠前是时间单位,斜杠后是时间精度。于是 #1 表示 1ns,#0.5 也能按 1ps 刻度表示;若单位变成 1ps,同样的 #1 就缩短为一千分之一。告警关心的是声明缺失,并不知道哪个数值才符合设计。
| 写法或选项 | 实际作用 | 不能替代的判断 |
|---|---|---|
`timescale 1ns/1ps | 当前及后续模块采用 1ns 单位、1ps 精度 | 这个单位是否符合接口约定 |
-Wwarn-TIMESCALEMOD | 让部分模块缺声明时可见 | 不会推断或修复单位 |
-Wno-fatal | 告警保留但不直接令编译失败 | 不会消除继承与默认值歧义 |
--timescale-override | 强制覆盖本次编译的时间单位 | 覆盖成错误单位仍会错误仿真 |
文件顺序也不能忽略。指令影响其后的模块;有声明文件在前时,缺省文件可能继承前一个单位,顺序反过来则可能落到工具默认值。一次仿真碰巧正确,不能证明换构建入口、拆分文件列表后仍正确。
三、排查清单:先还原单位来源,再改源码
按下面路径处理。红色表示歧义根因,蓝色是核对动作,橙色是修复,绿色代表语义检查通过,紫色是应固化到构建配置的动作。
实际检查可分四项:列出所有编译源文件及顺序;逐个搜索模块声明前的 timescale;核对延时数值对应的接口建立时间、脉冲宽度或超时;确认所有 lint 入口都显式启用同一告警策略。第三方模型若不能改,应在工程边界统一单位并验证,而不是局部关掉告警。
有一种看似省事的做法是在顶层加一条 lint_off TIMESCALEMOD,让后续日志恢复安静。它只适合已经审查过、确实有意混合声明的局部源码,不能作为跨文件缺省的默认处理。压制后,告警主位置提供的“哪个模块没写”也随之消失;下次新增文件或调整文件列表时,团队失去了发现单位漂移的机会。即使确需豁免,也应把范围限制到具体模块,并在附近说明该模块为何不含延时或为何由外部统一指定单位。
还要区分单位一致与精度一致。两个模块都使用 1ns 单位,不代表它们必须选择相同精度,但精度差异会让亚单位延时经历不同的舍入。排错时应把 #delay、周期计算、超时计数放在一起审查:若某个检查依赖 0.5ns,而精度被改成 1ns,即使单位看起来没变,时刻也可能不再是原值。对这类设计,修复后的测试应覆盖非整数延时,而不只观察最后是否打印 PASS。
四、修复代码:给叶子模块显式补上 1ns/1ps
缺省版本只有功能代码,#1 的单位没有本地依据:
module timescalemod_leaf (
output logic pulse
);
initial begin
pulse = 1'b0;
#1;
pulse = 1'b1;
end
endmodule本例接口要求脉冲在 1ns 时升高,因此修复是在文件首行增加与工程一致的声明,功能语句不变:
`timescale 1ns/1ps
module timescalemod_leaf (
output logic pulse
);
initial begin
pulse = 1'b0;
#1;
pulse = 1'b1;
end
endmodule顶层用绝对时间写检查:0.5ns 时 pulse 必须仍为 0,再等待 1.0ns 后必须为 1。检查使用 #0.5ns 和 #1.0ns,避免反例修改单位时连检查基准也一起漂移。这样测试锁定的不是“过了若干刻度”,而是真实的物理时刻。
五、复跑结果:lint 通过还不够,错误单位会被测试抓住
下面的同次运行记录包含缺省报错、修复零诊断和后续仿真;命令头与容器内实际执行入口一致。
修复 lint 退出 0,修复仿真输出 PASS 并退出 0。缺省版本另加 -Wno-fatal 后也能碰巧通过,因为它这次落到了默认 1ns;这正是不能只看 PASS 的原因。反例保持修复源码不变,仅用 --timescale-override 1ps/1ps 强制全工程改成 1ps,叶子的上升沿提前到 1ps,顶层在 500ps 检查点立即发现错误。
PASS: pulse stayed low through 0.5ns and rose by 1.5ns
- fixed/timescalemod_top.sv:22: Verilog $finish
fixed build exit=0
fixed simulation exit=0
[500] %Fatal: timescalemod_top.sv:13: Assertion failed in TOP.timescalemod_top: FAIL: pulse changed before 1ns
%Error: fixed/timescalemod_top.sv:13: Verilog $stop
Aborting...
wrong-unit build exit=0
wrong-unit simulation exit=134
PASS: TIMESCALEMOD reproduced; explicit units fixed lint; forced 1ps failed simulation最后的 PASS 是复现脚本已核对全部预期状态,包括反例必须非零退出;它不表示 1ps 仿真通过。正确修复仍是源码中显式写 1ns/1ps,而不是用覆盖选项把错误单位推广到全工程。
实验环境
- 机器/系统:Intel x86_64 Mac / macOS 26.5.2,实验在
geek-eda:0.2容器中运行。 - 工具版本:Verilator 5.020 2024-01-01 rev (Debian 5.020-1)。
- 日期:2026-10-30。
- 完整命令:
docker run --rm -v "$PWD":/work -w /work geek-eda:0.2 make run;脚本依次执行缺省与修复的 lint、两组正常仿真,以及--timescale-override 1ps/1ps反例。
代码获取
跨文件源码、复现脚本、Makefile 与完整原始输出见公开仓 experiments/ts-verilator-warn-timescalemod。进入目录后运行上述容器命令即可复现,make clean 可删除编译产物。
这一篇在知识体系里的位置
本篇属于 EDA 报错排查系列 的时间单位一致性节点,处理“有些模块声明、有些没有”的 TIMESCALEMOD。若工具转而指出源码含延时却未选择调度策略,应继续阅读 Verilator TIMESCALEMOD 之外的 NEEDTIMINGOPT 排查;两者可先后出现,但补时间单位和启用 --timing 不是同一件事。
总结
Verilator TIMESCALEMOD 的根因是部分模块缺少 timescale,让裸延时依赖继承顺序或默认值。Verilator 5.020 中需用 -Wwarn-TIMESCALEMOD 显式启用;给缺省模块补上经过时序确认的 1ns/1ps 后,lint 与仿真均通过。强制 1ps 的反例在 500ps 检查点失败,说明单位是功能语义而非排版风格,修复必须同时用告警退出码和关键沿测试验收。