RAM IP 核简介
RAM 是随机存取存储器(Random Access Memory)的简称,它是一种易失性存储器,RAM 工作时可以随时从任意一个合法地址写入或读取数据。
Vivado 软件自带的 Block Memory Generator IP 核(缩写为 BMG,中文名为块 RAM 生成器),可以用来配置单口RAM、伪双口RAM、真双口RAM、ROM( ROM 是一种只读存储器,也就是说,在工作时只能读出数据,而不能写入数据)。对于单端口 RAM,读写操作共用一组地址端口和数据端口,因此读写操作不能同时进行;对于伪双端口 RAM,读操作和写操作分别有各自的地址端口和数据端口(一个读端口和一个写端口),使用时要避免读写冲突;对于真正双端口 RAM,则有两个可以进行读写的地址端口和数据端口,使用时要避免读写冲突和写写冲突(IP 核内提供几种解决读写冲突和写写冲突策略,使用时根据需要进行选择)。
注意:
Block Memory Generator IP 核配置生成的 RAM 或者 ROM 使用的都是 FPGA 内部的 BRAM 资源只不过配置成 ROM 时只用到了嵌入式 BRAM 的读数据端口。
单口 RAM 简介
单端口 RAM 的框图如下:
各个端口的功能描述如下:
单口 RAM 配置核生成
打开 BMG IP 核的“Customize IP”窗口
- Vivado 工程左侧“Flow Navigator”栏中的“IP Catalog”
- 在“IP Catalog”窗口的搜索栏中输入“Block Memory”关键字后,出现唯一匹配的“Block Memory Generator”
- 双击“Block Memory Generator”后弹出 IP 核的配置界面
BMG IP 核有关单口 RAM 的配置
Block Memory Generator IP核的 IP Catalog 窗口如下,主要包括一个IP名称输入框核4个选项卡,页面依次进行介绍。
- 在“Component Name”一栏可以设置该 IP 元件的名称
- “Basic”选项卡
(1)“lnterface Type(接口模式)”:有两种接口模式可选,分别为 Native(常规)接口和 AXI4 接口。AXI4 模式一般是在处理器中的数据需要和 BRAM 交互时才会使用,当不需要与处理器数据进行交互时一般采用 Native 模式。
(2) “Generate address interface with 32 bits”选项为是否生成位宽为 32 的地址接口,勾选后内存的数据位宽也必须设置成 32 的整数倍,一般不做勾选。
(3) “Memory Type(存储类型)”:有五种类型可选,分别为“Single Port RAM(单端口RAM)”、“Simple Dual Port RAM(伪双端口 RAM)”、“True Dual Port RAM(真双端口 RAM)”、“Single Port ROM(单端口 ROM)”和“Dual Port ROM(双端口 ROM)”,这里以单端口 RAM 为例。
(4) “Common Clock”选项:是否启用同步时钟,在单端口模式下不需要考虑这个问题。
(5) “ECC Options(ECC 选项)”:ECC纠错码选项只有在伪双端口 RAM 类型下才可以进行配置。
(6) “Write Enable(写使能)”:可以选择是否使用字节写使能功能,启用后可设置字节大小为 8 位或 9 位,需要注意的是启用后内存的数据位宽必须设置为所选字节大小的整数倍。
(7) “Algorithm Options(算法选项)”:算法选项主要用于决定 BRAM 的拼接的方式,一般在BRAM 深度、宽度较大的时候起作用,有三种算法可选,分别为“Minimum Area(最小面积算法)”、“Low Power(低功耗算法)”和“Fixed Primitives(固定单元算法)” - “Port A Options”选项卡
(1)“Memory Size(内存大小)”:用于指定端口读/写宽度和深度、运行模式和使能端口类型。
- Write Width 写数据位宽,单位 bit,本次实验我们设置成 8,可设置的位宽范围为 1~4608。
- Read Width 读数据位宽,其位宽设置必须与写数据位宽存在倍数关系(倍数比仅支持 1:1、1:2、1:4、1:8、2:1、4:1、8:1 和 16:1),通常情况下读/写数据位宽保持一致。
- Write Depth 写深度,即 RAM 所能访问的地址范围。这里有一点需要注意,那就是写深度和写位宽的乘积不要超过器件本身的 ram 资源的大小。
- Read Depth 读深度,当写数据位宽、读数据位宽和写深度的值确定后,读深度的值就会自动确定。
- Operating Mode RAM 运作模式,有三种模式可选,分别是Write First(写优先模式)、 Read First(读优先模式)、No Change(不变模式),单口 RAM 一般选 No Change(不变模式)。
- Enable Port Type 使能端口类型。有两种可选,分别为 Use ENA pin(添加使能端口 A 的信号)和 Always Enabled(取消使能信号,端口 A 一直处于使能状态)。
(2)“Port A Optional Output Register”:用于为 RAM 的输出端添加寄存器。其作用是提高 BRAM 的运行频率和改善时序,当然为此付出的代价就是每勾选一个寄存器,输出就会延迟一拍。 - Primitives Output Register 使用 BRAM 内部的寄存器打拍输出。
- Core Output Register 使用 SLICE 的寄存器打拍输出。
- SoftECC Input Register 当使用软 ECC 的时候,用 SLICE 的寄存器打拍。
- REGCEA,当使用 Primitives Output Register 或者 Core Output Register 时,可以用 REGCEA 来使能相应的输出。
(3)“Port A Output Reset Options”:用于配置端口的复位信号。可以添加一个复位信号(RSTA Pin)、配置复位时 RAM 输出总线上的数据值(Output Reset Value)、配置是否复位内置锁存器(Reset Memory Latch)、配置复位信号与时钟使能之间的优先级(Reset Priority)。
(4)“READ Address Change A”:用于更改端口的读地址,这个功能只在 UltraScale 设备上使用。
- “Other Options”选项卡
(1)“Pipeline Stages within Mux”:输出端 Mux 选择器的流水线级数。在大位宽、大深度的 BRAM 拼接场景中会用 MUX 来选择输出地址所对应的数据,勾选该选项后可以使输出数据具有更好的时序。
(2)“Memory Initialization(初始化文件)”:选择是否使用本地初始化文件(.coe 文件)来对存储空间进行初始化。
(3)“Structural/UniSim Simulation Model Options”:用于选择结构仿真模型发生碰撞时生成的警告消息和输出的类型。
(4)“Behavioral Simulation Model Options”:用于关闭仿真时的冲突告警和超出范围告警。 - “Summary”选项卡
该界面显示了配置的存储器的类型,消耗的 BRAM 资源等信息,检查没问题可以直接点击“OK”按钮生成 RAM IP 核。
在弹出的“Generate Output Products”窗口直接点击“Generate”即可。
模块设计
本次实验的用 Xilinx BMG IP 核配置成一个单端口的 RAM 并对其进行读写操作,系统框图如下:
编写代码
生成单口 RAM IP 核
单口 RAM IP 核的配置如下:
单口 RAM IP读写代码编写
在单口 RAM IP读写代码中先例化了一个单口 RAM IP 核,然后对其进行读写操作。
它在复位完成后便一直进行单口 RAM IP 核的读写操作,再每轮操作中都是先向RAM的地址0到31写入数据(共计32个),然后再将地址0到31的数据读出(共计32个),其RAM IP读写时序图如下:
代码如下:
`timescale 1ns / 1psmodule ram_ip_rw(input sys_clk, //系统时钟input sys_rst_n //系统复位,低电平有效
);//RAM 使能,高电平使能
reg ram_en;
//RAM 读写使能信号,高电平写入,低电平读出
wire ram_we;
//RAM 读写地址
wire [4:0] ram_addr;
//写入 RAM 的数据
wire [7:0] ram_wr_data;
//从 RAM 读取的数据
wire [7:0] ram_rd_data;//读写控制计数器,每次写入32个,读取32个,共计64个
reg [5:0] rw_count;//RAM 使能控制,高电平使能
always @(posedge sys_clk) beginif(!sys_rst_n)ram_en <= 0;elseram_en <= 1;
end//RAM 读写使能信号,高电平写入,低电平读出
//计数器0~31时写入,计数器31~63时读取
assign ram_we = ((rw_count <= 31) && (ram_en == 1)) ? 1 : 0;//RAM 读写地址,0~31
assign ram_addr = (ram_en == 1) ? rw_count[4:0] : 0;//写入 RAM 数据,从地址0~31依次写入如0~31
assign ram_wr_data = (ram_we == 1) ? rw_count[4:0] : 0;//读写计数器,从0~63进行计数
always @(posedge sys_clk) beginif(!sys_rst_n)rw_count <= 0;else if((rw_count < 63) && (ram_en == 1))rw_count <= rw_count + 1;elserw_count <= 0;
end//例化单口RAM IP核
blk_mem_gen_0 u_blk_mem_gen_0_inst0(.clka(sys_clk),.ena(ram_en),.wea(ram_we),.addra(ram_addr),.dina(ram_wr_data),.douta(ram_rd_data)
);endmodule
仿真激励代码编写
仿真激励代码非常简单,只需要例化 单口 RAM IP读写模块 ,然后产生一个周期时钟即可,完整的代码如下:
`timescale 1ns / 1ps //仿真单位/仿真精度module tb_ram_ip_rw();reg sys_clk; //系统时钟
reg sys_rst_n; //系统复位,低电平有效//信号初始化
initial beginsys_clk = 1'b0;sys_rst_n = 1'b0;#200sys_rst_n = 1'b1;
end//产生时钟
always #20 sys_clk = ~sys_clk;//例化需要仿真的IP核
ram_ip_rw tb_u_ram_ip_rw_inst0(.sys_clk(sys_clk), //系统时钟.sys_rst_n(sys_rst_n) //系统复位,低电平有效
);endmodule