01signal.com

Quartus:SDC 文件中 derive_pll_clocks 的重要性

引言

在逻辑设计中,只要用 PLL 从一个时钟生成另一个时钟,通常都会指望时序工具自己算出频率,并弄清楚不同时钟之间的时序关系。

然而在 Intel 的 Quartus 中,默认并不是这样。要让工具做这件事,必须在 SDC 约束文件中加入 derive_pll_clocks 命令。事实上,任何由工具自动生成的 SDC 文件里,几乎都会有这条命令。

但可怕的地方在这里:如果漏掉了 derive_pll_clocks,你可能会期望工具为 PLL 生成的时钟正确地施加时序约束(timing constraints);另一个可能的期望,是根本不给这些时钟施加任何约束。不幸的是,实际情况完全不同:正如下面所见,工具确实会对这些时钟做时序计算,但使用的约束是错误的。这样一来,你可能会以为时序约束已经满足、一切正常,但实际上没有一件事做对。

一个例子

假设 FPGA 的输入接的是一个 48 MHz 的振荡器(因此周期是 20.833 ns),PLL 会生成一个 240 MHz 的时钟(即周期 4.166 ns)。

先看一个简单、写得很规矩的 SDC 文件,内容如下:

create_clock -name root_clk -period 20.833 [get_ports {osc_clock}]

derive_pll_clocks
derive_clock_uncertainty

注意,这个文件里有 derive_pll_clocks 命令。

现在来看一条路径(path)上的时序报告,这条路径位于两个寄存器之间,并由 PLL 生成的时钟驱动。报告中最值得关注的部分用红色标出:

+-------------------------------------------------------------------------------------------------------------------------------------------------+
; Data Arrival Path                                                                                                                               ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+
; Total   ; Incr     ; RF ; Type ; Fanout ; Location               ; Element                                                                      ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+
; 0.000   ; 0.000    ;    ;      ;        ;                        ; launch edge time                                                             ;
; 4.937   ; 4.937    ;    ;      ;        ;                        ; clock path                                                                   ;
;   0.000 ;   0.000  ;    ;      ;        ;                        ; source latency                                                               ;
;   0.000 ;   0.000  ;    ;      ; 1      ; PIN_B12                ; osc_clock                                                                    ;
;   0.000 ;   0.000  ; RR ; IC   ; 1      ; IOIBUF_X19_Y29_N8      ; osc_clock~input|i                                                            ;
;   0.667 ;   0.667  ; RR ; CELL ; 2      ; IOIBUF_X19_Y29_N8      ; osc_clock~input|o                                                            ;
;   2.833 ;   2.166  ; RR ; IC   ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|inclk[0]                     ;
;   1.119 ;   -1.714 ; RR ; COMP ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|observablevcoout             ;
;   1.119 ;   0.000  ; RR ; CELL ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|clk[0]                       ;
;   3.274 ;   2.155  ; RR ; IC   ; 1      ; CLKCTRL_G13            ; clkrst_ins|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl|inclk[0] ;
;   3.274 ;   0.000  ; RR ; CELL ; 8      ; CLKCTRL_G13            ; clkrst_ins|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl|outclk   ;
;   4.336 ;   1.062  ; RR ; IC   ; 1      ; FF_X40_Y24_N27         ; clkrst_ins|main_state[0]|clk                                                 ;
;   4.937 ;   0.601  ; RR ; CELL ; 1      ; FF_X40_Y24_N27         ; clkrst:clkrst_ins|main_state[0]                                              ;
; 6.774   ; 1.837    ;    ;      ;        ;                        ; data path                                                                    ;
;   5.169 ;   0.232  ;    ; uTco ; 1      ; FF_X40_Y24_N27         ; clkrst:clkrst_ins|main_state[0]                                              ;
;   5.169 ;   0.000  ; FF ; CELL ; 5      ; FF_X40_Y24_N27         ; clkrst_ins|main_state[0]|q                                                   ;
;   5.591 ;   0.422  ; FF ; IC   ; 1      ; LCCOMB_X40_Y24_N24     ; clkrst_ins|Equal1~0|dataa                                                    ;
;   6.002 ;   0.411  ; FR ; CELL ; 1      ; LCCOMB_X40_Y24_N24     ; clkrst_ins|Equal1~0|combout                                                  ;
;   6.370 ;   0.368  ; RR ; IC   ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst_ins|the_register|d                                                    ;
;   6.774 ;   0.404  ; RR ; CELL ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst:clkrst_ins|the_register                                               ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+

