RAM:是英文Random Access Memory的缩写,即随机存取存储器,也叫主存,是与CPU直接交换数据的内部存储器。相对FIFO来说,RAM工作时可随时从任何一个指定地址写入或读出信息。
在QuartusII中,生成RAM IPCORE时有两种可选
我们先生成一个写数据位宽8,读数据位宽8的单口RAM,利用Modelsim仿真来观察单口RAM的时序波形。
2.1 首先打开QuartusII软件,新建一个工程,命令为single_ram_test
新建工程的步骤就不一一说明,为了方便上板验证,选用我们开发板上的器件:EP4CE6F17C8
2.2 单口RAM IPCORE配置
2.2.1 生成IPCORE,命名为single_ram_w8r8_d1024
我们在对IPCORE命名时,最好能体现出该IPCORE的一些主要特性,比如我们上面的命名,我们知道是一个单口RAM,写数据位宽8,读数据位宽8,深度1024。
生成步骤如下图所示:
当生成好后可以看到左边RAM框图已经显示出了RAM的输入输出接口,同时在左下角还能看到这个RAM需要占用的资源情况。
2.2.2 RAM接口定义如下:
aclr:异步清零信号,高电平有效。该清零信号只能清楚输出端口的数据,并不会清除存储器内部存储的内容。
address:地址线,位宽为10bit。由于我们调用的 RAM 为单口 RAM,所以只有一组地址线。
clock:读写时钟。
data:写入 RAM 的数据,位宽为 8bit。
rd_en:读使能信号,高电平有效。该信号在配置时刻可选择不生成。
wr_en:写使能信号,高电平有效。在 RAM 中,该信号固定存在。
q:读出 RAM 中的数据,位宽也是 8bit。
其中“ q”为输出信号,其余信号都为该模块的输入信号,需要我们产生输入。为了测试生成的RAM IPCORE,我们做一个测试例程,向RAM地址0到3中写入4个数据,然后再从地址3~0,把数据读出来,看一下读出的数据和写入的数据是否一致。我们通过仿真来验证。
`timescale 1ns / 100ps
module single_ram_test(
input clk ,//时钟,频率50MHZ
input rst_n ,//复位信号,低电平有效
output [7:0] dout //ram输出数据
);
reg [8:0] cnt;
wire[9:0] address;
reg [7:0] wrdata;
reg [1:0] wraddr;
reg [1:0] rdaddr;
reg wren;
reg rden;
//用assign做一个选择,当wren为高电平时,输入ram的地址等于写ram地址,
//否则输入ram的地址等于读ram地址
assign address=(wren)?{8'h00,wraddr}:{8'h00,rdaddr};
//计数器,以此计数器来生成RAM读写使能及读写地址和写的数据
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt<=0;
else
cnt<=cnt+1;
end
//生成写地址,写数据和写使能
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
wraddr <=3;
wrdata <=0;
wren <=0;
end else if(cnt>0&&cnt<=4)begin
wraddr <=wraddr+1;
wrdata <=cnt;
wren <=1;
end else begin
wraddr <=3;
wren <=0;
end
end
//生成读地址和读使能
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rdaddr <=0;
rden <=0;
end else if(cnt>5&&cnt<=9)begin
rdaddr <=rdaddr-1;
rden <=1;
end else begin
rdaddr <=0;
rden <=0;
end
end
//例化RAM IPCORE
single_ram_w8r8_d1024 Usingle_ram_w8r8_d1024 (
.aclr (~rst_n ),//异步清零信号
.address (address ),//读写地址线
.clock (clk ),//使用系统时钟作为读写时钟
.data (wrdata ),//写入 RAM 的数据
.wren (wren ),//写 RAM 使能
.rden (rden ),//输出读 RAM 数据
.q (dout ) //输出读 RAM 数据
);
endmodule
`timescale 1ns / 100ps
module single_ram_test_tb;
reg clk =1;
reg rst_n =0;
initial
begin
#1000
rst_n=1;
end
//生成激励时钟
always #10 clk<=~clk;
//例化被测试模块
single_ram_test Usingle_ram_test(
.clk (clk),//50MHZ
.rst_n (rst_n),
.dout ()
);
endmodule
通过上面的仿真图,我们可以看到,当wren为高电平时,写入的地址依次是0,1,2,3,写入的数据依次是1,2,3,4。这样就相当于建立了一张表,如下图所示:
那么如果我们读地址3的数据就应该是4,地址2的数据是3,地址1的数据是2,地址0的数据是1。可以看到仿真波形中,当rden为高电平时,读地址依次是3,2,1,0,读出的数据依次是4,3,2,1(有效数据在rden拉高后延时一个时钟周期才输出),与存储的表格相符。
如果大家想要该工程的源码,测试激励文件用来学习,可以直接联系工程师,感谢大家的阅读!