当前位置: 首页 > news >正文

8.【Verilog】Verilog 时序检查

第一步:分析与整理Verilog 时序检查

1. 时序检查概述

  • 目的:在 specify 块中调用系统任务,检查设计是否存在时序违规(violation),如建立/保持时间、恢复/去除时间、脉冲宽度、周期等。
  • 调用位置:只能在specify…endspecify块内使用这些系统任务。
  • 常用任务$setup$hold$setuphold$recovery$removal$recrem$width$period

2. $setup 和 $hold

2.1 $setup

  • 格式$setup(data_event, ref_event, setup_limit);
    • data_event:被检查的信号(数据)
    • ref_event:参考信号(通常是时钟边沿)
    • setup_limit:最小建立时间要求
  • 违规条件:当(ref_event 时刻 - data_event 稳定时刻) < setup_limit时,报告 violation。
  • 注意:时间差计算方式为参考事件减去数据事件。

2.2 $hold

  • 格式$hold(ref_event, data_event, hold_limit);
    • 参数顺序与$setup不同:第一个是参考事件(时钟),第二个是数据事件。
  • 违规条件:当(data_event - ref_event) < hold_limit时,报告 violation。

2.3 $setuphold

  • 同时检查建立和保持时间:$setuphold(ref_event, data_event, setup_limit, hold_limit);

2.4 示例:乘法15的加法器链并检查时序

全加器模块(full_adder1):指定了路径延迟。

module full_adder1(input Ai, Bi, Ci, output So, Co); assign So = Ai ^ Bi ^ Ci; assign Co = (Ai & Bi) | (Ci & (Ai | Bi)); specify (Ai, Bi, Ci *> So) = 1.1; (Ai, Bi *> Co) = 1.3; (Ci => Co) = 1.2; endspecify endmodule

8位加法器(full_adder8):通过generate例化8个全加器。

8位D触发器(D8):包含时序检查。

module D8(input [7:0] d, input clk, output reg [7:0] q); always @(posedge clk) q <= d; specify $setup(d, posedge clk, 2); // 建立时间要求2ns $hold(posedge clk, d, 3); // 保持时间要求3ns (d, clk *> q) = 0.3; endspecify endmodule

测试平台(test)

  • 产生时钟周期10ns。
  • 生成一个4位计数器num每个时钟加1。
  • 用三个8位加法器实现num * 15 = (num<<3)+(num<<2)+(num<<1)+num。第一级:num<<2+num<<3→ adder1;第二级:num<<1+num→ adder2;第三级:adder1+adder2 → adder3。
  • 最后用 D8 寄存器锁存结果。
  • 仿真结果:出现 setup/hold violation 报告,波形显示建立时间仅1.6ns(<2ns),保持时间2.2ns(<3ns)

2.5 时序优化方法

  • 修改前:一个时钟周期内完成三级加法,延迟太大导致建立时间违例。
  • 优化思路
    • 增大时钟周期(例如20ns)。
    • 增加流水线:在第三级加法前将 adder1 和 adder2 用寄存器缓存一拍,使组合逻辑路径拆分为两个周期。
    • 在 testbench 中用LOGIC_BUF宏控制:加入adder1_bufadder2_buf两级寄存器,同时将num的变化速率减半(通过slow_flag每两拍变化一次)。
  • 优化后结果:建立时间裕量充足(8.6ns),无 violation。

3. $recovery 和 $removal

  • 适用场景:异步复位信号(如rst_n)相对于时钟的恢复时间和去除时间。
  • recovery time(恢复时间):复位释放(从有效到无效)必须在时钟有效沿之前稳定一段时间,类似于 setup。
  • removal time(去除时间):复位有效(从无效到有效)必须在时钟有效沿之后保持一段时间,类似于 hold。
  • 系统任务
    • $recovery(ref_event, data_event, recovery_limit);
      ref_event通常是复位跳变(释放),data_event是时钟沿。当(时钟沿 - 复位释放) < recovery_limit时报违规。
    • $removal(ref_event, data_event, removal_limit);
      ref_event通常是复位跳变(有效),data_event是时钟沿。当(复位有效 - 时钟沿) < removal_limit时报违规。
    • $recrem(ref_event, data_event, recovery_limit, removal_limit);同时检查。

