爱原来这么简单(原来这么简单500字)

FPGA中的时序问题是一个比较重要的问题 , 时序违例 , 尤其喜欢在资源利用率较高、时钟频率较高或者是位宽较宽的情况下出现 。本文介绍时序分析的原理以及出现时序问题时一般的解决办法 。
基本概念建立时间和保持时间是FPGA时序约束中两个最基本的概念 , 同样在芯片电路时序分析中也存在 。




爱原来这么简单(原来这么简单500字)

文章插图


电路中的建立时间和保持时间其实跟生活中的红绿灯很像 , 建立时间是指在绿灯(clk的上升沿)亮起之前行人或者车辆(data数据)在路口提前等待的时间(只允许绿灯亮起的一刹那在路口的车辆才允许通行);而保持时间 , 则是绿灯亮起后必须保持的时间 , 这样行人或者数据才能够通过这个十字路口 , 否则hold时间就不满足 。
同时 , 红绿灯默认都是周期性的(clk也是周期性的) , 车辆不允许在两个相邻的红绿灯之间通过的时间超过一个clk的周期(组合逻辑时延不能过大) 。




爱原来这么简单(原来这么简单500字)

文章插图


建立时间(Tsu):是指在时钟沿到来之前数据从不稳定到稳定所需的时间 , 如果建立的时间不满足要求 , 在时钟上升沿 , 寄存器将不能正确采到数据值 。如下图(左)所示:
保持时间(Th):是指在时钟上升沿后数据保持稳定的时间 , 如果保持时间不满足要求那么数据同样也不能被正确采集到 。保持时间示意图如下图(右)所示:




爱原来这么简单(原来这么简单500字)

文章插图


如图1.3 , 这是一个FPGA输入数据的模型 , 输入端口到第一个寄存器之间的路径需要进行时序约束 。一般我们需要告知FPGA输入输出接口的最大最小延迟 , 使EDA工具在进行布局布线时能够尽可能的优化输入端口到第一级寄存器之间的延迟 , 使FPGA中时钟的上升沿能够正确采集到输入的数据 。在sdc约束中 , 输入延时是从上游器件发出数据到FPGA输入端口的延时时间 。如图,1.4所示 , 输入接口时序清楚反应了FPGA在接收数据时应满足的建立和保持时间要求 。




爱原来这么简单(原来这么简单500字)

文章插图




爱原来这么简单(原来这么简单500字)

文章插图


说明:
OSC : 系统时钟
ASSP.CLk :外部器件寄存器的时钟
ASSP.Q :外部器件数据输出
FPGA.D :FPGA数据输入
FPGA.CLK :FPGA内部寄存器的时钟
Tclk1 :系统时钟到外部器件之间的延时
Tclk2 :系统时钟到FPGA之间的延时
Tco :数据经过外部器件寄存器输出后相对于ASSP.CLK的偏移
Tpcb :数据在pcb电路板上的延时
FTsu :FPGA上寄存器的建立时间要求
FTh :FPGA上寄存器的保持时间要求
setup slack :建立时间余量 , 必须大于等于0才能满足建立时间的时序要求
hold slack :保持时间余量 , 必须大于等于0才能满足保持时间的时序要求
T: 系统时钟频率




爱原来这么简单(原来这么简单500字)

文章插图




爱原来这么简单(原来这么简单500字)

文章插图


c. 输出延时即为FPGA输出数据后到达外部器件的延时时间 。如1.7所示 , 为FPGA和外部器件接口时序图 。




爱原来这么简单(原来这么简单500字)

文章插图




爱原来这么简单(原来这么简单500字)

文章插图




爱原来这么简单(原来这么简单500字)

文章插图


系统同步和源同步接口系统同步中数据发送器和数据接收器在同一时钟源下同步工作 , 发送器和接收器之间只传递数据 , 数据的时序关系以系统时钟作为参考 。
所谓源同步接口是指发送器和接收器之间传送数据时同时传一个和数据保持特定相位关系的时钟 , 接收器就可以根据这个时钟的相位来准确采集相应的数据 。如图所示 , 分别是系统同步和源同步接口示例图 。


爱原来这么简单(原来这么简单500字)

