3.【Verilog】Verilog 门延迟
第一步分析与整理Verilog 门延迟1. 门延迟基础1.1 为什么需要门延迟实际门电路有传输延迟Verilog 允许用户在门级单元例化时指定延迟使仿真更接近真实硬件行为。1.2 三种基本延迟类型延迟类型定义示例上升延迟 (rise delay)输出从0, x, z变为1的时间开启晶体管下降延迟 (fall delay)输出从1, x, z变为0的时间关断晶体管关断延迟 (turn-off delay)输出从0,1,x变为z的时间三态门进入高阻to_x 延迟输出变为x所需时间取上述三种延迟的最小值。多输入门与门、或门最多只定义 2 个延迟输出不会变z。三态门、MOS 开关可以定义 3 个延迟。上下拉pullup/pulldown无延迟。tran双向开关无延迟tranif1/0可定义 1 或 2 个延迟开通/关断延迟。1.3 延迟指定格式gate_type [delay] [instance_name] (signal_list);1.3.1 延迟个数与含义延迟个数上升下降关断to_x000001 (d)dddd2 (d1, d2)d1d2min(d1,d2)min(d1,d2)3 (d1, d2, d3)d1d2d3min(d1,d2,d3)示例and #(1) (OUT1, IN1, IN2); // 所有延迟1 or #(2.1, 2) (OUT2, IN1, IN2); // 上升2.1下降2关断min(2.1,2)2 bufif0 #(2, 1, 1.3) (OUT3, IN1, CTRL); // 上升2下降1关断1.31.3.2 最小/典型/最大延迟min:typ:max模拟工艺波动仿真时可选择使用最小值、典型值或最大值。语法#(min:typ:max)或#(min1:typ1:max1, min2:typ2:max2, ...)示例and #(1:2:3) (OUT1, IN1, IN2); // 所有类型: min1, typ2, max3 or #(1:2:3, 3:4:5) (OUT2, IN1, IN2); // 上升: 1:2:3; 下降: 3:4:5; 关断: min(1,3):min(2,4):min(3,5) 1:2:3 bufif0 #(1:2:3, 3:4:5, 2:3:4) (OUT3, IN1, CTRL); // 上升:1:2:3; 下降:3:4:5; 关断:2:3:42. D 触发器的门级建模带门延迟2.1 基础结构演进理解原理SR 触发器由两个与非门交叉耦合真值表S0,R1 → Q1S1,R0 → Q0S1,R1 → 保持S0,R0 → 禁止QQ’1带使能的 SR 锁存器增加两个与非门EN0 时保持EN1 时与 SR 触发器相同。D 锁存器在 SR 锁存器的 D 输入加反相器使 S 和 R 互补当 EN1Q D当 EN0保持。电平触发在 EN1 期间输出随 D 变化。D 触发器上升沿或下降沿触发– 主从结构两级 D 锁存器级联时钟反相连接。主锁存器在 CP1 时采样透明从锁存器在 CP0 时锁存输出。最终实现仅在时钟下降沿本例是下降沿采样 D 并保持一个周期。2.2 门级 D 触发器 Verilog 模型带延迟参数完整模块D_TRI如下保留原文代码module D_TRI( input D, CP, output Q, QR); parameter RISE_TIME 0.11 ; parameter FALL_TIME 0.07 ; //part1, not gate wire CPN, DN ; not #(RISE_TIME, FALL_TIME) (CPN, CP); not #(RISE_TIME, FALL_TIME) (DN, D); //part2, master trigger wire G3O, G4O ; nand #(RISE_TIME, FALL_TIME) (G3O, D, CP); nand #(RISE_TIME, FALL_TIME) (G4O, DN, CP); wire #(RISE_TIME, FALL_TIME) G1O, G2O ; // 这里wire的延迟原文如此但实际应该是无延迟可能是笔误 nand #(RISE_TIME, FALL_TIME) (G1O, G3O, G2O); nand #(RISE_TIME, FALL_TIME) (G2O, G4O, G1O); //part3, slave trigger wire G7O, G8O ; nand #(RISE_TIME, FALL_TIME) (G7O, G1O, CPN); nand #(RISE_TIME, FALL_TIME) (G8O, G2O, CPN); wire G5O, G6O ; nand #(RISE_TIME, FALL_TIME) (G5O, G7O, G6O); nand #(RISE_TIME, FALL_TIME) (G6O, G8O, G5O); assign Q G5O ; assign QR G6O ; endmodule注意原文中wire #(RISE_TIME, FALL_TIME) G1O, G2O ;这种写法并不常见wire 通常不带延迟可能是教程笔误实际门延迟已在nand实例中给出。我们在教学时应强调延迟应附在门实例上。2.3 Testbench 与仿真结果timescale 1ns/1ps module test ; reg D, CP 0 ; wire Q, QR ; always #5 CP ~CP ; // 周期10ns占空比50% initial begin D 0 ; #12 D 1 ; #10 D 0 ; #14 D 1 ; #3 D 0 ; #18 D 0 ; end D_TRI u_d_trigger( .D(D), .CP(CP), .Q(Q), .QR(QR) ); initial begin forever #100 if ($time 1000) $finish ; end endmodule仿真结果分析Q即G5O在 CP 下降沿采样 D 的值并保持到下一个下降沿。QR 是 Q 的反相因为G6O为另一个交叉耦合输出。输出相对时钟下降沿有延迟约 360ps由门级延迟累积而成。延迟追踪原文对cap3时刻的分析CP → CPN上升延迟 110psCPN → G8O下降延迟 70psG8O → G6O上升延迟 110psG6O → Q下降延迟 70ps总和 360ps与设置的RISE_TIME0.11ns, FALL_TIME0.07ns匹配。第二步费曼教学法 – 通俗讲解门延迟与 D 触发器费曼技巧核心用最简单的比喻把复杂概念讲得连外行也能听懂。作为验证工程师会告诉你这些东西在实际工作中哪里用得上怎么用踩过哪些坑一、门延迟给数字电路加上“时间标尺”1.1 为什么需要门延迟想象你设计了一个电路仿真时所有信号瞬间变化0延迟。但真实芯片里信号从一个门传到另一个门需要时间。如果没有延迟你会发现时序检查setup/hold无法进行竞争冒险看不到综合后的网表仿真与 RTL 行为不一致加入延迟后仿真能更真实地反映硬件行为提前发现时序问题。1.2 三种延迟的生活化比喻延迟类型比喻上升延迟你推一个秋千从地面0到最高点1需要的时间下降延迟秋千从最高点回到地面的时间关断延迟水龙头从关紧到完全没水的“断流时间”为什么有上升和下降之分因为晶体管导通输出1和截止输出0的电阻不同时间也不同。比如 NMOS 拉低快PMOS 拉高快。1.3 如何指定延迟记住“个数含义”1个数通通一样懒人模式2个数第一个上升第二个下降关断取两者最小3个数上升、下降、关断分别指定你可能会犯的错误给and门写了 3 个延迟 → 语法错误因为and输出不会变z。给tranif1写了 3 个延迟 → 也是错误它最多 2 个开通/关断。工作中如何应用在门级网表仿真GLSGate Level Simulation时库文件.lib或.v会为每个标准单元提供延迟值你不需要手动写。但在教学或简单模型中自己加延迟可以观察时序逻辑的行为。1.4 最小/典型/最大延迟应对芯片制造波动同一个芯片因工艺偏差有的批次跑得快最小延迟有的慢最大延迟。你可以这样仿真// 选择快模型 define FAST // 或者仿真器选项 mindelays / typdelays / maxdelays这样做的好处验证电路在**最差max情况下是否满足时序在最快min**情况下是否出现保持时间违例。二、D 触发器的门级建模从最简电路一步步搭出来2.1 为什么要学这个工作中又不用门级搭触发器你说得对现在没有人手画 6 个与非门做一个 DFF。但是理解原理知道为什么 DFF 是边沿触发为什么有 setup/hold 要求。调试底层当你仿真一个 PLL 或 IO 单元时可能会看到门级网表。写延时模型有时需要自己写一个带延迟的简单触发器用于测试。学习路线SR 触发器 → SR 锁存器 → D 锁存器 → D 触发器主从这是一个循序渐进的智力体操理解后你会对“时序”有通透的认识。2.2 核心主从结构为什么能实现边沿触发主锁存器时钟高电平透明像个打开的窗户从锁存器此时因为时钟反相它是锁住的窗户关着当时钟下降沿到来瞬间主锁存器立即锁住窗户关闭固定了当时的 D 值从锁存器变为透明窗户打开把主锁存器的值传出去结果只有下降沿那一刻 D 的值被采样其他时间输出不变。关注点延迟参数RISE_TIME和FALL_TIME作用于每个与非门。输出延迟累积从 CP 变化到 Q 变化的路径上有多个门总延迟 各门延迟之和。2.3 仿真波形的现实意义图中 CP 下降沿后Q 并没有立刻变化而是过了 360ps 才变。这在实际时序分析中叫Clock-to-Q 延迟Tckq。验证工程师需要知道这个延迟是否影响下游电路的建立时间工作中如何学习跑一下这个示例用 VCS/Icarus Verilog 仿真打开波形。修改延迟参数比如把RISE_TIME改大看 Q 的变化如何滞后。尝试自己搭一个上升沿触发的 DFF只需把 CP 和 CPN 交换。三、验证工程师的实战心法3.1 门延迟在什么场景下真正重要场景说明门级网表仿真GLS逻辑综合后的网表包含标准单元延迟必须用 SDFStandard Delay Format反标进行时序仿真。IO 电路建模比如 PAD 模型需要指定输入到输出的延迟、三态使能延迟。异步电路分析判断毛刺是否会产生错误触发。培训与教学理解时序基础。3.2 常见误区和调试技巧误区1以为延迟指定多了就能自动处理所有情况。实际上门延迟只是传输延迟惯性延迟不包含线延迟。精确时序要用 SDF。误区2在 RTL 代码中使用#delay。这是仿真延迟不可综合而门级延迟如nand #(2,3) (…)是建模延迟两者不要混淆。调试技巧当你发现门级仿真波形与 RTL 不一致首先检查timescale设置是否1ns/1ps然后看延迟值是否过大导致信号在某个时间窗口内为x。3.3 如何将这部分知识融入工作学会读标准单元库的 Verilog 模型里面会有bufif0 #(DELAY_RISE, DELAY_FALL) …这样的描述。掌握 SDF 反标$sdf_annotate(design.sdf, top_module);这是验证工程师的必备技能。写简单的带延迟的激励模型比如模拟一个外部芯片的输出延迟assign #(5,3) ext_data (ctrl) ? int_data : 1bz;总结一句话记住门延迟与 D 触发器门延迟给每个门加上“时间标签”让仿真接近真实D 触发器的主从结构是边沿触发的本质。工作中直接面对的是带 SDF 的网表但理解这些原理能让你快速定位时序问题。建议学习路径手打 D 触发器代码跑仿真看波形。改变RISE_TIME和FALL_TIME观察总延迟变化。用$display打印每次 Q 变化的时间验证延迟累计。思考如果给nand只写两个延迟关断延迟会取哪个值尝试将 D 触发器改为上升沿触发并测试。当你遇到一个门级仿真失败你能说出“可能是时钟路径的上升延迟过大导致数据在下降沿之前没准备好” —— 这节就没白学。