从最初学FPGA到现在,遇到过太多bug,但都没有写过博客记录,因为多数问题都比较简单且网上有比较好的答案。
但最近发现一个布局布线的报错,并不是因为逻辑导致的,而是用户不清楚布局布线导致的,且网上基本上相关的解答,因此把原因分析出来。
01 相关问题报错
最近一些群友碰到了如下问题,报错信息为:
[Place 30-719] Sub-optimal placement for a global clock-capable IO pin-IDELAY-BUFG pair. If this sub optimal condition is acceptable for this design, you may use the CLOCK_DEDICATED_ROUTE constraint in the .xdc file to demote this message to a WARNING. However, the use of this override is highly discouraged. These examples can be used directly in the .xdc file to override this clock rule.
< set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets dclk_r] >
u_IDELAYE2 (IDELAYE2.DATAOUT) is locked to IDELAY_X0Y78
and dclk_r_BUFG_inst (BUFG.I) is provisionally placed by clockplacer on BUFGCTRL_X0Y1。
图1 place 30-719报错
按照错误提示,在xdc中添加如下约束,然后重新综合、布局布线。
图2 添加约束
然后出现如下错误,很多人可能会直接出现下面的错误,原因都是一样的。 报错信息:
[Place 30-650] Non IO buffer dclk_IBUF_BUFG_inst{BUFG} is driving IDATAIN pin of IDELAY instance u_IDELAYE2. This will lead to unroutable situation. IDATAIN pin of IDELAY instance should always get signal from IO buffer or GND.
[Place 30-99] Placer failed with error: 'Implementation Feasibility check failed, Please see the previously displayed individual error or warning messages for more details.'
Please review all ERROR, CRITICAL WARNING, and WARNING messages during placement to understand the cause for failure.
[Common 17-69] Command failed: Placer could not place all instances
图3 报错信息
上述报错其实很奇怪,因为程序中idelaye2的IDATAIN是连接到FPGA输入管脚的,并没有什么问题,报错不是很准确。
这个错误在网上好像还没有具体的讲解,本文解析一下具体原因,以及如何避免。
02 复现错误
之所以出现这个问题,是由于不了解信号进入fpga的走线,错误使用idelaye信号导致的。
提供如下例程,输入时钟dclk与输入数据din对齐,为了稳定采集输入数据,内部使用idelaye2对dclk延时24.72ns。然后内部使用两个ila,分别查看dclk延时前后采集到的输入数据是否一致。
//--############################################################################################### //--# //--# File Name : top //--# Designer : 数字站 //--# Tool : Vivado 2017.4 //--# Design Date : 2024 //--# Description : //--# Version : 0.0 //--# Coding scheme : GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode) //--# //--############################################################################################### module top ( input clk ,//系统时钟信号; input rst ,//系统复位信号,高电平有效; input dclk ,//串行时钟输入; input din ,//输入数据; output reg dout //输出数据信号; ); reg [9 : 0] din_r ; wire dclk_r ; wire clk_200m ; //例化锁相环,生成idelaye2需要的200MHz时钟信号; clk_wiz_0 u_clk_wiz ( .clk_out1 ( clk_200m ),// output clk_out1 .reset ( rst ),// input reset .clk_in1 ( clk ) // input clk_in1 ); (* IODELAY_GROUP = "IODELAY_0" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL IDELAYCTRL u_IDELAYCTRL ( .RDY ( ),// 1-bit output: Ready output .REFCLK ( clk_200m ),// 1-bit input: Reference clock input .RST ( rst ) // 1-bit input: Active high reset input ); //例化idelaye2对时钟信号进行延时24*78+600=24.72ns; (* IODELAY_GROUP = "IODELAY_0" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL IDELAYE2 #( .CINVCTRL_SEL ("FALSE" ),//Enable dynamic clock inversion (FALSE, TRUE) .DELAY_SRC ("IDATAIN" ),//Delay input (IDATAIN, DATAIN) .HIGH_PERFORMANCE_MODE ("FALSE" ),//Reduced jitter ("TRUE"), Reduced power ("FALSE") .IDELAY_TYPE ("FIXED" ),//FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE .IDELAY_VALUE (24 ),//Input delay tap setting (0-31) .PIPE_SEL ("FALSE" ),//Select pipelined mode, FALSE, TRUE .REFCLK_FREQUENCY (200.0 ),//IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0). .SIGNAL_PATTERN ("CLOCK" ) //DATA, CLOCK input signal ) u_IDELAYE2 ( .CNTVALUEOUT ( ),//5-bit output: Counter value output .DATAOUT ( dclk_r ),//1-bit output: Delayed data output .C ( clk_200m ),//1-bit input: Clock input .CE ( 1'b1 ),//1-bit input: Active high enable increment/decrement input .CINVCTRL ( 'd0 ),//1-bit input: Dynamic clock inversion input .CNTVALUEIN ( 'd0 ),//5-bit input: Counter value input .DATAIN ( 'd0 ),//1-bit input: Internal delay data input .IDATAIN ( dclk ),//1-bit input: Data input from the I/O .INC ( 'd0 ),//1-bit input: Increment / Decrement tap delay input .LD ( 'd0 ),//1-bit input: Load IDELAY_VALUE input .LDPIPEEN ( 'd0 ),//1-bit input: Enable PIPELINE register to load data input .REGRST ( rst ) //1-bit input: Active-high reset tap-delay input ); //移位输出数据; always@(posedge dclk_r)begin {dout,din_r[9:0]} <= {din_r[9:0],din}; end //ila使用延时前的时钟采集din_r的数据; ila_0 u_ila_0 ( .clk (dclk ),// input wire clk .probe0 (din_r ) // input wire [9:0] probe0 ); //ila使用延时后的时钟采集din_r的数据; ila_0 u_ila_1 ( .clk (dclk_r ),// input wire clk .probe0 (din_r ) // input wire [9:0] probe0 ); endmodule
上述例程的逻辑思路和代码大家应该都能够理解,也没有逻辑错误。然后使用vivado创建工程,综合,分配管教脚,最后布局布线。
综合不会出现问题,因为没有逻辑和语法错误,但布局布线后会出现图3的错误,如下图所示。
图4 复现问题
03 分析问题
是不是觉得很离谱?逻辑没问题,为什么布局布线失败。
需要通过正常的工程,才能分析出错误的原因,因此先将两个ila相关的代码注释掉,如下所示。
//--############################################################################################### //--# //--# File Name : top //--# Designer : 数字站 //--# Tool : Vivado 2017.4 //--# Design Date : 2024 //--# Description : //--# Version : 0.0 //--# Coding scheme : GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode) //--# //--############################################################################################### module top ( input clk ,//系统时钟信号; input rst ,//系统复位信号,高电平有效; input dclk ,//串行时钟输入; input din ,//输入数据; output reg dout //输出数据信号; ); reg [9 : 0] din_r ; wire dclk_r ; wire clk_200m ; //例化锁相环,生成idelaye2需要的200MHz时钟信号; clk_wiz_0 u_clk_wiz ( .clk_out1 ( clk_200m ),// output clk_out1 .reset ( rst ),// input reset .clk_in1 ( clk ) // input clk_in1 ); (* IODELAY_GROUP = "IODELAY_0" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL IDELAYCTRL u_IDELAYCTRL ( .RDY ( ),// 1-bit output: Ready output .REFCLK ( clk_200m ),// 1-bit input: Reference clock input .RST ( rst ) // 1-bit input: Active high reset input ); //例化idelaye2对时钟信号进行延时24*78+600=24.72ns; (* IODELAY_GROUP = "IODELAY_0" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL IDELAYE2 #( .CINVCTRL_SEL ("FALSE" ),//Enable dynamic clock inversion (FALSE, TRUE) .DELAY_SRC ("IDATAIN" ),//Delay input (IDATAIN, DATAIN) .HIGH_PERFORMANCE_MODE ("FALSE" ),//Reduced jitter ("TRUE"), Reduced power ("FALSE") .IDELAY_TYPE ("FIXED" ),//FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE .IDELAY_VALUE (24 ),//Input delay tap setting (0-31) .PIPE_SEL ("FALSE" ),//Select pipelined mode, FALSE, TRUE .REFCLK_FREQUENCY (200.0 ),//IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0). .SIGNAL_PATTERN ("CLOCK" ) //DATA, CLOCK input signal ) u_IDELAYE2 ( .CNTVALUEOUT ( ),//5-bit output: Counter value output .DATAOUT ( dclk_r ),//1-bit output: Delayed data output .C ( clk_200m ),//1-bit input: Clock input .CE ( 1'b1 ),//1-bit input: Active high enable increment/decrement input .CINVCTRL ( 'd0 ),//1-bit input: Dynamic clock inversion input .CNTVALUEIN ( 'd0 ),//5-bit input: Counter value input .DATAIN ( 'd0 ),//1-bit input: Internal delay data input .IDATAIN ( dclk ),//1-bit input: Data input from the I/O .INC ( 'd0 ),//1-bit input: Increment / Decrement tap delay input .LD ( 'd0 ),//1-bit input: Load IDELAY_VALUE input .LDPIPEEN ( 'd0 ),//1-bit input: Enable PIPELINE register to load data input .REGRST ( rst ) //1-bit input: Active-high reset tap-delay input ); //移位输出数据; always@(posedge dclk_r)begin {dout,din_r[9:0]} <= {din_r[9:0],din}; end //ila使用延时前的时钟采集din_r的数据; //ila_0 u_ila_0 ( // .clk (dclk ),// input wire clk // .probe0 (din_r ) // input wire [9:0] probe0 //); //ila使用延时后的时钟采集din_r的数据; //ila_0 u_ila_1 ( // .clk (dclk_r ),// input wire clk // .probe0 (din_r ) // input wire [9:0] probe0 //); endmodule重新综合、实现工程后,在“IMPLEMENTATION”界面下双击“open Implemented Design”,如下所示。
图5 打开布局布线
在“Device”界面中找到DCLK引脚,如下图所示。
图6 Device界面
如下图所示,首先点击图中1处,就能查看芯片内部的实际走线了,如下图所示,左边为DCLK对应的管脚,信号进入管脚后,沿着绿色的走线,先到达idelaye2的输入,经过延时后输出到ILOGIC。
图7 DCLK输入走线
将上图中idelaye2和ilogic部分放大,如下图所示,蓝色走线是DCLK管脚输入,红色是idelaye2输出绕过ilogic进入FPGA内部逻辑的走线。
图8 信号走线
上述是输入信号进入FPGA管脚,经过idelaye2延时,绕过ilogic进入FPGA内部逻辑的走线。注意这部分是专用走线(固定不变的走线,只要使用idelaye2,不使用ilogic,走线就不会变),不是可编程的。
同时用户需要知道,外部信号进入FPGA管脚后,只有经过ilogic(包括绕过)才能被FPGA内部逻辑所使用。
接下来分析不使用idelaye2的信号输入走线,找到din信号对应管脚,如下图所示。
图9 din进入fpga走线
放大din在ilogic部分的走线,如下所示。din的管脚输入信号不经过idelaye2,同时绕过ilogic后输入到FPGA内部逻辑。
图10 din的ilogic走线
对比图8和图10就能找到前文出现错误的原因了。如果使用了经过idelaye2延时前后的同一个管脚输入信号,该如何走线?
如下图所示,在进入内部逻辑之前,都需要绕过ilogic。蓝色和紫色为idelaye2延时前的信号进入内部逻辑的走线,而红色和紫色为idelaye2延时后的信号进入内部逻辑的走线,紫色为两个信号重合的走线。
一根线不能同时传输两个信号,因此布局布线失败。
图11 idelaye2延时前后的信号走线
回到前文的问题,ila0使用了dclk没有经过idlaye2延时的信号作为时钟信号,而ila1使用dclk经过idelaye2延时后的信号作为时钟信号。
同时使用了dclk延时前后的信号,最终导致布局布线失败。
04解决办法
上述问题的原因就是内部逻辑同时使用idelaye2延时前后的两个信号导致的,最直接的方法就是不这么去用,始终只使用其中一个就可以避免。
如果实在要这么用,也有其他方法,只不过会导致管脚到idelaye2的走线比较长,而且不是专用走线(每次布局后如果idelaye2位置发生变化,则走线延时也会变),引入的延时不稳定性会导致调试很麻烦,且不易于移植,一般不建议这么做。
具体实现思路是,既然内部要同时使用idelaye2延时前后的信号,而dclk引脚绕过ilogic的走线知有一条,那么就先让不经过idelaye2的信号进入内部逻辑,然后在使用其余管脚的idelaye2来对输入的信号进行延时,这样不就解决了?
对应代码如下所示,将两个ila的注释取消,同时将idelaye2的DELAY_SRC参数设置为DATAIN,输入来自内部逻辑。
//--############################################################################################### //--# //--# File Name : top //--# Designer : 数字站 //--# Tool : Vivado 2017.4 //--# Design Date : 2024 //--# Description : //--# Version : 0.0 //--# Coding scheme : GBK(If the Chinese comment of the file is garbled, please do not save it and check whether the file is opened in GBK encoding mode) //--# //--############################################################################################### module top ( input clk ,//系统时钟信号; input rst ,//系统复位信号,高电平有效; input dclk ,//串行时钟输入; input din ,//输入数据; output reg dout //输出数据信号; ); reg [9 : 0] din_r ; wire dclk_r ; wire clk_200m ; //例化锁相环,生成idelaye2需要的200MHz时钟信号; clk_wiz_0 u_clk_wiz ( .clk_out1 ( clk_200m ),// output clk_out1 .reset ( rst ),// input reset .clk_in1 ( clk ) // input clk_in1 ); (* IODELAY_GROUP = "IODELAY_0" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL IDELAYCTRL u_IDELAYCTRL ( .RDY ( ),// 1-bit output: Ready output .REFCLK ( clk_200m ),// 1-bit input: Reference clock input .RST ( rst ) // 1-bit input: Active high reset input ); //例化idelaye2对时钟信号进行延时24*78+600=24.72ns; (* IODELAY_GROUP = "IODELAY_0" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL IDELAYE2 #( .CINVCTRL_SEL ("FALSE" ),//Enable dynamic clock inversion (FALSE, TRUE) .DELAY_SRC ("DATAIN" ),//Delay input (IDATAIN, DATAIN) .HIGH_PERFORMANCE_MODE ("FALSE" ),//Reduced jitter ("TRUE"), Reduced power ("FALSE") .IDELAY_TYPE ("FIXED" ),//FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE .IDELAY_VALUE (24 ),//Input delay tap setting (0-31) .PIPE_SEL ("FALSE" ),//Select pipelined mode, FALSE, TRUE .REFCLK_FREQUENCY (200.0 ),//IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0). .SIGNAL_PATTERN ("CLOCK" ) //DATA, CLOCK input signal ) u_IDELAYE2 ( .CNTVALUEOUT ( ),//5-bit output: Counter value output .DATAOUT ( dclk_r ),//1-bit output: Delayed data output .C ( clk_200m ),//1-bit input: Clock input .CE ( 1'b1 ),//1-bit input: Active high enable increment/decrement input .CINVCTRL ( 'd0 ),//1-bit input: Dynamic clock inversion input .CNTVALUEIN ( 'd0 ),//5-bit input: Counter value input .DATAIN ( dclk ),//1-bit input: Internal delay data input .IDATAIN ( 'd0 ),//1-bit input: Data input from the I/O .INC ( 'd0 ),//1-bit input: Increment / Decrement tap delay input .LD ( 'd0 ),//1-bit input: Load IDELAY_VALUE input .LDPIPEEN ( 'd0 ),//1-bit input: Enable PIPELINE register to load data input .REGRST ( rst ) //1-bit input: Active-high reset tap-delay input ); //移位输出数据; always@(posedge dclk_r)begin {dout,din_r[9:0]} <= {din_r[9:0],din}; end //ila使用延时前的时钟采集din_r的数据; ila_0 u_ila_0 ( .clk (dclk ),// input wire clk .probe0 (din_r ) // input wire [9:0] probe0 ); //ila使用延时后的时钟采集din_r的数据; ila_0 u_ila_1 ( .clk (dclk_r ),// input wire clk .probe0 (din_r ) // input wire [9:0] probe0 ); endmodule
图12 idelaye2对内部信号延时
重新综合、布局布线,然后打开“Device”界面,找到dclk引脚。如下图所示DCLK进入FPGA后,通过蓝色走线到达bufg输入,然后经过粉色走线到达右上角的一个管脚的idelaye2,然后黄色走线是idelaye2输出信号。
图13 修改后的布局
由此可知采用这种方式时蓝色、粉色、黄色走线都是很长的,导致延时特别大,有兴趣的用户可以看下时序报告,这个延时可能会比idelaye2能够调节范围还大,因此不建议使用。
这种使用方式不同芯片的idelaye2布局也基本上不相同,所以移植其实也麻烦。
除了约束以外,可以利用某些手段(比如bufr)去限制idelaye2布局位置,来减小走线延时,但相比专用走线,还是没有优势。
这种问题能够体现对于底层器件的理解,平时有时间可以留意一下器件布局布线的方式。
来源: 本文转载自数字站公众号
全部0条评论
快来发表一下你的评论吧 !