文章插图
在系统同步接口中 , 系统时钟到发送器和接收器之间的时延很难确定 , 所以接收器比较难确定时钟和数据之间的相位关系 , 采集到的数据很难保证正确 。所以系统时钟只适用于低速时钟低速数据的收发 。而源同步接口的好处就在于可以以较高的频率高速收发数据 , 数据和时钟由发送器同步给出 , 在电路板上数据和时钟布线等长 , 时延相等 , 接收器接收到的数据和时钟的相位关系基本保持不变 。所以对于源同步接口的时序约束也较为简单 , 我们只需要告诉FPGA上游芯片发送端口数据和时钟的相对关系 , FPGA布局布线时就会调整时钟和数据的布线长度 , 使接收数据时满足时序要求 。
GMII的数据收发就是一个典型的源同步接口 。MAC接收数据的时钟Rx_clk和数据Rxd由上游PHY同步给出;MAC发送数据时发送时钟Gtx_clk和数据Txd也是同步给到PHY , 所以我们对于GMII接口的时序约束就可以按照源同步接口的方法 。




爱原来这么简单(原来这么简单500字)

文章插图


SOC系统的时序接口及约束若系统外部PHY芯片的型号是RTL8211EG , 其芯片手册中给出了PHY接口处的时序 , 如图所示:




爱原来这么简单(原来这么简单500字)

文章插图


RTL8211EG芯片GMII接口时序关系
对于输入时钟的约束



爱原来这么简单(原来这么简单500字)

文章插图


时钟输入接口约束
GMII接口的Rx_clk时钟是125MHZ , 频率较高 。这时由外部器件进入FPGA内部的时钟可能不稳定 , 采集Rxd数据时会有影响 , 这时我们应先对输入的时钟进行约束 。
如果不加PLL , 即直接时钟模式 , 一般不改变时钟特性直接进行数据采集 , 这通常适用于低速输入且中心对齐的单速率源同步接口;如果在输入端加一个PLL , 即采用PLL时钟模式 , PLL可对时钟与数据的关系进行精确调整 , 适用于高速输入的中心对齐和边沿对齐的源同步接口 。因此 , 使用PLL时钟对调整FPGA的接口时序有很大帮助 。
由图1.4中输入时序接口可以看出Tco即为时钟上升沿与数据的偏移 , 则RTL8211EG中MAC接收端口Tco(max) =T-tR/2-tGSUT=8-0.5-2.5=5ns , 最小Tco(min)=tGHTT+ tR/2=1ns , 
故相对于Rx_clk的输入最大最小延时
input delay max = Tco(max) =5ns
input delay min = Tco(min) =1ns
以上的约束的输入延时是相对于输入时钟Rx_clk的约束 , 在sdc约束中我们还可以设置一个虚拟时钟(可以假设是上游器件寄存器的驱动时钟 , 用于计算源器件的启动沿) , 源同步接口输入数据以这个虚拟时钟为参考输入FPGA , 所以当我们声明输入延时时就可以以这个虚拟时钟作为启动时钟 。使用虚拟时钟约束输入延时的好处是可以是约束更加方便、更加精确 。
输入约束的时延值可以理解为有效数据沿相对于时钟的偏移 , 如果时延值为正说明数据相对于时钟向后偏移 , 时延为负说明数据相对于时钟向前偏移 。根据上面描述输入数据相对于输入时钟Rx_clk的最大最小延时分别为1ns和5ns , 下面我们计算输入数据相对于虚拟时钟vir_clk的延时值 。取Rx_clk的上升下降时间分别为0、4ns(周期8ns) , 取数据时延Tco的平均值3ns为vir_clk相对于Rx_clk的偏移 , 即vir_clk的上升下降时间分别为3、7ns 。
根据下图所示 , 当Tco取1ns时 , Rxd有效时相对于Rx_clk上升沿偏移1ns , 相对于vir_clk上升沿偏移-2ns;当Tco取5ns时 , Rxd有效时相对于Rx_clk上升沿偏移5ns , 相对于vir_clk偏移2ns 。




爱原来这么简单(原来这么简单500字)

文章插图


Tco取最小值时Rxd相对于vir_clk关系图






爱原来这么简单(原来这么简单500字)

文章插图


Tco取最大值时Rxd相对于vir_clk关系图
根据上述描述 , 我们以虚拟时钟vir_clk为参考时钟 , 约束如下:




爱原来这么简单(原来这么简单500字)

文章插图


sdc中的输入延时约束
当然 , 我们也可以用Rx_clk作为参考来约束输入延时 , 但是quartus在布局布线时 , 以输入时钟为参考的约束不够精确 , 有时仍会出现时序错误 。
对于GMII发送数据约束时 , 由于发送时钟和发送数据布线时延可忽略 , 故FPGA发送端口和PHY接收端口数据时钟相位关系相似 , 结合图1.4中发送接口时序和RTL8211EG的图表可以看出FTco(max)+tGSUR+tR/2=Tclk , FTco(min)=tGHTR+ tR/2
故有
output delay max=Tclk- FTco(max)=tGSUR+tR/2=2.5ns
output delay min=- FTco(min)= -(tGHTR+tR/2)=-0.5ns