4. $width 和 $period

  • $width:检查脉冲宽度(从上升沿到下一个下降沿,或下降沿到下一个上升沿)。
    • 格式:$width(ref_event, time_limit);
    • 例如:$width(posedge CLK, 10);要求高电平宽度≥10ns。
  • $period:检查周期(从上升沿到下一个上升沿,或下降沿到下一个下降沿)。
    • 格式:$period(ref_event, time_limit);
    • 例如:$period(posedge CLK, 20);要求时钟周期≥20ns。

第二步:费曼教学法 – 通俗讲解时序检查

作为验证工程师。今天我们要学习的是Verilog 中的时序检查系统任务—— 这些任务就像芯片设计中的“红绿灯摄像头”,自动抓拍信号是否按时到达、是否停留足够久。我会用交警指挥交通的比喻帮你理解,然后告诉你如何在自己的设计中应用。

一、为什么需要时序检查?

想象一个十字路口:

  • 建立时间:黄灯亮起前,你必须已经进入路口(数据提前准备好)。
  • 保持时间:绿灯亮起后,你不能马上急刹车,要稳稳通过(数据继续稳定)。
  • 如果违反,就会“撞车”(亚稳态),导致数据错误。

在 Verilog 仿真中,我们不想靠眼睛看波形来判断是否违规,而是让仿真器自动检查并打印报告。这就是$setup$hold这些任务的作用。

二、六种时序检查任务速记表

任务检查内容常用场景比喻
$setup数据在时钟沿前的最小稳定时间同步输入公交车来前你必须站在站台
$hold数据在时钟沿后的最小稳定时间同步输入公交车来后你不能马上走开
$recovery异步复位释放相对于时钟沿的最小提前时间异步复位撤销复位信号要提前于时钟
$removal异步复位有效相对于时钟沿的最小延后时间异步复位施加复位信号要晚于时钟沿保持
$width脉冲高/低电平最小宽度时钟、使能信号绿灯不能闪一下就灭
$period周期信号的最小周期时钟两辆公交车最小间隔

三、逐个击破:语法与实战

3.1$setup$hold– 同步信号的“安全窗口”

例子(来自原文):一个 8 位寄存器 D8,要求建立时间 2ns,保持时间 3ns。

specify $setup(d, posedge clk, 2); $hold(posedge clk, d, 3); endspecify

仿真输出:如果实际时序不满足,会打印:

$setup( d, posedge clk, 2 ) violation= -0.4 ns

关注点

  • $setup的第一个参数是数据,第二个是时钟;$hold的顺序相反。极易写反,要注意!
  • 时间差计算方式不同:$setup(时钟 - 数据变更时刻)$hold(数据变更 - 时钟)
  • 建议使用$setuphold同时检查两者,避免顺序混淆。

为什么这样做?
因为实际芯片的触发器对输入数据有明确的时间窗口要求。不满足就会产生亚稳态,导致输出不可预测。在仿真中提前发现,可以避免流片后失败。

3.2$recovery$removal– 异步复位的“特殊窗口”

为什么复位也要检查?
异步复位信号可以随时拉低,但释放复位(从 0 变 1)的时刻必须离时钟沿足够远,否则触发器可能进入亚稳态。

示例

specify $recovery(negedge rst_n, posedge clk, 1.2); $removal(negedge rst_n, posedge clk, 0.8); endspecify
  • negedge rst_n表示复位释放的边沿(假设低有效)。
  • recovery 要求:在时钟上升沿之前,复位释放至少提前 1.2ns。
  • removal 要求:复位有效(拉低)后,时钟沿之后还要保持 0.8ns 低电平。

工作中常见错误:忘记对异步复位做时序检查,导致仿真中复位释放后立刻采样,工具可能不报错,但实际芯片会偶尔出错。

3.3$width$period– 时钟质量的“体检”

$width:检查一个脉冲的宽度,比如时钟高电平不能太窄,否则触发器可能无法正确采样。

specify $width(posedge clk, 2.5); // 高电平至少 2.5ns $width(negedge clk, 2.5); // 低电平至少 2.5ns endspecify

$period:检查时钟周期,避免时钟频率超出设计上限。

specify $period(posedge clk, 10.0); // 周期至少 10ns endspecify

