本文对xilinx 7系列FPGA的时钟路由资源进行讲解,内容是对ug472手册的解读和总结,需要该手册的可以直接在xilinx官网获取,或者在公众号回复“xilinx手册”即可获取。
1、概括
7系列器件根据芯片大小不同,会有8至24个时钟区域,如图1所示,图中的每个虚线框就表示一个时钟区域,每个时钟区域包含50个CLB和50个IO。
由上图可知,FPGA被主时钟网络(Clock Backbone)分为左右两部分,在主时钟网络中包含32个全局时钟资源BUFG,32个BUFG被水平时钟线(Horizontal Center)划分为上下两部分,每部分包含16个BUFG,上下两部分的BUFG不能混用。
从左向右,I/O 列(I/O Column)就是FPGA输入输出管脚的资源,包含前文介绍过的IOB、ILOGIC、OLOGIC等资源。位于I/O列旁边的CMT,可以提供时钟频率合成、去偏差和抖动滤波功能。每个CMT包含一个混合模式时钟管理器(MMCM)和一个锁相环(PLL)。最右侧就是高速收发器所在列。
注意水平相邻的两个时钟区域通过水平时钟行(Horizontal Clock Row)连接,也就是BUFH。把图1中阴影部分的时钟区域放大,得到结果如图2所示。每个时钟区域包含50个CLB和50个IO,在区域内部又被水平时钟行(Horizontal Clock Row)分为上、下两部分,各自包含25个CLB和25个IO管脚。
由图2可知,时钟区域内部主要包含全局时钟缓冲器(BUFG)、行时钟缓冲器(BUFH)、区域时钟缓冲器(BUFR)、IO时钟缓冲器(BUFIO)、时钟输入管脚CC,BUFMR用于驱动垂直相邻时钟区域的BUFR和BUFIO。
后文主要就是对上面这些内容进行详细讲解,最后在通过一张图进行总结,以后只需要通过最后的图就知道7系列的FPGA的时钟区域内各个缓冲器的使用规则以及时钟输入管脚的时钟规则。
2、时钟输入管脚
用户时钟必须通过专用时钟的差分引脚输入FPGA,专用时钟引脚输入的信号可以对FPGA内部全局、区域时钟资源进行专用高速访问,时钟信号不能通过通用IO进入FPGA。
每个I/O bank包括50个I/O引脚,在每个I/O列的每个I/O bank的50个I/O引脚中,有四个支持时钟的输入引脚对CC (总共8个引脚),2对MRCC和2对SRCC时钟管脚,如图3所示。水平时钟行(Horizontal Clock Row)的上、下两部分各包含一对MRCC差分时钟管脚和一对SRCC时钟管脚。
这也可以从FPGA的原理图中得到证实,图4是xilinx FPGA的一个BANK原理图。在中部包含四个SRCC和MRCC的差分时钟输入引脚,IO_L11P_T1_SRCC就表示SRCC的P输入端。
每个支持时钟的输入管脚可以连接到PCB上的差分或单端时钟,单端时钟输入必须分配给支持时钟的输入差分引脚对的P端。如果单端时钟连接到差分时钟引脚对的P端,则N端不能用作另一个单端时钟引脚,只能用作用户I/O。时钟输入管脚也可以被用作任何I/O标准(包括差分I/O标准)的通用IO使用。
SRCC管脚可以驱动当前时钟域的IO时钟缓冲器(BUFIO)、区域时钟缓冲器(BUFR)、行时钟缓冲器(BUFH)、位于同部分(如果SRCC位于FPGA下半部分,那就只能驱动下半部分的BUFG)的全局时钟缓冲器(BUFG)、相同或相邻时钟区域的CMT。
MRCC具有SRCC所有功能,且可以驱动多时钟区域缓冲器(BUFMR)来访问最多三个上下垂直相邻的时钟区域的BUFR和BUFIO,在后文讲解BUFR的时候会进行详细讲解。
如果一个时钟驱动一个CMT,那么时钟输入管脚和CMT必须处于同一个时钟区域。
单个时钟输入可以驱动多达三个CMT,但时钟的输入管脚必须与中间的CMT处于同一时钟区域,其余两个CMT必须位于上下相邻的时钟区域。
当时钟输入管脚驱动同一列中其它时钟区域的CMT,但不驱动同一时钟区域的CMT时,需要设置CLOCK_DEDICATED_ROUTE = BACKBON。这种情况下,CMT无法将输出时钟与输入时钟正确对齐。
这里主要是了解FPGA每个IO bank的专用时钟管脚有哪些,不同时钟管脚输入的时钟信号能够驱动的时钟资源有什么差异,单端时钟应该从什么管脚进入FPGA就行了。
3、全局时钟缓冲器(BUFG)
从此开始就会涉及一些原语的介绍,但是都比较简单,继续往下看。
7系列FPGA时钟树专为低偏斜和低功耗操作而设计,任何未使用的分支都被断开。时钟树也可以用来驱动逻辑资源,如复位或时钟使能,主要用于高扇出网络。
每个7系列器件都有32条全局时钟线,BUFG可以被上/下同一部分的MRCC、SRCC、CMT、BUFG、BUFR、GT高速收发器时钟、还有计数器分频得到的时钟(不推荐)驱动。BUFG的输出可以驱动CMT、BUFH、高速收发器时钟信号、同一部分中的BUFG、CLB及IOB等所有时钟区域的时钟信号和控制信号。
全局时钟缓冲器(BUFGCTRL,简称BUFG)驱动全局时钟线,必须用于访问全局时钟线。使用时钟区域中的12条水平时钟线,每个时钟区域最多支持12条全局时钟线。BUFG和BUFH会共用同一个时钟区域里面的12条水平时钟线。
可以通过vivado中芯片的时钟走线观察,如图5所示,一个区域会有12条水平的时钟线。
全局时钟缓冲器相关的原语是比较多的,包括BUFGCTRL、BUFG、BUFGCE、BUFGCE_1、BUFGMUX、BUFGMUX_1、BUFGMUX_CTRL。其实后面6个都是通过BUFGCTRL演化而来的,常用的就是BUFG,所以本文就讲解BUFGCTRL的功能以及怎么演化为BUFG的,其余原语就是使能或者选择时钟的功能,可以根据功能就可以得知具体怎么演化的了。
3.1、BUFGCTRL
BUFGCTRL原语可以用于切换两个异步时钟,如图6是BUFGCTRL原语的框图,I0和I1是两个时钟输入端口,而S0、S1、CE0、CE1、IGNORE0、IGNORE1是相应的控制信号,O是输出时钟端口。
对应原语如下所示:
BUFGCTRL #(
.INIT_OUT(0), // Initial value of BUFGCTRL output ($VALUES;)
.PRESELECT_I0("FALSE"), // BUFGCTRL output uses I0 input ($VALUES;)
.PRESELECT_I1("FALSE") // BUFGCTRL output uses I1 input ($VALUES;)
)
BUFGCTRL_inst (
.O(O), // 1-bit output: Clock output
.CE0(CE0), // 1-bit input: Clock enable input for I0
.CE1(CE1), // 1-bit input: Clock enable input for I1
.I0(I0), // 1-bit input: Primary clock
.I1(I1), // 1-bit input: Secondary clock
.IGNORE0(IGNORE0), // 1-bit input: Clock ignore input for I0
.IGNORE1(IGNORE1), // 1-bit input: Clock ignore input for I1
.S0(S0), // 1-bit input: Clock select for I0
.S1(S1) // 1-bit input: Clock select for I1
);
几个信号对应的真值表如下表1所示:
表1 BUFGCTRL真值表
S0 | CE0 | S1 | CE1 | O |
---|---|---|---|---|
1 | 1 | X | 0 | I0 |
1 | 1 | 0 | X | I0 |
0 | X | 1 | 1 | I1 |
X | 0 | 1 | 1 | I1 |
1 | 1 | 1 | 1 | 保持 |
当S0和CE0为高电平且S1或CE1有低电平时,将时钟I0输出,如果S1、CE1同时为高电平且S0或CE1为低电平时,将时钟I1输出。如果四个信号全为高电平,则保持之前的输出不变。
对应的时序图如图7所示,在I0的1处之前,S0和CE0为高电平,S1和CE1为低电平,则输出时钟I0。在1处S0、CE0、S1、CE1电平翻转,但是输出信号O不会立即将时钟信号I1输出,而是要检测到I0和I1的下降沿之后,在I1的上升沿3处后面才会把I1输出。
那如果不想让BUFGCTRL在S和CE信号变化后检测I0和I1的下降沿,该怎么办?只需要把IGNORE0或者IGNORE1信号拉高即可,如图7所示,把IGNORE1拉高,在5处S0、CE0、S1、CE1电平翻转,后面就只检测I0的下降沿,而无需检测I1的下降沿。
BUFGCTRL有三个参数,其中PRESELECT_I0和PRESELECT_I1用于设置I0和I1在器件运行前的初始状态,一般默认即可。INIT_OUT是用来设置BUFGCTRL在切换时是检测I0和I1有效沿,以及检测到相应沿时输出的电平状态,默认为0。
图7中INIT_OUT为0,在切换时钟过程中,在2处检测到I0下降沿,然后端口O输出低电平。
虽然S和CE均用于选择所需输出,但对于无毛刺开关,仅建议使用S。
3.2、BUFG
BUFG只是一个时钟缓冲器,具有一个时钟输入和一个时钟输出。此原语基于BUFGCTRL,其中一些引脚连接到逻辑高电平或低电平。
图8是BUFG的框图,将BUFGCTRL的S1、CE1、IGNORE0接低电平,S0、CE0、I1、IGNORE1接高电平,此时就会把I0作为输出,也就是BUFG的功能了。
BUFG的原语如下所示,这也是最常用的,把时钟信号引入全局时钟网络。
BUFG BUFG_inst (
.O(O), // 1-bit output: Clock output
.I(I) // 1-bit input: Clock input
);
图9是BUFG的时序图。
至于其余的BUFGCE、BUFGCE_1、BUFGMUX、BUFGMUX_1、BUFGMUX_CTRL也都是把BUFGCTRL的几个输入信号接固定电平演化得到的,此处就不再赘述,需要详细了解的可以直接查看数据手册。
4、水平时钟缓冲器(BUFH/BUFHCE)
水平时钟缓冲器(BUFH/BUFHCE)允许通过水平时钟行访问单个时钟区域中的全局时钟线。
BUFH可以被同一或水平相邻时钟区域的SRCC、MRCC、CMT、BUFG、GT时钟、互联逻辑(不建议)驱动,BUFH的输出可以驱动同一时钟区域的CMT、GT时钟、该区域中任意时钟节点(CLB、IOB、RAM、DSP等时钟节点), 相当于收到区域限制的BUFG。
要使用BUFH,逻辑必须适合水平相邻的两个区域(左和右),如图10所示。它还可以用作时钟使能电路(BUFHCE ),独立使能或禁用跨越单个时钟区域的时钟,从而实现潜在的节能。与驱动两个相邻区域的BUFG相比,BUFH的功耗和抖动更低。
这个其实比较有用,比如电路中某部分电路可能就在上电之后工作一段时间,经过这段时间后,就可以把该时钟的使能信号拉低,从而关闭该区域的时钟,降低功耗。
使用每个时钟区域中的12条水平时钟线,每个时钟区域可以支持多达12个时钟。每个BUFH都有一个时钟使能引脚(CE ),允许动态关闭时钟。图11是BUFH的框图。
BUFH对应原语模板如下所示:
BUFH BUFH_inst (
.O(O), // 1-bit output: Clock output
.I(I) // 1-bit input: Clock input
);
BUFHCE #(
.CE_TYPE("SYNC"), // "SYNC" (glitchless switching) or "ASYNC" (immediate switch)
.INIT_OUT(0) // Initial output value (0-1)
)
BUFHCE_inst (
.O(O), // 1-bit output: Clock output
.CE(CE), // 1-bit input: Active high enable
.I(I) // 1-bit input: Clock input
);
原语的输入和输出信号都比较简单,不再赘述,该原语包含两个参数,其中INIT_OUT表示初始化时BUFH输出电平,默认输出低电平。CE_TYPE用来表示使能端口与时钟的关系,是异步使能还是同步使能,默认为同步使能。
5、区域时钟缓冲器(BUFR)
BUFR将时钟信号驱动到时钟区域内的专用时钟网,独立于全局时钟树。每个BUFR可以驱动其所在区域的四个区域时钟网,BUFR可以驱动I/O逻辑和逻辑资源(CLB、块RAM等)。
BUFR可以被同一时钟区域的SRCC、MRCC、(MMCM . CLKOUT0~CLKOUT3)、时钟反馈CLKFBOUT、上下相邻时钟区域的BUFMR、通用互联(用户分频产生的时钟信号)驱动,BUFR输出可以驱动BUFG在该区域能驱动的所有节点、CMT、同部分的BUFG(不推荐)。
BUFR能够产生相对于时钟输入的分频时钟输出,分频系数可以设置为1~8之间的整数。FPGA内部能够对时钟分频的资源就是锁相环和BUFR,锁相环需要经过全局时钟网络,延迟会比BUFR分频大很多,但是锁相环的分频会更加稳定。图12是BUFR的原语模型。
BUFR的原语模板如下所示:
BUFR #(
.BUFR_DIVIDE("BYPASS"), // Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8"
.SIM_DEVICE("7SERIES") // Must be set to "7SERIES"
)
BUFR_inst (
.O(O), // 1-bit output: Clock output port
.CE(CE), // 1-bit input: Active high, clock enable (Divided modes only)
.CLR(CLR), // 1-bit input: Active high, asynchronous clear (Divided modes only)
.I(I) // 1-bit input: Clock buffer input driven by an IBUF, MMCM or local interconnect
);
BUFR的原语端口比较简单,I是输入时钟,O是输出时钟,CE是输出时钟使能,高电平有效。CLR用于分频逻辑异步清零,高电平有效,将输出设为低电平,不使用分频功能时不能使用该信号。要注意在使用过程中CE信号从无效变为有效后,必须将CLR拉高一次。
该原语有一个分频的参数BUFR_DIVIDE,默认为BYPASS,不使用分频功能。注意分频系数设置为奇数时,输出时钟占空比不是50%,低电平持续时间会比高电平持续时间长一个输入时钟周期。
下图是BUFR输出3分频的时序图,在1后面的时钟I上升沿,CE为高电平,此时输出时钟O输出高电平。由于采用3分频,所以时钟I前一个时钟周期BUFR输出高电平,然后输出两个时钟周期的低电平。在3处时钟I上升沿检测到CLR为高电平,则端口O输出低电平。
BUFR还是比较简单,能够驱动一个时钟区域内的所有时序节点,并且能够对输入时钟信号进行分频,可以减小延时。但是可能会有疑问,为什么会有1分频这个选项?1分频不就是不进行分频吗?
当参数BUFR_DIVIDE设置为BYPASS时,输出信号直接绕过BUFR内部分频器,导致输出信号的延时比分频后输出信号的延时小。
如下图所示,ISERDES的CLK采用BUFR直接输入,而CLKDIV是MRCC经过BUFR分频后的时钟。如果两个BUFR输出时钟有效沿要对齐,提供CLK时钟的BUFR分频系数就只能设置为1,不能设置为BYPASS。
6、IO时钟缓冲器(BUFIO)
前文提到的这些时钟路由资源,可以驱动时钟区域内的所有时钟节点,但是BUFIO只能驱动当前时钟区域的IO列中的时钟节点。
除互联逻辑外,能够驱动BUFR的资源也能够驱动BUFIO,而BUFIO的输出只能驱动ILOGIC和OLOGIC的IO列中的时钟信号。
下图能够很好说明BUFIO和BUFR的区别,BUFIO的输出只能驱动IO列里面的时钟端口,而BUFR拥有BUFIO所有功能且还能驱动当前时钟区域里的CLB、RAM、DSP的时序节点。
BUFIO驱动IO列的资源的延时相比BUFR、BUFG这些会更少,所以一般BUFIO与BUFR会一起使用,如下图所示,BUFIO用于驱动IO列中的时钟信号,而BUFR驱动该时钟区域内的其余时钟资源。这种方式在后续千兆网中会使用。
BUFIO的原语模型如下图所示:
该原语的模板如下所示:
BUFIO BUFIO_inst (
.O(O), // 1-bit output: Clock output (connect to I/O clock loads).
.I(I) // 1-bit input: Clock input (connect to an IBUF or BUFMR).
);
原语很简单,就一个输入时钟,经过一定内部延时后输出。
7、多区域时钟缓冲器(BUFMR/BUFMRCE)
用户时钟从MRCC或SRCC进入FPGA后,仅能驱动当前时钟区域里的BUFIO和BUFR。如果同时想要驱动上、下两个垂直相邻时钟区域里的BUFR或BUFIO,则需要使用BUFMR。只有MRCC进入的时钟信号可以使用BUFMR,SRCC进入的时钟信号不能使用BUFMR。
BUFMR/BUFMRCE只能把同一时钟区域的MRCC或GT的时钟信号作为输入,而输出信号只能驱动垂直相邻三个时钟区域里面的BUFR和BUFIO,如下两图所示,两张图描述的内容相似。
BUFMR/BUFMRCE的原语模型如下图所示:
BUFMR和BUFMRCE原语其实就相差一个使能引脚,其余没有区别,原语模板如下所示:
BUFMR BUFMR_inst (
.O(O), // 1-bit output: Clock output (connect to BUFIOs/BUFRs)
.I(I) // 1-bit input: Clock input (Connect to IBUF)
);
BUFMRCE #(
.CE_TYPE("SYNC"), // SYNC, ASYNC
.INIT_OUT(0) // Initial output and stopped polarity, (0-1)
)
BUFMRCE_inst (
.O(O), // 1-bit output: Clock output (connect to BUFIOs/BUFRs)
.CE(CE), // 1-bit input: Active high buffer enable
.I(I) // 1-bit input: Clock input (Connect to IBUF)
);
8、总结
前文对BUFG、BUFH、BUFR、BUFIO、BUFMR做了讲解,其实这些缓冲器的功能相似。
1、BUFG功能最强大,每个FPGA最多只能有32个BUFG工作,32个BUFG被水平时钟线分为上下两部分,各16个BUFG,上半部分的BUFG不能驱动下半部分相关时钟节点。
2、BUFH是能够被水平相邻时钟区域的SRCC、MRCC等资源驱动,能够驱动该时钟区域中BUFG能够驱动的时钟节点。
3、BUFR是区域时钟缓冲器,能够驱动所在区域BUFG能驱动的时钟节点,并且能够对输入时钟进行分频输出,可以降低分频时钟延时。
4、BUFIO只能驱动所在时钟区域中的IO列中ILOGIC、OLOGIC的时钟端口,延时也是最低的,最适合作为源同步时钟的处理。一般与BUFR组合使用,将延迟降低到最小。
5、BUFMR可以把所在时钟区域的MRCC或GT时钟作为输入,输出信号可以驱动垂直相邻三个时钟区域的BUFR和BUFIO。
上述所有资源都可以使用下图进行总结,下图是A7 FPGA的一个时钟区域各个时钟资源的分布。
经过前文讲解,该图可以对手册的一半内容进行总结,所以此处最后拿出来进行总结。
首先一个时钟区域包括50个CLB,上图中HROW上面包含25个CLB,下面包含25个CLB,且HROW上半部分的IO列中包含25个IO管脚,下半部分也有25个IO管脚,均包含2对差分时钟专用引脚CC。
IO列中包含BUFR和BUFIO,BUFIO的输出只存在IO列中,表示只能驱动IO列中的时钟资源,而BUFR输出还与CLB、RAM、DSP等时钟端口连接,表示可以驱动更多资源。
BUFMR输出分别穿出该时钟区域,向上、下分别延伸,表示可以驱动垂直相邻上下区域的BUFR和BUFIO。
BUFG和BUFH都是从主时钟网络中引出,通过HROW所在水平时钟行进入时钟区域,会共用一个时钟区域的12条水平时钟线。并且在该区域中,BUFG和BUFH能够驱动的时钟资源相同,都能够被CMT和GT的时钟信号驱动。
时钟路由资源只是该手册的一大半内容,还有一半内容是对MMCM和PLL使用进行讲解,包括原语的使用及相关参数。
这个手册很久之前就读过,那时候并没有单独调用这些资源使用,所以对BUFG、BUFH这些缓冲器的理解并不充分,甚至会混淆。最近在写以太网相关代码时,使用到了BUFIO、BUFR这些缓冲器,就重读了一遍手册,对一些重要的内容进行了总结。
手册最后几页的图也可以说是精华所在吧,能够对前文的大部分内容进行总结,熟悉之后,只要看到这些图片就可以支道每个缓冲器的功能等等,不必记忆什么文字内容。