☰
FPGA外部IO约束
2026/10/14 3:26:55 网站建设 项目流程

在FPGA中,有一个必不可少的问题,和外部芯片打交道,怎么保证输出的信号能被外部芯片能准确接收;以及外部芯片输出的信号被FPGA准确捕获呢?

1. 基本知识

1.1 建立时间与保持时间

我们知道FPGA的时序模型其实就是对两个寄存器进行建立时间、保持时间进行分析。

图1 寄存器时序分析模型

这里我们引入几个概念:

  1. 发射沿(Launch Edge)与捕获沿(Latch Edge):发射沿指的是源寄存器(reg1)时钟的发射数据的时刻;捕获沿是目的寄存器(reg2)时钟捕获数据的时钟的时刻。但是注意了,在不考虑时钟skew的情况下,在进行建立时间分析的时候,接收沿比发射沿晚1个时钟周期;而在对保持时间分析时,接收沿与发射沿是相同的。
  2. 数据到达时间(Date Arrival Time)与数据要求时间(Data Required Time):在进行建立时间时:

在计算保持时间时,就是把Data Require Time的“-Tsu”项改为“+Th”:

是不是很简单,最后建立时间分析就是Data Required Time - Data Arrival Time,对应的是到达时间要比要求时间短;而保持时间就是Data Arrival Time - Data Required Time,对应的是数据要保持足够长时间,避免数据在捕获沿被改写。

你会发现,数据延迟时间越长对保持时间越有利,而对建立时间越不利。还有一点就是时钟的延迟可以等效到数据延迟里,比如说Td - ( Tc2j - Tc2i),可以认为是等效数据传输延迟。

好了,不扯远了。大概原理就这样。

1.2 外部芯片与FPGA时序分析模型

你把外部芯片端的输入、输出端也想象成一个一个寄存器就行了:

在外部芯片寄存器作为源寄存器或目的寄存器时,作为FPGA端其实不了解的是1. 外部数据路径与时钟路径时间之差,可以为正数或负数,为正数时,表示外部数据路径比时钟路径远,记为Td;2.外部芯片寄存器的建立保持时间(只在外部芯片为目的寄存器时才会使用),记为Tsu、Th;3. 外部芯片引脚输出与时钟边沿的时间差(仅在外部芯片为源寄存器时才会使用)记记为To。

有了这些信息后,我们怎么把这些信息告诉EDA工具呢,就是靠set_input_delay、set_output_delay两个xdc约束。

输入延迟为Td+To;输出延迟的最大延迟为Td+Tsu、输出的最小延迟为Td-Th。

2 约束使用

2.1 约束语句

输入延迟使用输出延迟使用

这里:

  • -clock用于指定约束引脚的同步时钟(源时钟),其后的<args>即需要指定的同步时钟名称,这个时钟可以是设计中事先定义的主时钟或虚拟时钟。
  • -reference_pin用于指定延时值<delay >的参考时钟 ,其后的<args>即需要指定的参考时钟名称。-reference_pin<args>是可选项,不指定该选项,则指定延时值 <delay>的参考时钟就是-clock指定的同时钟。
  • -clock_fall命令选项指定输出(输入)延时的取值相对于同步时钟的下降沿。若不指定 -clock fall 命令选项,Vivado时序工具将默认为-clock_rise。
  • -rise -fall基本用不到,应该是指只分析数据从0变为1或从1变为0
  • -max、-min用来指定最大最小延迟
  • -add_delay是用来约束双边沿信号的,对需要同时约束clock_rise、-clock_fall,加入-add_delay防止两个指令只有后面那个生效
  • <delay>指定延迟指,可以为正数或者负数
  • <objects>指定输入或输出的引脚
多说无益,直接看例子

2.2 约束实例

这里我举个实例,代码如下:

