BRAM,Block RAM,也称为块RAM,在某些国产FPGA中也被称为DRM。相对于分布式RAM(DRAM)而言,块RAM通常按固定大小分布在芯片中,例如 Xilinx FPGA 中的块RAM通常为 18Kb 或 36Kb,适用于需要处理大批量数据的应用场景。DRAM是利用FPGA中的查找表(LUT)实现的小型存储器资源,因此可以分散在FPGA的不同区域。由于分布式RAM通常直接位于逻辑单元内部,访问速度较高,适合小数据块的快速访问需求。

BRAM的容量常见的有9Kbit,18Kbit,36Kbit等,具体得看厂家和器件。BRAM可以配置为单端口SP,简单双端口SDP,真双端口TDP。当配置为不同模式时,可以选择的深度和位宽也不同,以紫光同创的FPGA为例,当一个18Kbit的DRM配置为SDP时,可以选择的位宽和深度组合为:

而当18Kbit的DRM配置为TDP时,可以选择的位宽和深度组合为:

这主要是由于两种模式的RAM的端口配置不同,在FPGA设计中,每个BRAM都通过开关盒(switch-box)来连接数据总线。然而开关盒的连接数量是有限的,因此只能支持一定数量的数据总线。

对于True Dual Port (TDP)模式,由于两个端口都支持读和写操作,所以会有四条数据总线(每个端口有读和写各一条)。这四条数据总线占用了大量的开关盒连接。

而在Simple Dual Port (SDP)模式下,读和写端口是分开的,即一个端口只读,另一个端口只写,这样只需要两条数据总线(一条用于读,一条用于写)。因此,SDP模式可以利用本来在TDP模式下用于其他两条数据总线的开关盒连接资源,将其用于增加单端口的位宽,最终达到数据位宽的翻倍。

上图展示了BRAM的详细电路图,可以看出BRAM是由6T SRAM基本存储单元和外围电路组成,外围电路可以将BRAM配置成单端口和双端口RAM并且可以控制读写。

下面着重分析右侧的SRAM读写过程。

上面部分可以看出一个6T SRAM的经典结构,原图没有标注交点,用下面的图来表示更为清晰。

假设在某一时刻,Q为1,那么~Q为0,M1,M4导通,M2,M3截止,Q和~Q保持稳定。

在读数据时,BL和~BL预充电到到高电平,此时电压相等。WL拉高,M5,M6导通,Q和~Q之间的电压差会通过M1-M4放大,放大过程是一个正反馈,最终会快速稳定下来。预充电的好处是反馈迅速,读出速度快,不易受到BL线上残留电压的干扰。

在写入时,Wen拉高,BL上的电平由Din决定,Din为高电平,BL充电,~BL接地,数据被写入到Q中。

预充电的电路结构可以用下图表示,PCON为预充电信号。

对于双端口RAM,用下面的结构来形成两个独立的开关:

BRAM的内部简化示意图如下:

紫光FPGA手册示意图

Xilinx FPGA 手册示意图

对比一下两张图,结构非常相似,但是似乎紫光的Latch部分有误,控制信号不应该是时钟边沿,应该参考Xilinx的控制信号,后续和紫光的工程师确认一下。

输出端口可以看到从SRAM矩阵中读取的数据首先经过了一个锁存器latch,然后经过一个可选寄存器,这个寄存器是BRAM中内置的寄存器,也称为Embedded Output Register。虽然添加寄存器会使得读出数据增加一个时钟Cycle,但是由于这个寄存器在BRAM内部,会极大改善时序,延迟也很小,并且这个内置寄存器不会消耗任何额外的逻辑资源。

从上图中可以看出,添加了输出寄存器之后的延迟改善了很多,几乎为没有输出寄存器的1/3,因此一般推荐添加输出寄存器来提高频率。

上图展示了 Xilinx BRAM IP Core的电路结构,包含了Block RAM 原语部分和一些外部电路,包括外置输出寄存器Core Output Registers和内置寄存器 Embedded Output Registers。

上图展示了使用两种不同输出寄存器时能够达到的最大频率,可以看出,在单端口RAM的场景下,Embedded Output Registers的时序最优。实际上,BRAM的设置不同,频率变化比较大,因此可以在实际应用中对比后选择。推荐开启Embedded Output Registers。

读写冲突的问题:

在异步时钟下

  1. 一个端口进行写操作时,另一个端口不能对地址进行读写访问。

  2. 在可能产生读写冲突的情况,需要将RAM的读写模式设置为WRITE_FIRST而不能是READ_FIRST,因为这种情况下无法保证能将旧数据有效读出,只能保证有效数据被写入。无论何时NO_CHANGE都不保证读写冲突时读出数据有效性。

在同步时钟下

  1. 不能对相同地址进行写操作,除非写入的数据完全相同。

  2. 设置成READ_FIRST模式一个端口写,一个端口读同一地址,此时两个端口的输出数据都是原先的旧数据,新数据可以被正确写入。

  3. 设置为WRITE_FIRST或者NO_CHANGE时,另一个端口的读数据将是不可靠的。

参考资料:

Xilinx Block Memory Generator v8.4: pg058-blk-mem-gen.pdf

Logos Family FPGAs Dedicated RAM Module (DRM) User Guide:Logos.pdf

FPGA Architecture: Principles and Progression:casm2021_arch_survey.pdf