赞
踩
在FPGA中,想要实现RAM功能基本有2种方式:
1、使用DRAM;
2、使用BRAM;
其中DRAM一般用于少量的数据存储,且会占用大量的LUT资源;对于大量数据一般考虑使用BRAM,而想要调用开发板自带的BRAM,必须通过BMG IP核。
BMG IP核的配置是通过一系列参数完成的。下面是我对其中一部分重要参数配置的总结。
以下主要介绍一些常用的参数设置以及对应的时序效果分析,更详细的资料请参考官方文档
使用工具:Vivado 2022.2
打开IP Catalog
,搜索block memory generator
,双击查找到的IP核,我们就可以进行配置;
进入Basic
设置中,我们可以选择接口类型Interface Type
和我们需要配置的RAM类型Memory Type
,这里我只讲RAM,ROM留待以后;大多数情况下接口类型选择Naive
即可,尝试选择AXI4则会发现它只支持简单双口RAM。部分FPGA开发板上有ARM处理器,需要通过AXI4总线协议来实现处理器对FPGA的控制,本文对此不作详细展开。
对于双端口RAM,勾选Common clock
表示端口A和B采用同步时钟,不勾选则是异步时钟。采用不同的时钟同步模式会对端口的时序、读写模式等产生影响,后面会进行分析。
ECC Options
是纠错选项,同样也只支持简单双口RAM,一般不需要选。BMG采用的是汉明码纠错,可以纠1位bit错误或检测2位bit错误。本文重点关注的是时序变化,故也不作讨论。
Byte Write Enable
是一个很重要的选项,后面的很多时序也和这个选项有关。这里是指是否允许按字节方式写入,以及是8bit字节还是加上奇偶校验码(parity)的9bit字节。我们知道RAM的读写位宽可能不止一个字节。以32bit为例,其宽度为4个字节,勾选之后,我们可以只读/写这4个字节中的某几个字节。
Algorithm Options
是选择BRAM的串联方式。Xilinx 7 series的FPGA中,BRAM都是以小块排列的,我们很可能需要调用不止一块,块与块之间的连接组合可以有多种方式,这个选项提供了3种不同的算法来满足不同的需求,下面分别说明:
Minimun Area
:最小面积。该算法会在保证使用资源最少的情况下减少输出MUX的数量来提升性能;
Low Power
:最低功率。该算法会减少读写操作期间被激活的原语数目,降低功耗;
Fixed Primitives
:固定原语。通过指定原语的大小,所有的BRAM都由相同大小的原语拼接而成。
上述区别的详细的例子可以参考官方文档,这里不再赘述。
这里是对每个端口的配置。TDP的2个端口是独立的,而SDP的A端口只写,B端口只读。我们需要先详细了解这个界面各个参数的意义。
width指的是数据的位宽,depth是深度;简单但不完全准确的理解就是width指每个数据是多少bit,而depth指一共有多少个数据;如果之前勾选了Byte Write Enable
选项,Byte size
选8则输入位宽必须是8的倍数,选9则必须是9的倍数。 如果没有勾选,根据不同的配置在给定范围内选择即可。
对于不同位宽的读写,要注意地址的变化。例如写入位宽是32bit,深度16,而读取位宽是8bit,则读取深度为64,因而地址需要6位线宽。用这6位线宽怎么取4位地址呢?Vivado采用的是小端对齐,忽略LSB,即6位地址忽略最右边的2位获取4位地址。所以想要往0x0001写入数据,需要把输入地址设为0x000100。
在不使用Byte Write的情况下,如果地址最右边填充的不是0,那么由于LSB被忽略,故仍能正确写入数据,但无法将这个数据反映在dout上,dout的输出将是0;
这里是指端口采用写优先(Write first)、读优先(Read first)还是保持模式(No change)。这部分内容相信大家都有所了解,这里简单提及一下。注意一般RF会比No Change多15%的功耗,在不影响功能的情况下可以优先考虑用No change。
3种模式的时序图如下所示:图片来源于PG058文档
注意以上的时序图是在没有输出寄存器的情况下显示的。模式的选择对于冲突的应对有直接影响。对于简单双口RAM(SDPRAM),会出现读-写冲突;对于双口RAM(TDPRAM)还可能有写-写冲突。对于TDP,根据时钟是否同步以及模式选择的不同,冲突将会产生下面的结果:图片来源于UG473文档。
尝试一下可以发现,对于SDP,设置同步时钟的时候只读端口固定为RF,而设置异步时钟的时候只读端口固定为WF。原因在于Vivado对于异步冲突,规定异步的时钟强行暂停,待一个端口的写操作完成之后,再进行另一个端口的读写操作,再结合时序图就能理解为什么要这么设置了。
一般是默认使用使能信号EN来控制,可以减少一些功耗。
输出寄存器的作用是改善时序,每一级寄存器会使得输出结果延迟1个时钟周期输出,避免同周期内产生的很多时序问题。
Block Memory Generator提供了2种输出寄存器,primitive output register
(以下简称POR)以及core output register
(以下简称COR)。2种输出寄存器的区别在于位置不同,结构图参见下图。
POR位于BRAM的输出LATCH之后,属于BRAM内部资源,可以节省LUT资源,但是速度相对较慢;COR位于BRAM的输出端口之后,需要额外的LUT资源,但速度更快;
输出寄存器的控制主要由en、regce和rst构成。下图粗略显示了这些控制的具体作用位置。
接下来我们详细分析一下每个信号的具体作用。EN信号就是使能信号,当EN=0时不工作,当EN=1时输出寄存器才能工作;REGCE信号则用于控制最后一级输出寄存器,当EN有效时,拉高时寄存器的输出才能改变,否则将保持原来的输出结果;
总的来讲,时钟上升沿检测地址之后,会在同周期将数据加载到LATCH,因而只需要在下一个时钟周期的上升沿拉高REGCE,就可以让输出寄存器正确输出。
对输出寄存器的选择会直接影响RST信号的作用对象,我列举不同输出寄存器组合情况进行解释:
情况1:选择POR和COR,那么此时可以选择RST并设置复位值,右下角的优先级设置,CE表示和使能信号EN共同作用复位,即在EN有效的情况下RST才有效;若是选择SR,则RST可以单独复位最后一级寄存器,即COR。在RST拉高之后输出立刻会变为设定的复位值0;
情况2:只选择COR,与情况1的唯一区别在于输出只延迟1个周期,其余是类似的;
情况3:只选择POR。由于POR位于BRAM内部,而RST信号本身就是为这个设计的,所以会有更加特殊的设置。BRAM的输出会先经过LATCH后输入POR,默认设置RST信号不对LATCH作用,前面图片中的RSTRAM恒为‘0’,注意下方的提示,复位至少需要持续1个周期,建议一开始就进行复位操作,否则可能会产生不定态;若是勾选特殊设置Reset Memory Latch
,则RST信号会作用于LATCH上,复位时将LATCH也复位,此时复位需要持续至少2个时钟周期;
情况4:不选择寄存器,RST仍然是可选的,但是最好不要选,可能出现奇怪的问题。
上述过程中有的会产生一个rsta_busy
信号的输出,这个信号的作用我暂时还不清楚,以后再做探寻,也希望有大佬可以指点一二。
选择加入几级流水线,有的板子不支持该功能;每一级流水线导致输出延迟一个时钟周期。
选择是否初始化RAM。采用.coe文件进行初始化的方式不再赘述,网上有很多相关的例子。进行仿真之前建议进行初始化,避免不定态x造成许多奇怪的bug。
总的来讲,BMG v8.4几乎能满足所有对于BRAM的要求。使用IP核的核心就在于了解各个配置参数的意义,进而按照需求来进行相关的设计。
以上的BRAM调用是基于Naive接口,我最近在学习AXI4接口的BRAM调用,后续可能会写一些AXI4相关的总结。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。