module input_delay( input clk, input in1, input in2, input in3, input in4, output clk_out, output reg out1, output reg out2, output reg out3, output reg out4 ); //为了验证输入延迟与输出延迟的使用(set_input_delay和set_output_delay),这里信号分为4组 //in1为上升沿输入,上升沿捕获,上升沿输出,目标芯片上升沿捕获 //in2为上升沿输入,下降沿捕获,下降沿输出,目标芯片上升沿捕获 //in3为下降沿输入,上升沿捕获,上升沿输出,目标芯片下降沿捕获 //in4为下降沿输入,下降沿捕获,下降沿输出,目标芯片下降沿捕获 //使用MMCM时钟资源,输出和clk同频的时钟 wire clk_mmcm; assign clk_out = clk_mmcm; clk_wiz_0 clk_wiz_inst ( .clk_in1(clk), .reset(1'b0), .clk_out1(clk_mmcm), .locked() ); (*preserve = "true" *) reg in1_d,in2_d,in3_d,in4_d; always @ (posedge clk_mmcm) begin in1_d <= in1; in3_d <= in3; end always @ (negedge clk_mmcm) begin in2_d <= in2; in4_d <= in4; end //对输入反向后输出 always @ (posedge clk_mmcm) begin out1 <= ~in1_d; out3 <= ~in3_d; end always @ (negedge clk_mmcm) begin out2 <= ~in2_d; out4 <= ~in4_d; end endmodule

约束文件:

create_clock -period 10.000 -name clk [get_ports clk] create_generated_clock -name clk_mmcm -source [get_pins clk_wiz_inst/clk_out1] -multiply_by 1 [get_ports clk_out] set_input_delay -clock clk 2.000 [get_ports in1] set_input_delay -clock clk 2.000 [get_ports in2] set_input_delay -clock clk -clock_fall 2.000 [get_ports in3] set_input_delay -clock clk -clock_fall 2.000 [get_ports in4] set_output_delay -clock clk_mmcm 2.000 [get_ports out1] set_output_delay -clock clk_mmcm 2.000 [get_ports out2] set_output_delay -clock clk_mmcm -clock_fall 2.000 [get_ports out3] set_output_delay -clock clk_mmcm -clock_fall 2.000 [get_ports out4] set_property PACKAGE_PIN H9 [get_ports clk] set_property IOSTANDARD LVCMOS18 [get_ports clk] set_property PACKAGE_PIN D7 [get_ports in1] set_property IOSTANDARD LVCMOS18 [get_ports in1] set_property PACKAGE_PIN G13 [get_ports in2] set_property IOSTANDARD LVCMOS18 [get_ports in2] set_property PACKAGE_PIN A9 [get_ports in3] set_property IOSTANDARD LVCMOS18 [get_ports in3] set_property PACKAGE_PIN L13 [get_ports in4] set_property IOSTANDARD LVCMOS18 [get_ports in4] set_property PACKAGE_PIN M13 [get_ports out1] set_property IOSTANDARD LVCMOS18 [get_ports out1] set_property PACKAGE_PIN J10 [get_ports out2] set_property IOSTANDARD LVCMOS18 [get_ports out2] set_property PACKAGE_PIN K10 [get_ports out3] set_property IOSTANDARD LVCMOS18 [get_ports out3] set_property PACKAGE_PIN L11 [get_ports out4] set_property IOSTANDARD LVCMOS18 [get_ports out4] set_property IOSTANDARD LVCMOS18 [get_ports clk_out] set_property PACKAGE_PIN G10 [get_ports clk_out]

注意,这里加入了一个时钟IP,配置如下:

最后我们一个看:

2.2.1 in1:set_input_delay -clock clk 2.000 [get_ports in1]

它在外部芯片的clk时钟上升沿触发,相对clk上升沿后2ns到达FPGA,这里的2ns指的是数据变化发生在clk上升沿到达FPGA引脚后,数据延迟2ns才到。对应的,它的时序报告如下:

in1经过2ns的input delay后,还有一些线路延迟,最后到达寄存器D端口用时3.082ns,这就是到达时间。由于input delay指定了时钟管脚和数据关系,所以这里没有源时钟路径。
上面是数据要求时间计算,主要就是看目的寄存器的时钟捕获沿什么时候到,这里可以看到,上升沿经过了输入buff+MMCM。最终时序裕量为11.043-3.082=7.961ns。

再看保持时间:

可以看到保持时间计算时arrival time基本和建立时间的arrival time一样,略小一点,主要是计算保持时间时,要算arrival time - required time,arrival time 取最极端情况下的最小值。

再看时钟路径,同样经过相同的器件,不过捕获沿没有延后一个时钟,且required time计算时,各个路径延迟更大。

2.2.2 set_input_delay -clock clk 2.000 [get_ports in2]

in2和in1的主要差别是在FPGA端,in2使用下降沿进行捕获。

暂时更新到这,等晚上有空再更新

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询