动机
在 ISE 的综合器(synthesizer,即 xst)生成的报告底部附近,会写出最大频率是多少,并附上最慢路径(path)的轮廓。这个功能相当不错,特别是当你想要优化某个具体模块时。而用 Vivado 综合之后不会给出这样的数字,可能是因为 Xilinx 的人觉得这个“最大频率”会误导人。如果真是这样,他们有两个充分的理由:
- 并不存在所谓的“最大频率”:工具会关注时序约束(timing constraints),并据此尽力满足。简单地说,如果你不去要求某个频率,你就可能得不到它。
- 在一个典型设计中,通常会同时存在多个频率不同的时钟。最慢的那条路径可能本来就属于一个怎么也快不起来的时钟。
尽管如此,有时在开始完整实现这段漫漫长路之前,先了解一下当前的情况,也仍然是有用的。
如何在 Vivado 中操作
首先也是最重要的:根据你的预期设置好时序约束。或者至少以某种方式让约束清楚地表明哪个时钟重要、哪个时钟可以慢下来。然后对设计执行综合。
综合成功完成后,打开综合后的设计(点击左侧栏中的 “Open Synthesized Design”,或在 Tcl 控制台运行 “open_run synth_1”)。
在 Tcl 窗口中输入命令:
report_timing_summary -file mytiming.rpt
这会把一份完整的综合后时序报告写入 mytiming.rpt。如果只运行 “report_timing_summary”,则会直接把报告打印到控制台上。
左侧栏的 “Synthesized Design” 下也有一个 “Report Timing Summary” 选项,但我发现用 GUI 界面从这份报告中获取信息比较困难。
阅读报告
规则 #1:综合报告充其量只是粗略估计。其中的布线延迟只是猜测。它可能报告时序失败,可是之后的完整实现却照样能通过;它也可能宣称一切良好,可完整实现却会出大问题(特别是当 FPGA 的逻辑资源利用率接近 100% 时)。
现在开始实际操作:首先要看的是 Clock Summary 和 Intra Clock Table,弄清楚 Vivado 给哪个时钟起了哪个名字。例如:
------------------------------------------------------------------------------------------------
| Clock Summary
| -------------
------------------------------------------------------------------------------------------------
Clock Waveform(ns) Period(ns) Frequency(MHz)
----- ------------ ---------- --------------
clk_fpga_1 {0.000 5.000} 10.000 100.000
gclk {0.000 4.000} 8.000 125.000
audio_mclk_OBUF {0.000 41.667} 83.333 12.000
clk_fb {0.000 20.000} 40.000 25.000
vga_clk_ins/clk_fb {0.000 20.000} 40.000 25.000
vga_clk_ins/clkout0 {0.000 1.538} 3.077 325.000
vga_clk_ins/clkout1 {0.000 7.692} 15.385 65.000
vga_clk_ins/clkout2 {0.000 7.692} 15.385 65.000
------------------------------------------------------------------------------------------------
| Intra Clock Table
| -----------------
------------------------------------------------------------------------------------------------
Clock WNS(ns) TNS(ns) TNS Failing Endpoints TNS Total Endpoints WHS(ns) THS(ns) THS Failing Endpoints THS Total Endpoints WPWS(ns) TPWS(ns) TPWS Failing Endpoints TPWS Total Endpoints
----- ------- ------- --------------------- ------------------- ------- ------- --------------------- ------------------- -------- -------- ---------------------- --------------------
clk_fpga_1 3.791 0.000 0 12474 0.135 0.000 0 12474 3.750 0.000 0 5021
gclk 6.751 0.000 0 2
audio_mclk_OBUF 76.667 0.000 0 1
clk_fb 12.633 0.000 0 2
vga_clk_ins/clk_fb 38.751 0.000 0 2
vga_clk_ins/clkout0 1.410 0.000 0 10
vga_clk_ins/clkout1 10.747 0.000 0 215 -0.029 -0.229 8 215 6.712 0.000 0 195
vga_clk_ins/clkout2 3.990 0.000 0 415 0.135 0.000 0 415 7.192 0.000 0 211
如果 Clock Summary 中列出的时钟频率(这些频率来自时序约束)不足以帮你把某个时钟与某个名字对上号,那么 Intra Clock Table 中每个时钟的 TNS Total Endpoints 有助于分清楚谁是谁。等你找到目标时钟的名字后,在报告文件中搜索这个名字,会找到类似下面的内容:
Max Delay Paths -------------------------------------------------------------------------------------- Slack (MET) : 3.791ns (required time - arrival time) Source: xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_offset_limit_1/C (rising edge-triggered cell FDRE clocked by clk_fpga_1 {rise@0.000ns fall@5.000ns period=10.000ns}) Destination: xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0/D (rising edge-triggered cell FDRE clocked by clk_fpga_1 {rise@0.000ns fall@5.000ns period=10.000ns}) Path Group: clk_fpga_1 Path Type: Setup (Max at Slow Process Corner) Requirement: 10.000ns (clk_fpga_1 rise@10.000ns - clk_fpga_1 rise@0.000ns) Data Path Delay: 6.077ns (logic 2.346ns (38.605%) route 3.731ns (61.395%)) Logic Levels: 8 (CARRY4=3 LUT3=1 LUT4=1 LUT6=3) Clock Path Skew: -0.040ns (DCD - SCD + CPR) Destination Clock Delay (DCD): 0.851ns = ( 10.851 - 10.000 ) Source Clock Delay (SCD): 0.901ns Clock Pessimism Removal (CPR): 0.010ns Clock Uncertainty: 0.154ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE Total System Jitter (TSJ): 0.071ns Total Input Jitter (TIJ): 0.300ns Discrete Jitter (DJ): 0.000ns Phase Error (PE): 0.000ns Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk_fpga_1 rise edge) 0.000 0.000 r PS7 0.000 0.000 r xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/PS7_i/FCLKCLK[1] net (fo=1, unplaced) 0.000 0.000 xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/n_707_PS7_i BUFG (Prop_bufg_I_O) 0.101 0.101 r xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/buffer_fclk_clk_1.FCLK_CLK_1_BUFG/O net (fo=5023, unplaced) 0.800 0.901 xillybus_ins/xillybus_core_ins/bus_clk_w r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_offset_limit_1/C ------------------------------------------------------------------- ------------------- FDRE (Prop_fdre_C_Q) 0.496 1.397 f xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_offset_limit_1/Q net (fo=5, unplaced) 0.834 2.231 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_offset_limit[1] LUT4 (Prop_lut4_I0_O) 0.289 2.520 r xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_lutdi/O net (fo=1, unplaced) 0.000 2.520 xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_lutdi CARRY4 (Prop_carry4_DI[0]_CO[3]) 0.553 3.073 r xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_cy[0]_CARRY4/CO[3] net (fo=1, unplaced) 0.000 3.073 xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_cy[3] CARRY4 (Prop_carry4_CI_CO[3]) 0.114 3.187 r xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_cy[4]_CARRY4/CO[3] net (fo=3, unplaced) 0.936 4.123 xillybus_ins/xillybus_core_ins/unitw_1_ins/Mcompar_n0037_cy[7] LUT6 (Prop_lut6_I4_O) 0.124 4.247 f xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_wr_request_condition/O net (fo=7, unplaced) 0.480 4.727 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_wr_request_condition LUT3 (Prop_lut3_I2_O) 0.124 4.851 r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_flush_condition_unitw_1_wr_request_condition_AND_179_o3_lut/O net (fo=1, unplaced) 0.000 4.851 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_flush_condition_unitw_1_wr_request_condition_AND_179_o3_lut CARRY4 (Prop_carry4_S[2]_CO[3]) 0.398 5.249 f xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_flush_condition_unitw_1_wr_request_condition_AND_179_o2_cy_CARRY4/CO[3] net (fo=21, unplaced) 0.979 6.228 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_flush_condition_unitw_1_wr_request_condition_AND_179_o LUT6 (Prop_lut6_I5_O) 0.124 6.352 r xillybus_ins/xillybus_core_ins/unitw_1_ins/_n03401/O net (fo=15, unplaced) 0.502 6.854 xillybus_ins/xillybus_core_ins/unitw_1_ins/_n0340 LUT6 (Prop_lut6_I5_O) 0.124 6.978 r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0_rstpot/O net (fo=1, unplaced) 0.000 6.978 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0_rstpot FDRE r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0/D ------------------------------------------------------------------- ------------------- (clock clk_fpga_1 rise edge) 10.000 10.000 r PS7 0.000 10.000 r xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/PS7_i/FCLKCLK[1] net (fo=1, unplaced) 0.000 10.000 xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/n_707_PS7_i BUFG (Prop_bufg_I_O) 0.091 10.091 r xillybus_ins/system_i/vivado_system_i/processing_system7_0/inst/buffer_fclk_clk_1.FCLK_CLK_1_BUFG/O net (fo=5023, unplaced) 0.760 10.851 xillybus_ins/xillybus_core_ins/bus_clk_w r xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0/C clock pessimism 0.010 10.861 clock uncertainty -0.154 10.707 FDRE (Setup_fdre_C_D) 0.062 10.769 xillybus_ins/xillybus_core_ins/unitw_1_ins/unitw_1_end_offset_0 ------------------------------------------------------------------- required time 10.769 arrival time -6.978 ------------------------------------------------------------------- slack 3.791
这段文字看起来相当杂乱,但关键元素已经用红色标了出来。
在下结论之前,务必确认你正在看的是正确的部分:
- 它是 Max Delay Paths 部分。最小延迟路径部分主要用于发现保持时间违规,和最大频率没有关系。
- 还要确认它是正确的时钟。在上面的例子中是 clk_fpga_1。Requirement 行不仅显示了这个时钟的约束(10 ns = 100 MHz),也说明它是从 clk_fpga_1 的一个上升沿到下一个上升沿。
检查完之后,我们来看结果:原本的约束是 10 ns,余量(slack)为 3.791 ns(注意是正值)。这意味着,我们原本可以把要求的时钟周期再缩短 3.791 ns,也依然能满足。所以要求的时钟周期可以是 10 – 3.791 = 6.2090 ns,也就是大约 161 MHz。
因此,对于 clk_fpga_1 来说,“最大频率”问题的简短答案是 161 MHz。但请记住,如果约束改变了,这个数字也可能不一样。
最后补充一点:Data Path Delay 会告诉我们这条最坏路径(worst path)的延迟到底为什么是快还是慢——其中有多少花在逻辑上,又有多少花在(估计的)布线延迟上。后面那份更详细的延迟报告也是一样。如果你想要更详细的信息,可以在请求时序报告时加上 “-nworst” 选项,这样会列出若干条最差路径。这有助于定位并解决时序问题。