爱原来这么简单(原来这么简单500字)

文章插图


SDR接口输出约束含义
所以 , 在sdc中我们如下约束输出接口:




爱原来这么简单(原来这么简单500字)

文章插图




在上面的输出约束中 , 我们可以理解为:
根据outputdelay中max/-min的定义 , 源同步接口中输出最大最小延时为输出时钟上升沿到达之前最大与最小的数据有效窗口 。如图所示 , 用于建立时间分析的set output delay –max的值为正数2.5ns , 表示数据窗口在Gtx_clk上升沿之前2.5ns时间内有效 , 而用于保持时间分析的 -min之后跟着负数-0.5ns , 表示数据在Gtx_clk上升沿之后0.5ns内有效 , 即相对于Gtx_clk输出数据有效窗口为-0.5ns到2.5ns , 这个范围大于等于PHY芯片手册中给出的Txd相对于Gtx_clk的窗口范围时 , 才能满足PHY芯片采集Txd时的时序要求 。
Quartus的逻辑分区约束既然是FPGA和外部接口的时序问题 , 也就是输入输出的寄存Rxd/Txd的寄存器到外部器件寄存器的时序问题 。




爱原来这么简单(原来这么简单500字)

文章插图


GMII接收数据路径分析
Tpcb是外部PCB板上数据的延时 , Tdata_i是数据的输入延时 , Gmii_rx_interface相当于Rxd进入FPGA后的第一个寄存器模块(可以专门写一个接口模块 , 将Rxd数据打一拍 , 用于接收数据) 。如果Gmii_rx_interface距离接口Rxd较远 , Tdata_i的路径较长 , 布局布线时Rxd的八根线时延相差可能就比较大 , 所以我们应让这个模块放在距离Rxd接口较近的地方 。
Quartus软件中有一个LogicLock(物理分区)功能 , 把Gmii_rx_interface模块建立成一个LogicLock分区但并不对分区位置和大小进行固定 , 然后重新编译工程 。布局布线后就可以在chipplaner工具中看到这个分区的位置 , 如下图所示(放大可以看清) , Gmii_rx_interface模块距离Rxd接口位置很远 , 布局布线时 , 输入信号要绕很长一段距离才会到达输入的寄存器 , 资源占用很多时 , Rxd的8根数据线长度不一 , 很容易造成时序问题 。




爱原来这么简单(原来这么简单500字)

文章插图


未固定分区位置时布局布线结果
【爱原来这么简单(原来这么简单500字)】把Gmii_rx_interface模块分区移动到Rxd接口附近进行固定然后重新编译工程 , 布局布线后该逻辑分区就会在Rxd接口附近 , 从而保证输入数据接口进入FPGA的第一个寄存器的时延在一定范围内 , 保证时序要求 。




爱原来这么简单(原来这么简单500字)

文章插图


采用LogicLock后 , GMII寄存器接口位置
内部寄存器到寄存器时序问题



爱原来这么简单(原来这么简单500字)

文章插图




爱原来这么简单(原来这么简单500字)

文章插图


寄存器到寄存器之间建立和保持时间时序要求
在FPGA的设计中除了应该考虑到输入输出接口的时序 , 还应该考虑到内部寄存器到寄存器的时序问题 。内部寄存器之间同样要满足建立和保持时间要求 , 如上图所示
其中Tdata为组合逻辑在电路中的延时 。
建立时间余量=T+Tclk2-Tclk1-Tco-Tdata-Tsu>=0
保持时间余量=Tclk1+Tco+Tdata-Tclk2-Th>=0
通常在FPGA中忽略时钟的skew(偏移) , 即有Tclk2-Tclk1=0

建立时间余量=T-Tco-Tdata-Tsu>=0
保持时间余量=Tco+Tdata -Th>=0
为了使FPGA设计的电路正常 , 就必须满足以上的建立和保持时间要求 , 根据建立时间余量公式可知
T>=Tco+Tdata+Tsu
F=1/T
在FPGA中Tco、Tsu等的数值由所使用FPGA的特性决定 , 所以时序电路之间的组合电路延时决定了整个电路的速度 , 即决定了整个电路的最大工作时钟频率 。
若FPGA工作频率为130MHZ , 如果在做设计时 , 组合逻辑的过于复杂 , 寄存器到寄存器之间的延时Tdata过大 , 如果系统仍工作在130MHZ的频率下就有可能出现时序问题 。所以在设计时我们应尽可能减小组合逻辑的复杂度 , 以提高工作频率 。下面讨论提高系统工作频率的方法 。
a. 通过减小Tdata值来提高频率
在quartus的sdc约束中有关于寄存器到寄存器之间组合逻辑时延的约束 , 通过设置从REG1到REG2之间组合逻辑延时的最大最小值 , 来约束FPGA的布局布线 , 从而来提高系统的工作频率 。
但这种方法通常只能提高5%左右的工作频率 , 不能过多的限制组合逻辑的时延 , 否则不利于EDA工具的布局布线 。
b. 采用流水线设计来提高频率




