Menu Close

数据缓冲与乒乓Buffer

上节内容探讨了在数据交换及数据处理过程中的异步过程,出现了异步过程就需要数据缓冲。FIFO 作为数据缓冲器是一种较好的办法,但如果出现数据包校验错误,超时等因素需要数据包重发时,由于FIFO数据读出后就会消失,因此在重发的要求下FIFO就不适合做数据缓冲器。在数据缓冲设计中,还有一种带有地址寻址的RAM结构也是数据缓冲器的重要选择。在计算软件编程中经常听到向操作系统申请一片内存(allocate), 实际就是利用计算机内存实现带地址访存的内存空间作为数据缓冲器。在计算机系统中利用malloc分配内存,利用链表实现队列(Queue)。队列是一种特殊的链表,即它只允许在表的一端插入元素,而在另一端删除元素。在FPGA的编程中也有对应的机制,如RAM,或BRAM对应计算机软件中的RAM,FIFO对应软件的队列(Queue)。

1.利用RAM实现数据缓存

在嵌入式计算机系统中,数据或程序的存储器一般为单口RAM,即在某一时刻只能进行读或者写,不能读写同时,而且规定了严格访问仲裁机制。而高速的数据处理机制为了提高数据的吞吐率,又往往要求读写同时进行。因此在FPGA内创建双口RAM实现同时读/写是一个很好的机制,双口RAM如图所示。

图1   DPRAM

图1显示了双口RAM(DPRAM,dual port RAM)的结构,一般DPRAM将端口分成左右两边,左边的数据,地址,信号在尾缀添加_a(或a)的标志,右边添加_b(或b)的标志,当然实际命名按照需要和习惯进行,建议按照上面的方式进行命名。当然左右与_a或_b可以交换,即左边用 _b标识,右边用 _a标识。图1虽然实现了既读又写的机制,但使用起来却非常不安全,而且操作也很麻烦,具体的应用场景和问题如下:

(1)读写速度相同的应用

这种双口RAM由于没有良好的监控机制,因此一般用于读写速度相当的应用场景,即写地址永远超前,但又不能追尾。一般把双口RAM的深度设的大一些,对于平均速度相等的读写,可以满足要求,但应用场景的确受限。一般的随机读写或在一定时间内读写速度严重不平衡的设计中不宜采用。可应用场景如AD转换的数据,按一定的速度产生,数据处理也按同样的速度进行;再如图像数据按行读写,只要RAM的深度超过两到三行,即可平衡。但这种应用非常类似FIFO的行为,因此更多的采用FIFO实现。

(2)突发数据处理

虽然短时间数据的读写不平衡,但在较长的时间内统计是平衡的,可以使用该DPRAM的模型。但要求读写双方都应该有对应握手机制,控制读写速度,而且RAM的地址要反应到双方的握手机制上,防止写追尾或读追尾,如图2所示。

图2

从图2 中可以看出,在突发数据处理时不仅左右两端需要握手,而且为了防止读写追尾,两边都需要对方的地址进行参考计算。当读写双方是异步时钟域时,还要对异步时钟域的地址同步化,不仅安全性不能保证,还增加了额外的处理逻辑。但是应用图2中的处理办法的确使应用场景更广泛。有没有更好的处理办法呢?答案是肯定的,目前FPGA内都有可以例化的左右两边都有读写的双口RAM,一般称这种双口RAM为真双口RAM(TDPRAM,True Dual Port RAM)。

2. 真双口RAM(TDPRAM)

真双口RAM简化了双边的握手机制,而且避免左右两边地址的相互耦合。TDPRAM的实现才使双口RAM的应用真正走向实用阶段,TDPRAM的结构如图3所示。

图3  TDPRAM

图3 显示了真双口RAM的结构,可以实现双边读写和监控,对于有结构的数据也可以按照数据结构的方式读写,比如网络数据包的转发或高速通信的数据等,可以设制监控字段,保证数据的完整性。如图4所示。

图4  带有控制字段的TDPRAM

图4中的的控制(Control)字段是软件握手范畴,TDPRAM本身不具备该字段。以互联网数据包为例,A端口写入,为了不破坏包的完整性,可以将RAM的最高单元(CELL)设为控制字,控制两边的读写。其中K指示RAM内的数据是否有效,Length指示RAM内数据的长度。如以太网MAC层的数据包可以为60-1514个字节不等(不考虑VLAN,Jumbo包等),因此当数据写入时也同时计数,当数据包完成写入后,将控制字段填写为K = 1,Length = data_count;data_count 为接收数据包的数据长度。读数据要检查数据的有效性和数据的真实长度,保证读写双方数据的完整性。

