使用XPM原语
构建URAM模块
URAM模块的端口与BRAM完全相似,但是在配置URAM的时候有细微的差别
1.URMA不支持用IP核调用,但可以使用XPM原语
2. 自定义URAM的配置,调节输入和写入端口的地址宽度修改两个参数ADDR_WIDTH_A
和
ADDR_WIDTH_B
,调节输入和写入端口的数据宽度修改两个参数READ_DATA_WIDTH_A
和
READ_DATA_WIDTH_B
,根据以上的数据手动计算出内存大小MEMORY_SIZE= 2^ADDR_WIDTH_A*READ_DATA_WIDTH_A
3.指定B端口的写入模式,写入模式有两种分别是“read_first”和“write_first”,两者的显著区别是当需要在同一个位置中读写数据时,read_first会首先读取内存中旧的数据,write_first 则会用新数据覆盖掉旧数据,读取到最新的数据。在read_first模式下READ_LATENCY_B
的延迟为两个周期而在write_first模式下READ_LATENCY_B
的延迟为三个周期。为了与带有primitive output registers 的BRAM存储器的读写周期匹配,因此选择read_first模式
4.用MEMORY_INIT_FILE初始化URAM模块时,可以直接从文件中读取,但是文件格式必须是.mem类型的存储文件。保存.mem文件的技巧是,在记事本中另存文件时,将文件名包括扩展名用双引号括起来,例如输入"uram_init.mem"。确保"保存类型"设置为所有文件。特别注意,在Verilog文件中引用文件时,使用正斜杠(/)而不是反斜杠()作为路径分隔符
// xpm_memory_sdpram: Simple Dual Port RAM
// Using URAM in Xilinx FPGAs with Xilinx Parameterized Macros
module URAM_Module_a_im_0(
input wire clka, // A端口的时钟信号
input wire ena, // A端口的使能信号。当为高电平时,允许对RAM的访问。
input wire wea, // A端口的写使能信号。当为高电平且ena也为高电平时,允许数据写入。
input wire [17:0] addra, // A端口的写地址。
input wire [31:0] dina, // A端口的写入数据。
input wire clkb, // B端口的时钟信号。在此例中,A和B端口共用相同的时钟信号。
input wire [17:0] addrb, // B端口的读地址。
input wire enb, // B端口的使能信号。当为高电平时,允许从RAM读取数据。
output wire [31:0] doutb // B端口的读出数据。
);
// 参数化的XPM RAM配置
xpm_memory_sdpram #(
.ADDR_WIDTH_A(18), // A端口地址宽度
.ADDR_WIDTH_B(18), // B端口地址宽度
.AUTO_SLEEP_TIME(0), // 自动休眠时间配置,0表示禁用
.BYTE_WRITE_WIDTH_A(32), // A端口的字节写入宽度,此处设定为32位全宽写入
.CASCADE_HEIGHT(0), // 级联高度,0表示不使用级联
.CLOCKING_MODE("common_clock"), // 时钟模式配置,此处A和B端口共用时钟
.ECC_MODE("no_ecc"), // ECC模式配置,此处不使用ECC
.MEMORY_INIT_FILE("D:/FFT_Paper_Code/MDC/memory/input_bank1_a_im.mem"), // 内存初始化文件,此处使用
.MEMORY_INIT_PARAM("0"), // 内存初始化参数,此处不使用
.MEMORY_OPTIMIZATION("true"), // 启用内存优化
.MEMORY_PRIMITIVE("ultra"), // 使用URAM
.MEMORY_SIZE(8388608), // 内存大小配置,以位为单位
.MESSAGE_CONTROL(0), // 消息控制,此处禁用
.READ_DATA_WIDTH_B(32), // B端口的读数据宽度
.READ_LATENCY_B(2), // B端口的读延迟
.READ_RESET_VALUE_B("0"), // 读复位值
.RST_MODE_A("SYNC"), // A端口复位模式,同步复位
.RST_MODE_B("SYNC"), // B端口复位模式,同步复位
.SIM_ASSERT_CHK(0), // 模拟断言检查,0表示禁用
.USE_MEM_INIT(1), // 使用内存初始化
.WAKEUP_TIME("disable_sleep"), // 唤醒时间配置,此处禁用睡眠模式
.WRITE_DATA_WIDTH_A(32), // A端口的写数据宽度
.WRITE_MODE_B("read_first") // B端口的写模式
) xpm_memory_sdpram_inst (
.dbiterrb(), // 双位错误状态,此处未使用
.doutb(doutb), // B端口的读出数据
.sbiterrb(), // 单位错误状态,此处未使用
.addra(addra), // A端口的写地址
.addrb(addrb), // B端口的读地址
.clka(clka), // A端口的时钟信号
.clkb(clkb), // B端口的时钟信号(共用)
.dina(dina), // A端口的写入数据
.ena(ena), // A端口的使能信号
.enb(enb), // B端口的使能信号
.injectdbiterra(1'b0), // 双位错误注入信号,此处未使用
.injectsbiterra(1'b0), // 单位错误注入信号,此处未使用
.regceb(1'b1), // 输出寄存器的时钟使能,此处始终使能
.sleep(1'b0), // 睡眠模式信号,此处未使用
.wea(wea) // A端口的写使能信号
);
endmodule