延迟反标注是设计者根据单元库工艺、门级网表、版图中的电容电阻等信息,借助数字设计工具将延迟信息标注到门级网表中的过程。利用延迟反标注后的网表,就可以进行精确的时序仿真,使仿真更接近实际工作的数字电路。
前面教程中的仿真基本都是功能性的仿真。无论是进行 IC 设计还是 FPGA 开发,时序仿真都是必不可少的。《Verilog 教程》的《1.4 Verilog 设计方法》章节中也描述了完整的数字设计开发流程。
下面,说明延迟反标注在该流程中是怎么使用的,权当复习与巩固。
此过程示意图如下,标黄部分表示数字设计流程中可以增加的操作说明。

SDF (Standard Delay Format),标准延时格式文件,常用延迟反标注。该文件包含了仿真用到的所有 IOPATH,INTERCONNECT、TIMING CHECK 等延迟时间和时序约束的参数。下面就简单的介绍下 SDF 文件。
SDF 文件用关键字 DELAYFILE 声明,并包含 DESIGN、DATE 等关键字信息。
延迟时间和时序约束参数均在 CELL 内说明。
SDF 文件就是由文件声明信息和很多个不同的 CELL 组成的,格式如下。
(DELAYFILE
(DESIGN "top")
(DATE "Love Sep 7 11:11:11 2017")
......
(TIMESCALE 1ns)
(CELL
......
)
(CELL
......
)
......
)
SDF 文件中的延迟类型包括 cell delay 和 wire delay。cell delay 指逻辑门单元器件内部的延迟,wire delay 是指器件之间通过 wire 互联的延迟。
cell delay 描述如下,定义了 module "and_gate" 中输入端口(A/B)与输出端口(Z)的上升延迟和下降延迟,并指定了最小值和最大值。
(CELL
(CELLTYPE "and_gate") //module 名字
(INSTANCE u_and) //例化名字,如果多层次访问需要指定访问层次
(DELAY
(ABSOLUTE
(IOPATH A Z (1.5::1.8) (1.3::1.7)) //上升延迟最小值1.5,最大值1.8
(IOPATH B Z (1.5::1.8) (1.3::1.7)) //下降延迟最小值1.3,最大值1.7
)
)
)
wire delay 描述如下,定义了在 module "top" 中,从 u_and 输出端到 u_dt 输入端的上升延迟和下降延迟,并指定了最小值和最大值。
一般 RTL 级仿真或综合出的门级网表是可以忽略 wire delay的,因为后端还需要重新布局布线。布局布线后的网表就接近真实的电路,此时就需要考虑 wire delay。
(CELL
(CELLTYPE "top") //module 名字
(INSTANCE) //如果是顶层设计模块,可忽略例化名字
(DELAY
(ABSOLUTE
(INTERCONNECT u_and.Z u_dt.D (0.500::0.751) (0.400::0.551))
//(INTERCONNECT u_and/Z u_dt/D (0.500::0.751) (0.400::0.551))
//层次访问符号,有的编译器支持".",有的编译器支持"/",这里需要注意
)
)
)
CELL 中还可以用关键字 COND 指定条件延迟。
同时,也可以在 CELL 内做时序检查。
一个 D 触发器的延迟说明及时序检查举例如下。
(CELL
(CELLTYPE "d_gate")
(INSTANCE u_dt)
(DELAY
(ABSOLUTE
// D=1时 上升延迟为1.3-2.3, 下降延迟为1.5-2.2
(COND D==1'b1 (IOPATH CP Q (1.3::2.3) (1.5::2.2)))
// D=0时 上升延迟为1.2-2.1, 下降延迟为1.4-2.0
//此处只是为了说明 COND 的用法,D=1时下降延迟参数不可能用到
// D=0时上升延迟参数也不可能用到
(COND D==1'b0 (IOPATH CP Q (1.2::2.1) (1.4::2.0)))
)
)
(TIMINGCHECK
(SETUP D (posedge CP) (0.8::1))
//setup check, D-CP 时间小于0.8或1时,便打印 violation
)
)
Verilog 提供了系统函数 $sdf_annotate 去调用 SDF 文件完成延迟反标注的过程。
使用格式如下:
$sdf_annotate ('sdf_file'[, module_instance] [,'sdf_configfile'][,'sdf_logfile'][,'mtm_spec'] [,'scale_factors'][,'scale_type']);
这里,sdf_file 必须指定,其余参数可选。
这里只对前几个常用的参数进行说明。
下面使用 specify 进行简单的时序仿真,以便与使用 SDF 文件进行时序仿真做对比。
一个用 specify 指定延迟的与门逻辑描述如下:
module and_gate(
output Z,
input A, B);
assign Z = A & B ;
specify
specparam t_rise = 1.3:1.5:1.7 ;
specparam t_fall = 1.1:1.3:1.6 ;
(A, B *> Z) = (t_rise, t_fall) ;
endspecify
endmodule
一个用 specify 指定延迟的 D 触发器描述如下:
module d_gate(
output Q ,
input D, CP);
reg Q_r ;
always @(posedge CP)
Q_r <= D ;
assign Q = Q_r ;
specify
if (D == 1'b1)
(posedge CP => (Q +: D)) = (1.3:1.5:1.7, 1.1:1.4:1.9) ;
if (D == 1'b0)
(posedge CP => (Q +: D)) = (1.2:1.4:1.6, 1.0:1.3:1.8) ;
$setup(D, posedge CP, 1);
endspecify
endmodule
顶层模块描述如下,主要功能是将与逻辑的输出结果输入到 D 触发器进行缓存。
module top(
output and_out,
input in1, in2, clk);
wire res_tmp ;
and_gate u_and(res_tmp, in1, in2);
d_gate u_dt(and_out, res_tmp, clk);
endmodule
testbench 描述如下,仿真时设置 "+maxdelays",使用最大延迟值。
`timescale 1ns/1ps
module test ;
wire and_out ;
reg in1, in2 ;
reg clk ;
initial begin
clk = 0 ;
forever begin
#(10/2) clk = ~clk ;
end
end
initial begin
in1 = 0 ; in2 = 0 ;
# 32 ;
in1 = 1 ; in2 = 1 ;
# 13 ;
in1 = 1 ; in2 = 0 ;
end
top u_top(
.and_out (and_out),
.in1 (in1),
.in2 (in2),
.clk (clk));
initial begin
forever begin
#100;
if ($time >= 1000) $finish ;
end
end
endmodule // test
仿真时序如下所示,由图可知:
综上所述,仿真结果符合设计参数。

保持关于 SDF 文件的例子中涉及的参数不变,将多个 CELL 说明整合成完整的 SDF 文件,命名为"simple_test.sdf"。
在 testbench 中加入以下语句,将 SDF 文件中的延迟信息反标注到设计的模块 top 中,重新进行时序上的仿真。
initial begin
$sdf_annotate("../rtl/simple_test.sdf", u_top, , "sdf.log", "MAXIMUM", ,);
end
仿真时序及 log 打印信息如下,由图可知:
综上所述,仿真结果符合设计参数,但是时序存在 violation。主要原因是因为与门输入端的数据和触发器时钟是异步不相关的。为解决此类异步问题,请参考下一章节《4 章:同步与异步》。


需要说明的是:
与 specify 块语句相比,SDF 文件还可以指定模块间 wire delay。
一般来说,使用 SDF 文件指定版图级的网表 timing 信息最接近实际数字电路,相比 rtl 或综合出的门级网表,此版本的 timing 是最差的。
SDF 文件指定模块内路径延迟时,原模块的 specify 块必须保留,且 specify 块与 SDF 文件中指定的延迟的条件、类型等均需一致,延迟值可以不同。例如在 specify 块中无条件指定延迟:
(A => Z) = (1.3, 1.7) ;
在 SDF 文件中指定条件延迟:
(COND A==1'b1&&B==1'b1 (IOPATH A Z (1.5::1.8) (1.3::1.7)))
则在编译阶段就会报告"IOPATH from A to Z is not found."的 SDF Warning。SDF 文件设置的延迟是无效的。此处 SDF 文件也应该使用无条件的方法指定路径延迟。
本次只是为了介绍 SDF 文件及其用法而手动编写的 SDF 文件。实际上 SDF 文件都是由设计人员借助 IC 设计工具(例如 PrimeTime)生成的,上一条注意事项也无需太过担心,调试时注意就好。一般数字设计的门级网表数量巨大,人为写 SDF 文件也不切实际。
是否可以在所有delayed_job任务之前运行一个方法?基本上,我们试图确保每个运行delayed_job的服务器都有我们代码的最新实例,所以我们想运行一个方法来在每个作业运行之前检查它。(我们已经有了“check”方法并在别处使用它。问题只是关于如何从delayed_job中调用它。) 最佳答案 现在有一种官方方法可以通过插件来做到这一点。这篇博文通过示例清楚地描述了如何执行此操作http://www.salsify.com/blog/delayed-jobs-callbacks-and-hooks-in-rails(本文中描述
目录一、inout在设计文件中的使用方法1.1、inout的第一种使用方法1.2、inout实现的第二种使用方法1.3、inout使用总结 二、inout在仿真测试中的使用方法一、inout在设计文件中的使用方法在FPGA的设计过程中,有时候会遇到双向信号(既能作为输出,也能作为输入的信号叫双向信号)。比如,IIC总线中的SDA信号就是一个双向信号,QSPIFlash的四线操作的时候四根信号线均为双向信号。在Verilog中用关键字inout定义双向信号,这里总结一下双向信号的处理方法。1.1、inout的第一种使用方法 实际上,双向信号的本质是由一个三态门组成的,三态门可以输出高电平,低电
我有一些使用delayed_job的小程序。在我的本地主机上一切正常,但是当我将我的应用程序部署到Heroku并单击应该由delayed_job执行的链接时,没有任何反应,“任务”只是保存到表delayed_job中。Inthisarticleonherokublog写入时,执行delayed_job表中的任务,当运行此命令时rakejobs:work。但是我怎样才能运行这个命令呢?命令应该放在哪里?在代码中,还是从终端控制台? 最佳答案 如果您正在运行Cedar堆栈,请从终端控制台运行以下命令:herokurunrakejobs:
我是一个尝试使用delayed_job的NOOB。我想在使用延迟作业成功发送邮件后更新用户模型。发送邮件:UserMailer.delay.welcome_email(user)如果邮件发送成功,请执行以下操作:User.update_attributes(:emailed=>true)邮件发送成功后如何回调或触发? 最佳答案 您需要创建一个Job对象而不是调用#delay帮助程序。您可以使用successHook来执行回调。classWelcomeEmailJob 关于ruby-on-
我在运行多个工作器的设置中使用延迟作业。就我的问题而言,这并不重要,但假设我有10个worker(目前在开发模式下这样做)。我遇到的问题是两个不同的工作人员有时会开始处理同一个工作,调用我的工作对象的perform方法。据我所知,DelayedJob正在使用悲观锁定来防止这种情况发生,但有时它似乎仍然有足够的时间在第一个worker有时间实际锁定它之前锁定它。我只是想看看有没有其他人遇到过这个问题,或者是我的设置有问题。我正在使用Postrgres,这发生在我的开发机器和我托管它的Heroku上。我会尝试在我的工作中解决这个问题,但发生这种情况仍然有点问题。理想情况下,延迟作业永远不会
defperformrefund_log={success:refund_retry.success?,amount:refund_amount,action:"refund"}ifrefund_retry.success?refund_log[:reference]=refund_retry.transaction.idrefund_log[:message]=refund_retry.transaction.statuselserefund_log[:message]=refund_retry.messagerefund_log[:params]={}refund_retry.er
我正在使用DelayedJob来管理后台工作。但是我有一些任务需要定期执行。例如每小时、每天或每周。现在,当我执行任务时,我会创建一个新任务,在一天/一周/一个月内执行。不过我不是很喜欢。如果由于任何原因,任务没有完全执行,我们不会创建下一个任务,我们可能会失去任务的执行。您如何在Rails应用程序中管理此类事情(延迟作业)以确保您的常规任务列表保持正确? 最佳答案 如果你可以访问Cron,我强烈推荐Wheneverhttp://github.com/javan/whenever您指定要运行什么以及在简单的ruby中以什么频率运
我正在构建一个与RubyonRails后端对话的iPhone应用程序。RubyonRails应用程序还将为Web用户提供服务。restful_authentication插件是提供快速和可定制的用户身份验证的绝佳方式。但是,我希望iPhone应用程序的用户在新列中存储一个由手机的唯一标识符([[UIDevicedevice]uniqueIdentifier])自动创建的帐户。稍后,当用户准备好创建用户名/密码时,帐户将更新为包含用户名和密码,iPhone唯一标识符保持不变。用户在设置用户名/密码之前不能访问该网站。然而,他们可以使用iPhone应用程序,因为该应用程序可以使用它的标识符
Delayed::Job将您的类、方法和参数序列化到处理程序字段中。我们目前求助于将这种序列化方法硬编码到我们的代码中。这太恶心了。我们应该如何构建处理程序以便我们可以查找现有的排队作业? 最佳答案 这是我做的:1)添加两个新列到delayed_jobs表db/migrations/20110906004963_add_owner_to_delayed_jobs.rbclassAddOwnerToDelayedJobs2)添加多态关联到Delayed::Job模型config/initializers/delayed_job.rbc
如何在ruby中产生延迟?我使用了sleep语句,但它没有给我想要的东西。puts"amit"sleep(10)puts"scj"我希望它先打印amit,然后延迟10秒,然后打印scj。但在上述情况下,它会暂停10秒,然后同时打印amit和scj。我不想这样。我希望你明白我想说的。 最佳答案 我无法重现这个。在控制台中,这完全符合您的预期:puts"amit"sleep10puts"scj"(Linux上的Ruby1.8.6)您能否提供一个类似的简短但完整的示例,该示例没有做您想要的-或者更多地解释您的上下文?如果您正在编写Web应