为什么需要
在系统仿真中,你可能会用外部模型产生时钟,如果时钟频率错误,$period会立刻报警,而不是等到功能出错才发现。

四、完整案例剖析:乘法15电路中的时序优化

4.1 原始设计的问题

  • 工作流程:每个时钟周期,num递增,然后通过三级加法器计算出num*15,最后用 D8 寄存器锁存。
  • 时序路径:从num寄存器的 Q 端,经过三级 8 位加法器(每级有1.1~1.3ns 延迟),最后到 D8 的 D 端。建立时间要求 2ns。
  • 路径延迟估算Tcq(D8本身)+Tcomb(三级加法器)+Tsu。加上加法器内部的路径延迟,10ns 周期很紧张。
  • 仿真结果:建立时间违例(1.6ns < 2ns),保持时间也违例(2.2ns < 3ns)。

保持时间违例原因:数据从 num 寄存器出发,经过组合逻辑太快到达 D8 的 D 端,而 D8 的保持时间要求 3ns,实际数据在时钟沿后 2.2ns 就变了,所以违例。

4.2 优化方法:流水线 + 降低数据速率

改动

  1. 在第三级加法之前,插入两级寄存器adder1_bufadder2_buf,将adder1adder2缓存一拍。
  2. 同时让num每两个时钟周期才变化一次(通过slow_flag分频)。
  3. 这样,从num寄存器到最终data_store的路径被拆成两个周期:
    • 第一周期:num→ 第一、二级加法 →adder1/adder2→ 缓存寄存器
    • 第二周期:缓存寄存器 → 第三级加法 →data_store输入
  4. 每个周期的组合逻辑深度减为原来三分之一,建立时间裕量充足(8.6ns)。

关键:保持时间违例如何解决?
插入的缓冲寄存器增加了数据路径的最小延迟(因为寄存器本身有Tcq),使得data_store的 D 端在时钟沿后能保持更久,满足了保持时间要求。

4.3 工作中的启示

  • 建立时间违例→ 通常降低频率或减少组合逻辑(流水线)。
  • 保持时间违例→ 通常增加数据路径延迟(插入 buffer、使用延迟单元),或调整时钟树(减少 skew)。RTL 设计者一般通过流水线或增加组合逻辑来隐式解决,但更彻底的解决在后端 P&R 阶段。
  • 时序检查任务不仅用于标准单元库,也可以用在你自己写的 IP 行为模型中,向使用者提供时序要求。

五、验证工程师实战指南

5.1 什么时候需要手工写这些检查?

  • 当你在写一个行为模型(比如模拟一个外部 SRAM、Flash 或 DDR 芯片)时,需要在 specify 块中定义时序参数,以便 SoC 仿真时能自动检查。
  • 当你在门级网表仿真中反标 SDF 后,标准单元库自带的时序检查会自动触发。你不需要写,但需要理解报告。

5.2 如何调试时序违例?

  1. 定位违例路径:从仿真 log 中找到具体 violation 信息,确定是$setup还是$hold,涉及哪些信号。
  2. 打开波形:测量实际的时间差,与要求值对比。
  3. 分析原因
    • 建立时间违例:查看数据路径上的组合逻辑是否过深,时钟周期是否太紧。
    • 保持时间违例:查看数据路径是否太短(例如两个寄存器直接连接且时钟 skew 为负)。
  4. 修改设计或约束
    • RTL 优化:插入流水线、拆分运算、调整逻辑级数。
    • 后端约束:调整时钟树、插入延迟单元、修改 SDC 中的set_clock_uncertainty
  5. 重新仿真验证

5.3 常见错误及避免

错误后果正确做法
$setup$hold参数顺序颠倒检查结果完全错误,可能误报或不报牢记:$setup(data, clock, limit)$hold(clock, data, limit)
忘记在 specify 块中写检查仿真不报错,但实际芯片有时序问题所有时序敏感的模块都应包含时序检查
对异步信号使用$setup而不是$recovery无法正确检查恢复/去除时间区分同步和异步信号,使用正确任务
$width的边沿选错(例如检查高电平却用 negedge)检查了低电平宽度明确你想检查高还是低,选择对应的边沿
时序检查的 limit 值过于严格或宽松过度悲观或遗漏真正的违例参考工艺库或数据手册,使用典型值加裕量