爱原来这么简单(原来这么简单500字)

文章插图


流水线分割组合逻辑
通过约束减小组合逻辑延时的方法并不能够十分有效的提高系统的工作频率 , 所以在设计时我们应尽量减少大规模组合逻辑的使用 。如图所示 , 采用流水线的设计思想 , 将两个寄存器之间的组合逻辑拆分成两级组合逻辑 , 从而减小组合逻辑的复杂度 。采用流水线技术可以很好地提高系统运行时钟的工作频率 。
假设原来路径延时为t , 加入两级流水线并且假设路径切割均匀 , 则路径延时减少到约t/3 , 从而系统的工作频率提高到原来3倍左右 。




爱原来这么简单(原来这么简单500字)

文章插图


如上图所示 , 在我们做FPGA设计过程中 , 原来的judge_result是一个很大的组合逻辑 , 信号产生的路径时延很大 , 很难满足时序要求 , 在FPGA编译完做验证时 , 出现if条件不正确的情况 , 状态机不能正确跳转 。
修改:将if中复杂的组合逻辑信号在时钟的上升沿 , 赋值给中间变量寄存器judge_result和judge_result_en , 这样在做if判断时就不用判断原来的复杂组合逻辑值 , 只需判断judge_result和judge_result_en的值 。即采用流水线分割的方法把原来十分复杂的组合逻辑分成两部分 , 这样FPGA在编译后就不会出现时序错误的情况 。




爱原来这么简单(原来这么简单500字)

文章插图




实例:使用vivado进行简单的时钟约束Vivado下时钟约束可以参考这两个文章:
https://blog.csdn.net/neufeifatonju/article/details/80450951
https://blog.csdn.net/FPGADesigner/article/details/82871624
之所以要进行时钟约束是因为:当时钟进入了FPGA器件 , 通过时钟树传递时 , 时钟边沿会有延时 , 通常称作时钟网络延迟;噪声或硬件表现会导致时钟随时可能发生变化 , 通常称作时钟不确定性 , 包括时钟抖动、相位错位等等 。
增加时钟约束可以一定程度上减少时钟延时带来的问题 , 比如大位宽数据(128位)从ram中读出时由于路径延时导致数据错误的问题 。
这里介绍一下简单进行时钟约束的办法(以vivado2018.2为例):
第一步:对工程进行综合 , 综合之后点击“Edit Timing Constraints”




爱原来这么简单(原来这么简单500字)

文章插图


第二步 , 打开之后看到如下界面:




爱原来这么简单(原来这么简单500字)

文章插图


第三步 , 双击create clock,打开如下界面:




爱原来这么简单(原来这么简单500字)

文章插图


第四步 , 一般会点击sourcesobjects 旁边的这个按钮来选择你要约束的时钟:




爱原来这么简单(原来这么简单500字)

文章插图


点击之后弹出如下界面:




爱原来这么简单(原来这么简单500字)

文章插图


第五步 , 输入你要约束的时钟 , 然后进行查找 , 找到之后按照如下添加到右侧框内 , 然后点击set:




爱原来这么简单(原来这么简单500字)

文章插图


第六步 , 然后set之后会返回到这个界面 , 你需要在这个界面输入时钟名 , 不然会生成一个虚拟时钟:




爱原来这么简单(原来这么简单500字)

文章插图


第七步 , 然后到这个界面 , 按照图片进行操作:




爱原来这么简单(原来这么简单500字)

文章插图


一般来说要点击add clock , 然后按crtl+s保存你设置的时钟约束 , 之后再点击apply(或者直接点击apply) 。
然后你打开你的xdc文件,会发现已经有了这么一个约束了 , 然后再重新综合和实现就好了 。
create_clock -period 8.000-name clkb -waveform {0.000 4.000} -add [get_nets{u_TTE_switch_top/U_ET_switch_plane_top/U_fp_and_sch_0/u_schedule_top/u_bus_ram/clkau_TTE_switch_top/U_ET_switch_plane_top/U_fp_and_sch_0/u_schedule_top/u_bus_ram/clkb}]
create_clock -period 8.000-name clk_gtx_125m -waveform {0.000 4.000} -add [get_netsinst_sgmii_if/clk_gtx_125m]




爱原来这么简单(原来这么简单500字)

文章插图


全文完 。