+-------------------------------------------------------------------------------------------------------------------------------------------------+
; Data Required Path                                                                                                                              ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+
; Total   ; Incr     ; RF ; Type ; Fanout ; Location               ; Element                                                                      ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+
; 4.166   ; 4.166    ;    ;      ;        ;                        ; latch edge time                                                              ;
; 9.005   ; 4.839    ;    ;      ;        ;                        ; clock path                                                                   ;
;   4.166 ;   0.000  ;    ;      ;        ;                        ; source latency                                                               ;
;   4.166 ;   0.000  ;    ;      ; 1      ; PIN_B12                ; osc_clock                                                                    ;
;   4.166 ;   0.000  ; RR ; IC   ; 1      ; IOIBUF_X19_Y29_N8      ; osc_clock~input|i                                                            ;
;   4.833 ;   0.667  ; RR ; CELL ; 2      ; IOIBUF_X19_Y29_N8      ; osc_clock~input|o                                                            ;
;   6.912 ;   2.079  ; RR ; IC   ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|inclk[0]                     ;
;   5.119 ;   -1.793 ; RR ; COMP ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|observablevcoout             ;
;   5.119 ;   0.000  ; RR ; CELL ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|clk[0]                       ;
;   7.187 ;   2.068  ; RR ; IC   ; 1      ; CLKCTRL_G13            ; clkrst_ins|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl|inclk[0] ;
;   7.187 ;   0.000  ; RR ; CELL ; 8      ; CLKCTRL_G13            ; clkrst_ins|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl|outclk   ;
;   8.199 ;   1.012  ; RR ; IC   ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst_ins|the_register|clk                                                  ;
;   8.736 ;   0.537  ; RR ; CELL ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst:clkrst_ins|the_register                                               ;
;   9.005 ;   0.269  ;    ;      ;        ;                        ; clock pessimism removed                                                      ;
; 8.985   ; -0.020   ;    ;      ;        ;                        ; clock uncertainty                                                            ;
; 8.890   ; -0.095   ;    ; uTsu ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst:clkrst_ins|the_register                                               ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+

注意报告中带引号的 latch edge time(锁存沿时间)那一行。这个数值表示的是某个时钟沿在穿过时钟网络(并累加时钟缓冲器和布线的延时)之后,成为驱动接收寄存器的那个时钟的时刻。由于这条路径的两个寄存器使用的是同一个时钟的同一个上升沿,所以 latch edge time 就该等于时钟周期。报告里也的确写着 4.166 ns。到目前为止,一切都很正常。

然而,灾难来了

现在再看看,如果漏掉 derive_pll_clocks 命令会发生什么。也就是说,SDC 文件变成这样:

create_clock -name root_clk -period 20.833 [get_ports {osc_clock}]

derive_clock_uncertainty

对同一条路径(path),时序报告却变成:

+-------------------------------------------------------------------------------------------------------------------------------------------------+
; Data Arrival Path                                                                                                                               ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+
; Total   ; Incr     ; RF ; Type ; Fanout ; Location               ; Element                                                                      ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+
; 0.000   ; 0.000    ;    ;      ;        ;                        ; launch edge time                                                             ;
; 4.937   ; 4.937    ;    ;      ;        ;                        ; clock path                                                                   ;
;   0.000 ;   0.000  ;    ;      ;        ;                        ; source latency                                                               ;
;   0.000 ;   0.000  ;    ;      ; 1      ; PIN_B12                ; osc_clock                                                                    ;
;   0.000 ;   0.000  ; RR ; IC   ; 1      ; IOIBUF_X19_Y29_N8      ; osc_clock~input|i                                                            ;
;   0.667 ;   0.667  ; RR ; CELL ; 2      ; IOIBUF_X19_Y29_N8      ; osc_clock~input|o                                                            ;
;   2.833 ;   2.166  ; RR ; IC   ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|inclk[0]                     ;
;   1.119 ;   -1.714 ; RR ; COMP ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|observablevcoout             ;
;   1.119 ;   0.000  ; RR ; CELL ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|clk[0]                       ;
;   3.274 ;   2.155  ; RR ; IC   ; 1      ; CLKCTRL_G13            ; clkrst_ins|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl|inclk[0] ;
;   3.274 ;   0.000  ; RR ; CELL ; 8      ; CLKCTRL_G13            ; clkrst_ins|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl|outclk   ;
;   4.336 ;   1.062  ; RR ; IC   ; 1      ; FF_X40_Y24_N19         ; clkrst_ins|main_state[0]|clk                                                 ;
;   4.937 ;   0.601  ; RR ; CELL ; 1      ; FF_X40_Y24_N19         ; clkrst:clkrst_ins|main_state[0]                                              ;
; 6.765   ; 1.828    ;    ;      ;        ;                        ; data path                                                                    ;
;   5.169 ;   0.232  ;    ; uTco ; 1      ; FF_X40_Y24_N19         ; clkrst:clkrst_ins|main_state[0]                                              ;
;   5.169 ;   0.000  ; FF ; CELL ; 5      ; FF_X40_Y24_N19         ; clkrst_ins|main_state[0]|q                                                   ;
;   5.583 ;   0.414  ; FF ; IC   ; 1      ; LCCOMB_X40_Y24_N24     ; clkrst_ins|Equal1~0|datab                                                    ;
;   5.994 ;   0.411  ; FR ; CELL ; 1      ; LCCOMB_X40_Y24_N24     ; clkrst_ins|Equal1~0|combout                                                  ;
;   6.361 ;   0.367  ; RR ; IC   ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst_ins|the_register|d                                                    ;
;   6.765 ;   0.404  ; RR ; CELL ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst:clkrst_ins|the_register                                               ;
+---------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+