注:这里完整性是指写入数据时应保证在上一次数据包没有被完全读出之前等待,写入完成后应指示数据包的有效性和数据的真实长度。读出端在读之前应检查数据的有效性,即RAM中的数据是更新过的数据包,而不是历史数据,同时也要确切知道RAM内有效数据的长度。

例1: 假设TDPRAM的A端口为以太网的数据接收端,将接收的数据写入RAM,B端口将数据读出。设计握手机制,保证数据读写的完整性。

读写机制及读写步骤如下:

A端口:

(1)将地址调整到控制字段(这里为最高地址),读出控制字检查K是否为0,如果为0表示RAM内的数据已经无效,可以进行写操作,

(2)将地址调到最低(这里为0),等待网络数据,

(3)写数据,直到完成整个数据包的写操作,

(4)写控制字段,Length = data_count, K = 1,

(5)读控制字段直到K = 0(可能需要一个时钟周期的延迟),进行下一个数据包的写。

B端口:

(1)读控制字,如果K=0,表示RAM中无有效数据包,等待直到K=1,

(2)如果K=1,将Length 读出,将地址调到最低开始读数并累计读出数据的数量,直到累积数据的量与Length相等,

(3)写0到控制字单元(控制字清0),指示RAM中的数据无效。

可见A,B端口同时监控控制字,如此循环,则数据包内的数据可以做到完整的转发或使用。从这种机制也可以看出虽然对数据包处理实现了数据读写的完整性,但是严格握手机制使得数据交换效率严重降低,本来畅通的数据流,变成了半双工机制,结果RAM的交换机制变成整个数据流的瓶颈。

3. 乒乓Buffer机制

为了打破RAM在数据交换的瓶颈,可以改变图4中的结构,引入乒乓Buffer机制。实现原理如下:

将TDPRAM在深度方向上进行分割,如将图4中的RAM在深度方向上一分为二。分割后的每个部分都设有控制字,如图5所示,

图5  乒乓Buffer

图5 的读写机制如下:

A端口:

(1)地址调整到Control1,检查K,如果K == 0,

(2)写RAM1,写RAM1的K = 1, 和 数据长度

(3)跳转到RAM2 的Control2,检查RAM2的K,如果K == 0,

(4)写RAM2,写RAM2的K = 1, 和 数据长度

(5)返回RAM1,跳转到(1),往复循环。

B端口:

(1)检查RAM1的K == 1 后得到相应的数据长度,

(2)读RAM1,

(3)清Control1,

(4)跳转到RAM2,检查RAM2的K == 1 后得到相应的数据长度,

(5)读RAM2,

(6)清Control2,

(7)返回(1),循环读TDPRAM的操作。

说明:这里的例子将乒乓Buffer设为在深度方向的两个RAM,但并不限于2个RAM的分割,也可以分为3,4,5 , ….。推荐采用2n 的方式进行分割。推荐分割的原则如下:

(1)RAM块采用2n 的方式进行分割,

(2)计算数据包的最大长度,使分割后的每个RAM的深度 = Length(RAM) + 1 或 > Length(RAM) + 1, 其中=,>主要看控制字是否能容纳数据包的长度。

(3)可以等间隔(等长)分割TDPRAM(RAM利用效率低),也可以非等长分割。根据FPGA内TDPRAM的特点以及数据包的长度结合具体情况划分。推荐等间隔划分。

a. 等间隔(等长)分割TDPRAM,RAM利用效率低,但寻址简单。

b. 非等长分割TDPRAM,RAM利用效率高,但寻址复杂。

4.总结

以上在异步过程中根据实际应用提出了RAM的配置方法和使用技巧,并逐步提出了乒乓Buffer的握手机制,乒乓Buffer较好的平衡了数据包读写的完整性和读写效率。在后续的文章中会结合Verilog的开发实例,特别是串行高速通信的示例进行介绍乒乓Buffer的使用。

 

 

 

 

 

Posted in FPGA, FPGA 教材教案, FPGA硬件资源, IC, IP开发, 教材与教案, 文章

1 Comment

  1. 国 刘

    拜读了文章,受益匪浅,感觉硬件上的乒乓buffer跟软件上多线程的共享内存访问原理类似。所以,思想性的东西,无论是软件还是硬件,都是可以借鉴的,只是实现的手段不同。谢谢老师辛苦付出。

发表回复

相关链接