前言
本文不介绍RAM的基本概念,适用于快速上手使用RAM IP核
一、伪双端口RAM IP核配置
“ECC(全称 Error Correcting Code,即纠错码) Options”,纠错码选项只有在伪双端口 RAM类型下才可以进行配置。
“Write Enable(写使能)”:可以选择是否使用字节写使能功能,启用后可设置字节大小为 8位(无奇偶校验)或 9 位(包括奇偶校验),需要注意的是启用后内存的数据位宽必须设置为所选字节大小的整数倍。
“Algorithm Options(算法选项)”:算法选项主要用于决定 BRAM 的拼接的方式,一般在BRAM 深度、宽度较大的时候起作用,有三种算法可选,分别为“Minimum Area(最小面积算法)”、“Low Power(低功耗算法)”和“Fixed Primitives(固定单元算法)”。
Operating Mode:RAM 运作模式。该选项决定了我们在进行写操作期间,DOUT(读数据线)上的数据变化,有三种模式可选,分别为:
①Write First(写优先模式):当我们在对某个地址进行写操作时,则会将写入的数据传递到读数据线
上。
②Read First(读优先模式):当我们在对某个地址进行写操作时,则会将上次写入该地址的数据递到读
数据线上。
③No Change(不变模式):在该模式下,进行写操作时,读数据线上的数据保持不变。
注意是,若勾选Primitives Output Register的话,读数据会多延迟一个时钟周期
二、IP核读写测试
1.IP核端口介绍
2.测试代码
`timescale 1ns / 1ps
module RAM_top(
input clk,
input rst,
input data_in_flag,
input [11:0] data_in,
output [11:0] data_rd
);
reg wea;
always@(posedge clk or negedge rst)
begin
if(~rst)
wea <= 0;
else wea <= 1;
end
reg data_in_flag0;
reg data_in_flag1;
always @(posedge clk or negedge rst)
begin
if(~rst) begin
data_in_flag0 <= 0;
data_in_flag1 <= 0;
end
else begin
data_in_flag0 <= data_in_flag;
data_in_flag1 <= data_in_flag0;
end
end
wire data_in_flag_pose;
wire data_in_flag_nege;
assign data_in_flag_pose = (data_in_flag0)&(!data_in_flag1);
assign data_in_flag_nege = (!data_in_flag0)&(data_in_flag1);
reg wirte_flag;
reg read_flag;
reg read_en;
always @(posedge clk or negedge rst)
begin
if(~rst) begin
wirte_flag <= 0;
read_flag <= 0;
read_en <= 0;
end
else if(data_in_flag_pose)begin
wirte_flag <= 1;
read_flag <= 0;
end
else if(data_in_flag_nege)begin
wirte_flag <= 0;
read_flag <= 1;
read_en <= 1;
end
else if(read_done)begin
wirte_flag <= 0;
read_flag <= 0;
end
else begin
wirte_flag <= wirte_flag;
read_flag <= read_flag;
read_en <= 0;
end
end
reg [10:0] addr;
reg read_done;
reg [10:0] addr_temp;
always @(posedge clk or negedge rst)
begin
if(~rst) begin
addr <= 0;
addr_temp <= 0;
read_done <= 0;
end
else if(data_in_flag_pose)begin
addr <= 0;
addr_temp <= 0;
end
else if(wirte_flag)begin
addr <= addr + 1;
addr_temp <= addr;
end
else if(read_en)begin
addr <= 0;
end
else if(read_flag)begin
addr <= addr + 1;
if(addr == addr_temp)begin
read_done <= 1;
end
end
else begin
addr <= 0;
addr_temp <= 0;
read_done <= 0;
end
end
RAM0 RAM0(
.clka(clk), //写时钟
.ena(wirte_flag), //端口a使能
.wea(wea), //端口a写使能
.addra(addr), //写地址
.dina(data_in), //写入数据
.clkb(clk), //读时钟
.enb(read_flag), //端口b使能
.addrb(addr), //读地址
.doutb(data_rd) //输出数据
);
endmodule
3.测试结果
3.1写端
使用本算法进行伪双端RAM的操作写端的数据data_in需要延迟写信号data_in_flag两个时钟周期
3.2读端
读端由于没有选择输出端加一个寄存器的选项,因此输入地址,在下一个时钟周期便可以输出RAM里的数据。
由于地址125的位置没有数据写入,因此读出的为默认值0.