+--------------------------------------------------------------------------------------------------------------------------------------------------+
; Data Required Path                                                                                                                               ;
+----------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+
; Total    ; Incr     ; RF ; Type ; Fanout ; Location               ; Element                                                                      ;
+----------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+
; 20.833   ; 20.833   ;    ;      ;        ;                        ; latch edge time                                                              ;
; 25.672   ; 4.839    ;    ;      ;        ;                        ; clock path                                                                   ;
;   20.833 ;   0.000  ;    ;      ;        ;                        ; source latency                                                               ;
;   20.833 ;   0.000  ;    ;      ; 1      ; PIN_B12                ; osc_clock                                                                    ;
;   20.833 ;   0.000  ; RR ; IC   ; 1      ; IOIBUF_X19_Y29_N8      ; osc_clock~input|i                                                            ;
;   21.500 ;   0.667  ; RR ; CELL ; 2      ; IOIBUF_X19_Y29_N8      ; osc_clock~input|o                                                            ;
;   23.579 ;   2.079  ; RR ; IC   ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|inclk[0]                     ;
;   21.786 ;   -1.793 ; RR ; COMP ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|observablevcoout             ;
;   21.786 ;   0.000  ; RR ; CELL ; 1      ; PLL_3                  ; clkrst_ins|altpll_component|auto_generated|pll1|clk[0]                       ;
;   23.855 ;   2.069  ; RR ; IC   ; 1      ; CLKCTRL_G13            ; clkrst_ins|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl|inclk[0] ;
;   23.855 ;   0.000  ; RR ; CELL ; 8      ; CLKCTRL_G13            ; clkrst_ins|altpll_component|auto_generated|wire_pll1_clk[0]~clkctrl|outclk   ;
;   24.867 ;   1.012  ; RR ; IC   ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst_ins|the_register|clk                                                  ;
;   25.404 ;   0.537  ; RR ; CELL ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst:clkrst_ins|the_register                                               ;
;   25.672 ;   0.268  ;    ;      ;        ;                        ; clock pessimism removed                                                      ;
; 25.572   ; -0.100   ;    ;      ;        ;                        ; clock uncertainty                                                            ;
; 25.477   ; -0.095   ;    ; uTsu ; 1      ; DDIOOUTCELL_X41_Y24_N4 ; clkrst:clkrst_ins|the_register                                               ;
+----------+----------+----+------+--------+------------------------+------------------------------------------------------------------------------+

整个分析过程仍然一模一样,只是它假定时钟周期是 20.833 ns(请再次注意报告中的 latch edge time)。可以发现,时序分析确实走过了 PLL,但完全忽略了 PLL 的输出是另一个频率这一事实。它就好像在说:你忘了 derive_pll_clocks 命令?没关系。我们就假装 PLL 的输入时钟直接穿过去了。

坦白说,我想不出任何场景下这种行为是合理的。要么干脆不要用 PLL 的时钟来计算这些路径的时序,要么就正确地算。但只是把原始时钟的周期硬套上去,算是怎么回事?而且,这些被算错的路径既不会出现在未约束路径汇总(unconstrained path summary)里,也没有任何其他迹象会提醒你,时序已经错得离谱。

为工具说句公道话:时序分析其实会就这个问题产生警告,但其中没有一条达到严重警告(critical warning)级别,所以很容易在 FPGA 工具总是产生的那一大堆警告中漏掉它们。

结论

本页由机器从英文翻译而来。如有疑问,请参阅原文。
Copyright © 2021-2026. All rights reserved. (852e87d4)