5.4 学习路径

  1. 抄写并运行原文中的乘法15例子,观察 violation 报告,熟悉任务语法。
  2. 修改时钟周期从 10ns 改为 20ns,看 setup violation 消失,理解周期与建立时间的关系。
  3. 启用LOGIC_BUF,运行优化后的版本,对比波形差异,理解流水线如何改善时序。
  4. 自己创建一个带异步复位的触发器模型,加入$recovery$removal检查,仿真测试复位释放的边界情况。
  5. 在真实项目的某个模块的 specify 块中添加或修改时序检查,运行回归测试,观察是否出现新的 violation。

六、总结(费曼收尾)

时序检查任务就是数字世界的交通规则摄像头

  • $setup$hold拍下同步信号是否遵守“绿灯前停车、绿灯后慢行”。
  • $recovery$removal拍下异步复位信号是否在正确时间“松手”。
  • $width$period拍下时钟是否“呼吸均匀”。

你作为验证工程师,不需要自己写这些摄像头(除非你在建行为模型),但你要学会读懂监控照片(violation 报告),分析是哪个路口(路径)出了问题,然后告诉设计团队:“这里组合逻辑太深,需要加流水线”或“这里保持时间不够,后端要插 delay cell”。

掌握了这些,你就能在芯片流片前揪出时序隐患,避免“芯片回来后时钟跑不快”或“偶尔复位失败”的悲剧。

http://www.jsqmd.com/news/730219/

相关文章:

  • 告别手搓界面!用GUI Guider给STM32F4快速设计LVGL中文界面(附Keil5移植避坑点)
  • 别再手动做表了!用Excel宏+VBA,5分钟搞定月度成绩报表自动化
  • Dify插件SDK开发指南:从零构建AI工作流扩展工具
  • 靠谱的国企绩效薪酬咨询品牌企业有哪些? - mypinpai
  • ComfyUI-AnimateDiff-Evolved:解锁无限动画创作的专业指南
  • XUnity.AutoTranslator:3步解锁Unity游戏多语言自由
  • Altium Designer 22 保姆级配置指南:从原理图到PCB,这些隐藏设置让你效率翻倍
  • 2026国密改造趋势洞察:头部企业为何纷纷布局国密SSL证书?
  • 目标检测入门踩坑记:YOLO/Detectron2依赖项cython-bbox在Win10上的终极安装指南
  • 2026年3月轮胎批发厂家推荐,外胎/电瓶车轮胎/轻型电动车轮胎/摩托车轮胎/真空胎/电动两轮车真空胎,轮胎生产厂家推荐 - 品牌推荐师
  • 用Python爬虫+Scapy抓包,手把手教你从零搭建一个自己的期末复习资料库(附完整代码)
  • 知识付费小程序怎么搭建?
  • MQTTS连接adafruit平台示例
  • 对比直接使用官方 API,通过 Taotoken 聚合调用带来的管理便利
  • 春季儿童长高攻略:抓住长高黄金期
  • 3D模型渐进式对齐技术Interp3D解析与应用
  • 2026年保姆级教程|4000内全配重电钢琴测评,新手避坑不毁手型
  • AI自动化集成:atlassian-skill实现Jira与Confluence智能操作
  • 失业创业决定:10年程序员,我决定给自己打工
  • 几乎适用于所有传感器——通用数据采集器的接口与测量能力详解|笛远科技
  • 吉林省 CPPM 报名(美国采购协会)SCMP 报名(中物联)授权招生报名中心及联系方式 - 众智商学院课程中心
  • 3步快速上手:Windows虚拟串口驱动完全指南
  • 9.【Verilog】Verilog 延迟反标注
  • 如何彻底解决华硕笔记本显示色彩异常问题:G-Helper终极修复指南
  • AI编程新范式:用cursor-flow实现结构化、可复现的AI辅助开发流程
  • 混合信号IC设计验证:挑战与HiPer仿真解决方案
  • 2026年3M广告灯箱实力厂商调研:聚隆运灯箱为何成为连锁品牌优选解决方案?
  • 大厂不会告诉你的秘密:你的AI对话背后,一半的GPU算力都在“空转”
  • 如何快速上手MIT App Inventor:零基础开发Android和iOS应用的完整指南
  • 【花雕学编程】Arduino BLDC 之机器人双超声波PID跟随系统