原以为选用了一个BRAM资源为16M的FPGA,就不需要考虑内部RAM的资源使用了,16M妥妥的够啊。
没想到啊,我大意了。
之前看过官方MEM的手册ug473 7 Series FPGAs Memory Resources, 并没有太在意内部RAM位宽WIDTH
,深度DEPTH
和使用BRAM资源
的问题。
直到在综合实现的时候,提示BRAM资源溢出,才突然想到,是BRAM资源使用的不合理。提示信息如下:
[Place 30-640] Place Check:This design requires more BRAM36/FIFO cells than are avaliable in the target device. This Design requires 534 of such cell types but only 445 compatible sites are avaliable in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
上次见到这个情况还是,ILA调试的时候加载了太多数据,导致BRAM使用资源溢出。
在手册中了解到,7系列的设备都有偶较大容量的 36Kb block RAMs。每个36Kb block RAM包含两个独立控制的18Kb RAMs。
这些36Kb的block可以级联可以在最小的时序损失下,实现深度更深或者位宽更宽的存储。
查表可知7K325T的Block RAMs分为7列,每一列有70个,拢共有445个36 Kb Block RAM(是不是感觉少了45个?)。
手册中也有对内部资源使用的介绍:
嵌入式双端口或单端口RAM模块,ROM模块,同步FIFO和数据宽度转换器是使用Xilinx CORE Generator™块存储模块实现的。 可以使用CORE Generator FIFO生成器模块生成双时钟FIFO。 同步或异步(双时钟)FIFO实现不需要用于FIFO控制逻辑的其他CLB资源,因为它使用了专用的硬件资源。
也就是说,使用FIFO的时候如果选用BRAM存储类型,FIFO的容量也就取决于片上BRAM的容量;
手册中也有给出不同类型的FIFO容量,深度与位宽的关系:
在Standard模式下,18Kb BRAM指的是位宽为18bit,深度为1K的RAM块。同样36Kb BRAM指的是位宽为36bit,深度为1K的RAM块。
从上表中能够看出来,使用1个18Kb BRAM的最大位宽为与深度为36bit * 512;使用1个36Kb BRAM的最大位宽与深度为72bit * 512;
如果用户FIFO的位宽和深度与上述表格不匹配,在FIFO Generator中,会自动计算需要的BRAM个数。
举例如下:
如果位宽大于等于36bit,那么就需要使用36K的BRAM了;即如果位宽为40bit,深度不大于1024,就需要36K的BRAM1个;
如果位宽很宽而深度很浅的情况下,比如位宽256bit,深度16;
此时需要用36K和18K的BRAM来先凑位宽。一个18K的BRAM支持位宽为36bit以内;一个36K的BRAM支持位宽为72bit以内。
72 * 4 = 288;
所以,至少需要4个36K BRAM,深度也就固定下来最大为512;在FIFO Generator中的Summary也可以得到同样的BRAM资源分配方式:
这样,本来缓存的数据容量为256 * 16 = 4 K;而现在却使用了36 * 4 = 144 K的容量实现。
这就是导致最终BRAM不够使用的原因;
再假如需要位宽为512bit,深度为16;
72 * 7 + 18 = 522 > 512 bit;
因此,至少需要7个36K BRAM和1个18K BRAM,深度最大为512; 在FIFO Generator中的Summary也可以得到同样的BRAM资源分配方式:
与刚才类似,这里因为FIFO位宽太长,而深度使用不足的原因也造成了非常多的BRAM资源没有使用。
控制好FIFO的位宽与深度数值,尽量用满一个BRAM之后,再启用第二个甚至更多的BRAM;
比如想将768bit位宽的48组数据存储到FIFO中:
按照之前的计算需要使用11个36K BRAM存储,深度512只使用了24;
可以先将768bit数据,切分为4小组,每组位宽为192bit;按照192bit的位宽存储到FIFO中,这样深度就变成为48 * 4 = 192;
需要使用3个36K BRAM就可以存储了,虽然还是有很多浪费的空间,但是可比上面节约多了。
根据需求,数据从FIFO读出后,也须要进行位拼接,拼接成之前的768bit(是不是感觉有点繁琐)。
这样做的局限在于,牺牲了数据传输的时间,因为数据切分成片段,是Delay一段时间的,分的越零碎,需要的时间也就越长;
还有FIFO的读写位宽降低,读写时钟不变,所以FIFO的带宽也降低了。
目前还没有想到其他的方式来处理,如果有更好的方式,欢迎留言讨论。
为啥Xilinx选用36K来做为一个Block RAM的容量呢?
使用FIFO的时候需要注意数据位宽,与数据深度,对占用的BRAM资源大小的影响,要避免设计超出FPGA的BRAM资源。