此页面属于关于时序(timing)的一系列页面。前几页解释了一些基本主题: 时序计算和时钟周期时序约束(clock period timing constraint)背后的理论。还展示并解释了一些时序报告(timing reports)。现在该说说这些知识的一个重要用途了:解决时序问题。
介绍
FPGA 工具最大的挑战是实现时序约束(timing constraints)的要求。这很有希望成功,但有时会失败。当它失败时,是我们人类有责任找出它失败的原因并加以修复。这个任务有一个名字: 我们称之为时序收敛 。这不是一件容易的事。
为什么时序收敛难?问题是,这些工具有一个布局和布线(place and route)算法,试图以最佳方式使用 FPGA的资源。通常,该算法首先会毫不费力地将逻辑单元(logic elements)放在 FPGA 上。然后一个迭代过程开始: 工具会检查所有路径(paths),并找出不符合时序约束的路径。为了纠正这些故障,对这些路径采取纠正措施。最值得注意的是,将逻辑单元移至 FPGA上的不同位置,并调整布线(routing)。至于更高级的纠正措施,每个 FPGA 工具都有自己的方法。
当所有路径都满足时序约束时,实现(implementation)才算完成。但实现也可能因为工具未能达到这一目标而结束,因此放弃了尝试。在这种情况下,我们得到的是工具在努力停止时所取得的成果。这个结果不一定是最佳的: 实现中可能有路径可以改进,但工具正忙于修复其他问题。当失败时,这些工具就放弃了,而没有尝试修复其他问题。就像工具在说: “如果实现无论如何都会失败,那么浪费时间修复它是没有意义的”。
我们作为 FPGA 设计师的任务是查看这个次优结果,并找出时序约束的目标没有实现的原因。
随着时间的推移,算法会变得更好。当存在无法实现时序约束的常见原因时,下一版本的软件将针对该情况提供特定的解决方案。因此,当工具失败时,通常有充分的理由。
所以我们看看这些工具取得了什么成果,并问自己: 为什么工具会失败?我们要求的东西是不可能的吗?更重要的是,我们是否要求了一些不必要的东西?也许导致工具失败的障碍是我们甚至不需要的东西。或许,优化算法效果不佳?有时这只是运气不好的问题: 逻辑单元的初始位置可能非常糟糕,以至于后续提高性能的尝试注定要失败。
不管是什么问题,找到失败的原因都类似于侦探调查犯罪现场: 事实摆在眼前,但原因往往是隐藏的。这些事实中的大部分都可以在时序报告中找到,但线索不会轻易泄露。人们必须经常问的问题是时序报告有什么问题、异常或异常。就像试图找到罪犯的侦探一样,目标是找到导致问题的细节。
但是为了发现什么是异常的,你必须知道什么是正常的: 比如普通的时延(delay)换网络(net)配某扇出(fan-out)是什么?为了实现某个逻辑函数,正常的逻辑级(logic levels)有多少?这类问题的答案因 FPGA 而异。因此,即使一切都很好,也有必要通过阅读和理解时序报告来获得经验。当一切正常时,您必须能够知道时序报告的样子,以便找到时序报告指示问题的地方。如果您想知道我为什么要在前几页中详细介绍,这就是原因之一。
关键路径(Critical Path)
当工具无法实现时序约束时,意味着至少有一条路径(path)具有负 slack。 slack 最负的路径称为关键路径。这个名字反映了时序收敛的惯用策略: 专注于关键路径通常是解决时序问题的方法。但我将在下面证明这种策略也可能是浪费时间。
实现时序约束后,关键路径就是路径加上最小的 slack。这条路径通常并不有趣,因为这些工具不会尝试用积极的 slack来改进路径。因此,如果最差的路径有一个正 slack,那么这条路径竟然是最差的可能是巧合。
但是如果 slack 为正并且接近于零(例如,小于 0.2 ns),这可能表明很难让路径达到时序约束。这种关键路径可以看作是警告,这些路径将来可能会造成麻烦(特别是当 FPGA 被更多的逻辑填满时,工具的努力就会转移到其他路径上)。
时序报告通常包含每个时钟的有限数量的关键路径。大多数 FPGA 工具的默认设置是显示一些关键路径,即使它们的 slack 为正(即当时序约束实现时)。这是推荐设置。
关键路径的一个例子
我将从关键路径的分析示例开始。本例 Verilog 代码如下:
reg [24:0] calc, result;
reg [11:0] x, y, z;
always @(posedge clk)
begin
calc <= x * y + z;
result <= calc;
end
本例中 @clk的频率为 250 MHz,没有使用锁相环(PLL)来生成这个时钟。还假设 @x、 @y 和 @z 是与 @clk同步的寄存器(registers)。没有显示为这些寄存器赋值的 Verilog 代码,因为它不相关。
在 Vivado上尝试此代码时未实现时序约束。在时序报告中,这是关键路径:
Slack (VIOLATED) : -0.239ns (required time - arrival time) Source: x_reg[1]__0_replica_2/C (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Destination: calc_reg[23]/D (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Path Group: clk Path Type: Setup (Max at Slow Process Corner) Requirement: 4.000ns (clk rise@4.000ns - clk rise@0.000ns) Data Path Delay: 4.180ns (logic 1.642ns (39.282%) route 2.538ns (60.718%)) Logic Levels: 7 (CARRY8=4 LUT3=1 LUT4=1 LUT6=1) Clock Path Skew: -0.087ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 3.176ns = ( 7.176 - 4.000 ) Source Clock Delay (SCD): 3.864ns Clock Pessimism Removal (CPR): 0.601ns Clock Uncertainty: 0.035ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE Total System Jitter (TSJ): 0.071ns Total Input Jitter (TIJ): 0.000ns Discrete Jitter (DJ): 0.000ns Phase Error (PE): 0.000ns Clock Net Delay (Source): 2.032ns (routing 0.396ns, distribution 1.636ns) Clock Net Delay (Destination): 1.748ns (routing 0.365ns, distribution 1.383ns) Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk rise edge) 0.000 0.000 r AG12 0.000 0.000 r clk (IN) net (fo=0) 0.000 0.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.738 0.738 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.105 0.843 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.049 0.892 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.839 1.731 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.101 1.832 r clk_IBUF_BUFG_inst/O X2Y0 (CLOCK_ROOT) net (fo=106, routed) 2.032 3.864 clk_IBUF_BUFG SLICE_X54Y54 FDRE r x_reg[1]__0_replica_2/C ------------------------------------------------------------------- ------------------- SLICE_X54Y54 FDRE (Prop_HFF2_SLICEL_C_Q) 0.137 4.001 r x_reg[1]__0_replica_2/Q net (fo=21, routed) 0.371 4.372 x[1]_repN_2 SLICE_X56Y53 LUT6 (Prop_E6LUT_SLICEL_I1_O) 0.219 4.591 r calc[23]_i_101/O net (fo=2, routed) 0.550 5.141 calc[23]_i_101_n_0 SLICE_X54Y57 CARRY8 (Prop_CARRY8_SLICEL_DI[5]_CO[7]) 0.228 5.369 r calc_reg[23]_i_30/CO[7] net (fo=1, routed) 0.030 5.399 calc_reg[23]_i_30_n_0 SLICE_X54Y58 CARRY8 (Prop_CARRY8_SLICEL_CI_O[1]) 0.163 5.562 r calc_reg[23]_i_22/O[1] net (fo=3, routed) 0.351 5.913 calc_reg[23]_i_22_n_14 SLICE_X56Y57 LUT3 (Prop_C6LUT_SLICEL_I1_O) 0.146 6.059 r calc[23]_i_26/O net (fo=3, routed) 0.240 6.299 calc[23]_i_26_n_0 SLICE_X55Y58 LUT4 (Prop_A6LUT_SLICEM_I0_O) 0.089 6.388 r calc[23]_i_7/O net (fo=1, routed) 0.407 6.795 calc[23]_i_7_n_0 SLICE_X53Y57 CARRY8 (Prop_CARRY8_SLICEM_DI[2]_O[4]) 0.308 7.103 r calc_reg[23]_i_2/O[4] net (fo=1, routed) 0.538 7.641 P[20] SLICE_X54Y56 CARRY8 (Prop_CARRY8_SLICEL_S[4]_O[7]) 0.352 7.993 r calc_reg[23]_i_1/O[7] net (fo=1, routed) 0.051 8.044 P0_out[23] SLICE_X54Y56 FDRE r calc_reg[23]/D ------------------------------------------------------------------- ------------------- (clock clk rise edge) 4.000 4.000 r AG12 0.000 4.000 r clk (IN) net (fo=0) 0.000 4.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.515 4.515 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.066 4.581 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.034 4.615 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.722 5.337 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.091 5.428 r clk_IBUF_BUFG_inst/O X2Y0 (CLOCK_ROOT) net (fo=106, routed) 1.748 7.176 clk_IBUF_BUFG SLICE_X54Y56 FDRE r calc_reg[23]/C clock pessimism 0.601 7.777 clock uncertainty -0.035 7.741 SLICE_X54Y56 FDRE (Setup_HFF_SLICEL_C_D) 0.063 7.804 calc_reg[23] ------------------------------------------------------------------- required time 7.804 arrival time -8.044 ------------------------------------------------------------------- slack -0.239
这条路径的 slack 是 –0.239 ns,所以与时序约束的匹配稍微有点不成功。首先要检查的是这条路径的开头和结尾: 我们查看报告的 header中的“源(Source)”和“目的地(Destination)”,找到 x_reg 和 calc_reg。所以问题的根源显然是这部分:
calc <= x * y + z;
这应该不足为奇,因为它是 Verilog 代码中唯一有意义的操作。在现实生活中,逻辑的哪个部分导致问题并不那么明显。
从时序报告也可以明显看出逻辑级的数量很大: 7。组合路径(combinatorial path)太长了。换句话说, @clk的两个时钟边沿(clock edges)之间要做的事情太多了。
但失败的真正原因是什么?也许是布线导致时延中的 61% ?回想一下,有一条经验法则,即布线时延(routing delay)通常是总时延中的 40% 。那么也许尝试使用 FPGA 工具来获得更好的性能?然而,这不太可能是一个成功的解决方案,因为这些工具通常会在放弃尝试实现路径中的时序约束之前努力工作。
尝试在 @x 和 @calc 之间更改逻辑函数同样是徒劳的: 乘法是必不可少的,所以没有办法用更简单的东西代替。
我将在下一页介绍解决此类问题的其他可能方法。但是在这种情况下,浏览一系列技术将无济于事。这个简单的例子表明,有时我们需要像侦探一样思考。
你的大脑无可替代
阅读时序报告时要问的第一个问题是它有什么异常。在此示例中,答案是组合路径仅由 slices组成: 几乎所有 FPGAs 都有指定的算术单元(DSPs、 ALUs,名称各不相同),它们在请求乘法时使用。实际上, multiply and add 是此类指定逻辑中最常见的功能。所以大多数情况下最简单的解决办法就是让工具使用指定的运算单元。此解决方案的时序报告显示在本页底部。
但我们真正应该问的问题是,为什么使用 slices 而不是指定的运算单元。最常见的原因是 FPGA的所有可用运算单元已被设计的其他部分使用。在这种情况下,必要的更改可能与关键路径根本无关: 也许需要通过从设计中移除一些逻辑来释放一些运算单元。另一种可能性是指示工具在设计的不同部分之间以不同方式分配这些算术单元。
在此示例中,使用 slices 代替算术单元,因为我希望发生这种情况: 我故意关闭了算术单元的使用(使用 Vivado的综合工具参数(synthesizer parameters)之一: 我将 max_dsp 设置为零)。但这并不会使此示例显得不自然。有时,错误的参数(parameters)与 FPGA 工具一起使用,导致这种情况。事实上,故意不使用算术单元有时是正确的,因为它们在设计的其他地方更需要。
因此,简单的解决方案是使用指定的算术单元。但是,如果我们必须使用 slices怎么办?同样,解决方案是间接的。回想一下,有问题的部分是:
calc <= x * y + z;
但请注意,这是紧随其后的:
result <= calc;
如果 @calc 仅用于此行,而不用于其他任何地方,则可以将计算分为两个阶段。这种技术通常称为流水线(pipelining)。所以 Verilog 代码更改为:
reg [24:0] calc, result;
reg [11:0] x, y, z, z_d;
always @(posedge clk)
begin
z_d <= z;
calc <= x * y;
result <= calc + z_d;
end
在此解决方案中, @calc 仅给出乘法结果。 @z 的值仅在下一阶段添加到 @calc 。更准确地说,加操作是在 @calc 和 @z_d之间,因为这个操作发生在一个时钟周期(clock cycle)之后。所以 @result 的值和之前完全一样。
这样解决问题很容易,因为 @result 只是原始 Verilog 代码中 @calc 的延迟副本。在现实生活中,我们通常没有这么幸运。
请注意,关键路径仅涉及 @calc 和 @x。路径中甚至没有提到 @z 。所以这种操作的目的是为了减轻算术运算的负担。或者更准确地说,减少逻辑级的数量。
回想一下,关键路径是执行优化算法后最差的路径。该算法不询问问题的原因。相反,它试图改进具有负 slack的路径。因此,即使问题的解决方案需要对 @z进行操作,与 @z 相关的路径也不是关键路径。这只是一个巧合,但这种情况经常发生。
本方案的时序报告与关键路径也在本页下方展示,显示逻辑级的数量由 7 减少至 6,结果数据路径时延(data path delay)减少了 0.715 ns,满足时序约束绰绰有余。
从这个例子中吸取的教训是,关键路径并不总是问题的直接原因。问为什么这条路径失败仍然是正确的,但解决方案可以在其他地方。请记住,每 FPGA 工具都有自己的实用程序,这些实用程序提供的信息可以帮助找到问题的根本原因。花时间探索这些实用程序并阅读它们的文档是值得的。
尽早避免问题而不是稍后解决问题
如果从一开始就正确地完成逻辑设计,那么时序收敛上的大部分工作都可以避免。这需要持续意识到逻辑设计不是软件这一事实。 Verilog 代码的目的不是在模拟(simulation)期间产生正确的结果。真正重要的是综合工具(synthesizer)从 Verilog 代码生成的输出。
一个好的逻辑设计首先要考虑逻辑应该如何最好地实现其目的。这包括识别与时序相关的潜在障碍。
经验不足的 FPGA 设计师经常通过反复试验开发 Verilog 代码。用模拟看逻辑是否按预期工作,逐步修正,直到模拟输出正确。结果可能是无法在硬件上使用的逻辑: 为了实现时序约束,必须完全重写 Verilog 代码。
提前考虑 Verilog 代码生成的组合路径很重要。这个想法是查看每个寄存器(register),并跟踪组合路径到底。回想一下,组合路径始终以寄存器开始并以寄存器结束。
让我们看一下这个例子:
reg [15:0] a, b;
wire [16:0] x, y;
reg [33:0] z;
assign x = a + 2;
assign y = b + 3;
always @(posedge clk)
z <= x * y;
关于 @a: 当这个寄存器发生变化时,组合路径会首先到达 @x 。但是 @x 不是寄存器。 @x 会通过 continuous assignment进行更新。因此路径会继续到 @z。因此逻辑会在这条组合路径(combinatorial path)中执行两个重要的操作: 算术加法和算术乘法。这太多了吗?是否需要借助流水线将其拆分为两个时钟周期?这取决于时钟频率和使用的 FPGA 。
另一个重要因素是将组合路径变短的难度。有时长组合路径是不可避免的。但是当改进路径的时序很容易时,即使设计中有更差的路径,也要这样做: 如果设计中有几个有问题的路径,工具通常可以通过集中精力解决这些路径来实现时序约束。当很容易满足其他路径的时序要求(timing requirements)时,它会很有帮助。
因此,为了获得实现时序约束的设计,没有允许或不允许的规则。它需要 FPGA 设计的经验才能在该领域做出正确的决定。使用特定 FPGA 工具的经验也很重要。唯一永远正确的规则是: 如果可以通过简单更改 Verilog 代码来改进时序,那就去做吧。不要偷懒,从一开始就做出改变。始终牢记时序。
快速编写逻辑
如前所述,目标是在寄存器之间实现短组合路径: 计算寄存器的下一个值的逻辑函数应该很简单。换句话说,应该需要少量的逻辑级来实现这些逻辑函数。
作为 FPGA 设计师,我们的任务是查看 Verilog 代码并评估逻辑函数的复杂程度。这需要了解综合工具如何将 Verilog 转换为逻辑单元(LUTs 和其他逻辑 primitives(logic primitives))。这些知识是通过经验获得的,部分是通过分析时序报告获得的。使事情变得更加困难的是,这种翻译从一 FPGA 到另一 FPGA 是不同的。因此,编写可产生快速逻辑的 Verilog 代码并非易事。
如果你是 FPGA 的新手,建议花点时间看看实现的成绩,以求学习。时序报告显示了如何将逻辑设计分解为简单的逻辑单元的示例。 FPGA 工具还提供其他用于查看低级逻辑单元的实用程序。
此外,还有一些简单的规则可以提供帮助:
- 流水线: 慷慨地使用寄存器。如果可能,将逻辑的任务分成小块,并在每个步骤后插入一个寄存器。 FPGAs 有很多触发器(flip-flops)(通常每 LUT旁边都有一个触发器(flip-flop)),因此插入寄存器不会增加 FPGA的利用率。避免使用流水线的唯一原因是它使设计变得过于复杂。
- 使用 if-then-else 时,避免链接许多“else”子句。如果可以改用“case”语句,通常效果会更好。 “else”子句通常需要一个逻辑函数,以确保该子句之前的所有内容都是 false。因此,多个“else”子句可能需要多个逻辑级(logic levels)。
- 避免不必要的复位(resets)。特别是,同步复位(synchronous reset)为逻辑函数增加了少量的复杂性。这两种复位都增加了布线的难度,因为这些都是信号,必须达到很多逻辑单元。关于这个主题有一个单独的系列页面。
- 不要创建巨大的状态机(state machines)。状态的数量没有硬性限制。但是如果状态的数量超过了 20,你就要考虑改造你的设计了。此外,请确保综合工具使用 one-hot encoding 用于大型状态机(默认情况下,大多数综合工具使用)。这有助于生成快速的逻辑。
- 在 RAM 之后再加一个寄存器通常会更好。让我们看一下这个隐式创建的 RAM 示例:
reg [7:0] array[0:127]; reg [7:0] val; reg [6:0] addr; always @(posedge clk) val <= array[addr];
此 Verilog 代码是正确的,但请注意, @val 是 RAM的同步输出(synchronous output)。所以当有上升沿(rising clock edge)时, RAM 开始运算,只有从 array 获取到值后, @val 才会更新。因此 @val 具有相对较大的 clock-to-output 时延(与触发器相比)。因此,从 @val开始,路径有一个固有的缺点。这可以通过添加额外的寄存器来解决:
reg [7:0] array[0:127]; reg [7:0] val_d, mem_out; reg [6:0] addr; always @(posedge clk) begin mem_out <= array[addr]; val_d <= mem_out; end
请注意,这在功能上并不等效: @mem_out 在这里就是 RAM 的输出(output)。只有一个时钟后来是这个输出(output)复制到 @val_d,所以它不是 @val的完全替代品。但是 @val_d 是真正的寄存器,低 clock-to-output 时延。在众多的 FPGAs中,这多出的寄存器是 block RAMs的一部分,所以没有浪费触发器。我有没有提到永远不要担心浪费触发器?
不幸的是,添加这样一个寄存器通常会使设计变得相当复杂。在这种情况下,最好不要添加这个额外的寄存器,而是尝试将组合路径与 @val 保持在一起。
两个额外的时序报告
我在上面的“你的大脑无可替代”一节中承诺了两个时序报告(timing reports)。我把它们放在这里,而不是在提到它们的地方,因为它们很长而且不完全相关。
请注意,这两个时序报告中的每一个都是相关场景的关键路径。因此,路径与上面显示的路径不在同一寄存器处开始和结束。
第一个时序报告与第一 Verilog 代码示例相关。与上面的时序报告不同,这些工具可以使用指定的运算单元。结果是轻松实现了时序约束。
此时序报告是为 Kintex Ultrascale FPGA生成的。在 FPGAs这个家族中,一个指定的运算单元被称为 DSP48E2。请注意,路径在同一 DSP48E2 单元上开始和结束。因此逻辑时延(logic delay)是 100%。
Slack (MET) : 1.406ns (required time - arrival time) Source: calc_reg/DSP_A_B_DATA_INST/CLK (rising edge-triggered cell DSP_A_B_DATA clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Destination: calc_reg/DSP_OUTPUT_INST/ALU_OUT[10] (rising edge-triggered cell DSP_OUTPUT clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Path Group: clk Path Type: Setup (Max at Slow Process Corner) Requirement: 4.000ns (clk rise@4.000ns - clk rise@0.000ns) Data Path Delay: 2.445ns (logic 2.445ns (100.000%) route 0.000ns (0.000%)) Logic Levels: 4 (DSP_ALU=1 DSP_M_DATA=1 DSP_MULTIPLIER=1 DSP_PREADD_DATA=1) Clock Path Skew: -0.010ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 3.392ns = ( 7.392 - 4.000 ) Source Clock Delay (SCD): 4.096ns Clock Pessimism Removal (CPR): 0.694ns Clock Uncertainty: 0.035ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE Total System Jitter (TSJ): 0.071ns Total Input Jitter (TIJ): 0.000ns Discrete Jitter (DJ): 0.000ns Phase Error (PE): 0.000ns Clock Net Delay (Source): 2.264ns (routing 0.756ns, distribution 1.508ns) Clock Net Delay (Destination): 1.964ns (routing 0.696ns, distribution 1.268ns) Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk rise edge) 0.000 0.000 r AG12 0.000 0.000 r clk (IN) net (fo=0) 0.000 0.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.738 0.738 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.105 0.843 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.049 0.892 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.839 1.731 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.101 1.832 r clk_IBUF_BUFG_inst/O X2Y1 (CLOCK_ROOT) net (fo=80, routed) 2.264 4.096 calc_reg/CLK DSP48E2_X11Y34 DSP_A_B_DATA r calc_reg/DSP_A_B_DATA_INST/CLK ------------------------------------------------------------------- ------------------- DSP48E2_X11Y34 DSP_A_B_DATA (Prop_DSP_A_B_DATA_DSP48E2_CLK_A2_DATA[9]) 0.302 4.398 r calc_reg/DSP_A_B_DATA_INST/A2_DATA[9] net (fo=1, routed) 0.000 4.398 calc_reg/DSP_A_B_DATA.A2_DATA<9> DSP48E2_X11Y34 DSP_PREADD_DATA (Prop_DSP_PREADD_DATA_DSP48E2_A2_DATA[9]_A2A1[9]) 0.182 4.580 r calc_reg/DSP_PREADD_DATA_INST/A2A1[9] net (fo=1, routed) 0.000 4.580 calc_reg/DSP_PREADD_DATA.A2A1<9> DSP48E2_X11Y34 DSP_MULTIPLIER (Prop_DSP_MULTIPLIER_DSP48E2_A2A1[9]_U[10]) 0.994 5.574 f calc_reg/DSP_MULTIPLIER_INST/U[10] net (fo=1, routed) 0.000 5.574 calc_reg/DSP_MULTIPLIER.U<10> DSP48E2_X11Y34 DSP_M_DATA (Prop_DSP_M_DATA_DSP48E2_U[10]_U_DATA[10]) 0.164 5.738 r calc_reg/DSP_M_DATA_INST/U_DATA[10] net (fo=1, routed) 0.000 5.738 calc_reg/DSP_M_DATA.U_DATA<10> DSP48E2_X11Y34 DSP_ALU (Prop_DSP_ALU_DSP48E2_U_DATA[10]_ALU_OUT[10]) 0.803 6.541 r calc_reg/DSP_ALU_INST/ALU_OUT[10] net (fo=1, routed) 0.000 6.541 calc_reg/DSP_ALU.ALU_OUT<10> DSP48E2_X11Y34 DSP_OUTPUT r calc_reg/DSP_OUTPUT_INST/ALU_OUT[10] ------------------------------------------------------------------- ------------------- (clock clk rise edge) 4.000 4.000 r AG12 0.000 4.000 r clk (IN) net (fo=0) 0.000 4.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.515 4.515 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.066 4.581 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.034 4.615 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.722 5.337 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.091 5.428 r clk_IBUF_BUFG_inst/O X2Y1 (CLOCK_ROOT) net (fo=80, routed) 1.964 7.392 calc_reg/CLK DSP48E2_X11Y34 DSP_OUTPUT r calc_reg/DSP_OUTPUT_INST/CLK clock pessimism 0.694 8.086 clock uncertainty -0.035 8.050 DSP48E2_X11Y34 DSP_OUTPUT (Setup_DSP_OUTPUT_DSP48E2_CLK_ALU_OUT[10]) -0.104 7.946 calc_reg/DSP_OUTPUT_INST ------------------------------------------------------------------- required time 7.946 arrival time -6.541 ------------------------------------------------------------------- slack 1.406
第二个时序报告与 Verilog 代码的第二个示例相关。在本例中,借助流水线,情况得到了改善:
Slack (MET) : 0.433ns (required time - arrival time) Source: y_reg[1]__0/C (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Destination: calc_reg[23]/D (rising edge-triggered cell FDRE clocked by clk {rise@0.000ns fall@2.000ns period=4.000ns}) Path Group: clk Path Type: Setup (Max at Slow Process Corner) Requirement: 4.000ns (clk rise@4.000ns - clk rise@0.000ns) Data Path Delay: 3.465ns (logic 1.653ns (47.706%) route 1.812ns (52.294%)) Logic Levels: 6 (CARRY8=4 LUT4=2) Clock Path Skew: -0.129ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 3.373ns = ( 7.373 - 4.000 ) Source Clock Delay (SCD): 4.040ns Clock Pessimism Removal (CPR): 0.538ns Clock Uncertainty: 0.035ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE Total System Jitter (TSJ): 0.071ns Total Input Jitter (TIJ): 0.000ns Discrete Jitter (DJ): 0.000ns Phase Error (PE): 0.000ns Clock Net Delay (Source): 2.208ns (routing 0.756ns, distribution 1.452ns) Clock Net Delay (Destination): 1.945ns (routing 0.696ns, distribution 1.249ns) Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk rise edge) 0.000 0.000 r AG12 0.000 0.000 r clk (IN) net (fo=0) 0.000 0.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.738 0.738 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.105 0.843 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.049 0.892 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.839 1.731 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.101 1.832 r clk_IBUF_BUFG_inst/O X2Y1 (CLOCK_ROOT) net (fo=121, routed) 2.208 4.040 clk_IBUF_BUFG SLICE_X54Y88 FDRE r y_reg[1]__0/C ------------------------------------------------------------------- ------------------- SLICE_X54Y88 FDRE (Prop_EFF2_SLICEL_C_Q) 0.138 4.178 r y_reg[1]__0/Q net (fo=25, routed) 0.505 4.683 y[1] SLICE_X53Y91 LUT4 (Prop_B6LUT_SLICEM_I0_O) 0.150 4.833 r calc[7]_i_28/O net (fo=1, routed) 0.344 5.177 calc[7]_i_28_n_0 SLICE_X53Y89 CARRY8 (Prop_CARRY8_SLICEM_DI[2]_CO[7]) 0.424 5.601 r calc_reg[7]_i_9/CO[7] net (fo=1, routed) 0.043 5.644 calc_reg[7]_i_9_n_0 SLICE_X53Y90 CARRY8 (Prop_CARRY8_SLICEM_CI_O[0]) 0.122 5.766 r calc_reg[23]_i_30/O[0] net (fo=3, routed) 0.402 6.168 calc_reg[23]_i_30_n_15 SLICE_X51Y88 LUT4 (Prop_C5LUT_SLICEL_I0_O) 0.169 6.337 r calc[15]_i_8/O net (fo=1, routed) 0.437 6.774 calc[15]_i_8_n_0 SLICE_X51Y92 CARRY8 (Prop_CARRY8_SLICEL_DI[1]_CO[7]) 0.422 7.196 r calc_reg[15]_i_1/CO[7] net (fo=1, routed) 0.030 7.226 calc_reg[15]_i_1_n_0 SLICE_X51Y93 CARRY8 (Prop_CARRY8_SLICEL_CI_O[7]) 0.228 7.454 r calc_reg[23]_i_1/O[7] net (fo=1, routed) 0.051 7.505 calc_reg[23]_i_1_n_8 SLICE_X51Y93 FDRE r calc_reg[23]/D ------------------------------------------------------------------- ------------------- (clock clk rise edge) 4.000 4.000 r AG12 0.000 4.000 r clk (IN) net (fo=0) 0.000 4.000 clk_IBUF_inst/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.515 4.515 r clk_IBUF_inst/INBUF_INST/O net (fo=1, routed) 0.066 4.581 clk_IBUF_inst/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.034 4.615 r clk_IBUF_inst/IBUFCTRL_INST/O net (fo=1, routed) 0.722 5.337 clk_IBUF BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.091 5.428 r clk_IBUF_BUFG_inst/O X2Y1 (CLOCK_ROOT) net (fo=121, routed) 1.945 7.373 clk_IBUF_BUFG SLICE_X51Y93 FDRE r calc_reg[23]/C clock pessimism 0.538 7.910 clock uncertainty -0.035 7.875 SLICE_X51Y93 FDRE (Setup_HFF_SLICEL_C_D) 0.063 7.938 calc_reg[23] ------------------------------------------------------------------- required time 7.938 arrival time -7.505 ------------------------------------------------------------------- slack 0.433
差异并不像使用指定算术单元时那么显着。但它仍然足以实现时序约束。
关于时序收敛的一般性讨论到此结束。下一页就此主题提出了几种实用策略。