FPGA 设计之 跨时钟域的弹性Buffer

FPGA设计之跨时钟域的弹性Buffer

9ea0d3519f31496d4e1d4b26e8342da5.png

\\\插播一条:

自己在今年整理一套单片机单片机相关论文800余篇

论文制作思维导图

原理图+源代码+开题报告+正文+外文资料

想要的同学私信找我。

bf6b6ceceac033dadef2d021dbd431f2.png

在前面的文章中我们已经介绍了异步FIFO的设计原理FPGA设计之跨时钟域(五-异步FIFO)。我们知道为了防止FIFO overflow或者 underflow,异步FIFO有空满信号。当满信号有效时会反压前级逻辑,不让其继续写数据到FIFO内,当空信号有效时,则通知后级逻辑,数据已经全部读出,不让其继续读取FIFO。如果我们的应用需求是数据必须不断流入然后流出FIFO呢?这意味着既不能反压前级也不能通知后级。

弹性Buffer便是应用在这种需求下的一种跨时钟域的设计方法。本文将从以下几点介绍弹性Buffer:

·弹性Buffer的应用背景

·弹性Buffer与普通异步FIFO的区别

·弹性Buffer的具体设计

·弹性Buffer有什么缺点

弹性Buffer的应用背景

在起初的PCI总线设计中,采用的是同步时序结构,即发送端和接收端使用同步时钟,发送端只需要发送数据,接收端正常采样即可。这种同步结构要求时钟到达发送端和接收端的时间精确相同,特别是对总线接口pin-to-pin的skew要求极高。随着总线频率的提升,对skew的要求也越来越高,使得时钟网络布线越来越困难。

因此,当前的很多高速接口设计,如PCIe,Ethernet都是采用了源同步(source-synchronous)时序结构,即发送端同时发送时钟和数据,接收端需要从接收到的数据中恢复出数据的采样时钟,用该时钟来采样收到的数据。这种设计方式虽然避免了上述的问题,但是也带来了新的问题,即跨时钟域的问题,因为这种设计结构下一般会有两个时钟域,即Recovered Clock Domain和 Local Clock Domain。一般来说,Recovered Clock和 Local Clock之间频率只有些微的差别,弹性Buffer便是用来解决这种情况下的跨时钟域数据传输问题的。如图1所示:

a1d2095bb2bd2842796f04330e08e811.png图1 - PCIe器件中使用弹性Buffe做跨时钟域处理

弹性Buffer与普通异步FIFO的区别

普通的异步FIFO读写时钟不同,随着数据的不断写入或者不断读出,最终必然会到达满或空的状态,从而停下数据从写时钟域向读时钟域的流动,直到FIFO不再为满或空。

对于弹性Buffe来说,读写时钟之间独有些微的差别,频次近似。数据会不断从写时钟域流向读时钟域的,为了到达这个目标,弹性Buffer会自己丢弃或者插入数据来补偿读写时钟之间的频次/相位差。应用弹性Buffer的总线协议会定义特定的Symbol,假如PCIe协议的Skip或者Ethernet协议的IDLE,这些特殊定义的Symbol就能够被用来丢弃或者插入而不影响正常的数据传输。

弹性Buffer的详细设计

从上一局部的内容我们能够看出来,弹性Buffer相比普通异步FIFO主要是增加了丢弃或插入特殊字符的逻辑,同时也没有满空信号。

以1G Ethernet协议为例。Ethernet协议要求两个包之间须要发送特殊字符IDLE,该字符能够被弹性Buffer用来做时钟频次/相位的补偿。我们的设计是10bit位宽的数据,采样时钟为125M,读写时钟之间允许最高有300ppm的频次差别。

如何考虑Buffer的深度

以+/-300ppm的容忍程度,频次范围则是在124.9625M~125.0375M之间。以最差情况看,假入写时钟为124.9625Mhz(8.0024ns),读时钟为125.0375Mhz(7.9976ns)。两者之间时钟周期的差为0.0048ns,也就是说每 7.9976/0.0048=1666个Cycle会有一次时钟周期的漂移。

依照Ethernet最长的包长1500bytes计算,一个包会跨越 (1500*8)/10=1200个Cycle。所以一个Ethernet包至多有一次时钟周期的漂移。假设我们想在每次漂移之后都做时钟补偿,那么FIFO的深度为4即可,想留一些裕量则能够考虑更大的深度,如8,16。

如何决定是否丢弃或插入IDLE字符

以FIFO深度为4为例。在FIFO的正常工作模式下,我们会让FIFO总是处在半满状态,即含2个数据。然后我们设置两个阈值,3和1。当

64b6996524f55b6d5b738c327157e4c3.png8dadf720b93fbff7868717d58da46f43.png9f8a36b0ce0e4b7ae00f3e7af65ec03f.png

FIFO内所含的数据大于等于3时,我们认为写时钟过快,则丢弃IDLE字符。当FIFO内所含的数据数目小于等于1时,我们认为读时钟过快,需要插入IDLE字符。

那么什么时候丢弃或插入呢?当然不能在一个Ethernet包内,因为这样会导致数据传输错误。前面我们已经提到在两个Ethernet包的间隔,协议要求要发送IDLE字符,我们可以在间隔期间看到IDLE字符后选择丢弃或插入。

综上,我们设计的弹性Buffer可能会是这样的一个工作流程:

.FIFO上电后达到半满状态

.数据不断流入FIFO再流出,FIFO一直处于半满状态,所存数据个数为2

.一个新的Ethernet数据包来临,在传输这个包期间,FIFO的读写时钟发生了一次漂移,写时钟更快。导致FIFO内所存放的数据个数变成了3

.这个Ethernet包传输结束,发送端开始发送IDLE字符,我们检测到IDLE字符后同时检查FIFO内的数据个数,发现FIFO不是半满,而是3

.我们认为写时钟快了,则丢弃接下来收到的IDLE字符,直到FIFO恢复半满

弹性Buffer就不需要考虑Overflow或Underflow了么?

因为我们对弹性Buffer的深度设计是基于读写时钟之间的ppm差计算的,如果能保证读写时钟的ppm差满足要求,那么是不用考虑的。

如果无法保证,我们则需要考虑增加Overflow和Underflow的判断,并报告Error。一旦出现Overflow或Underflow我们认为系统无法正常工作,需要停止运行。

弹性Buffer有什么缺点

从弹性Buffer的设计可以看出,其主要的缺点是会带来延迟。为了保证弹性Buffer在正常情况的半满状态,我们需要先将数据Buffer在FIFO中。上文中的设计,弹性Buffer会引入至多3个Cycle,至少2个Cycle的延迟。

总结

本篇文章主要介绍了用于跨时钟域的弹性Buffer的应用背景和设计原理。

猜你喜欢

转载自blog.csdn.net/danpianji777/article/details/125007021