一、RAM简介与实验任务
1.1 RAM简介
RAM,即随机存取存储器,简称随机存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址的存储单元中读出数据,其读写速度是由时钟频率决定的。存储器的大致分类,如下图所示:
存储器包括随机存储器和只读存储器,随机存储器包括静态 RAM 和动态 RAM。静态RAM 只要有供电,它保存的数据就不会丢失;而动态 RAM 在供电的情况下,还需要根据其要求的时间来对存储的数据进行刷新,才能保持存储的数据不会丢失。
只读存储器一般包括 PROM、EPROM 和 EEPROM 等,是非易失性的存储器。目前使用率较高的是EEPROM,其特点是容量相对较小,存储的一般是器件的配置参数信息。
单端口 RAM 只有一个端口进行读写,即读/写只能通过这一个端口来进行。对于伪双端口 RAM 而言,其也有两个端口可以用于读写,但是其中一个端口只能读不能写,另一个端口只能写不能读;对于真双端口 RAM 而言,其有两个端口可以用于读写,且两个端口都可以进行读或写;
1.2 实验任务
将 Xilinx BMG IP 核配置成一个单端口的 RAM 并对其进行读写操作,然后通过仿真观察波形是否正确,最后将设计下载到 FPGA 开发板中,并通过在线调试工具对实验结果进行验证。
二、程序设计
2.1 单端口RAM IP核的配置
在vivado中新建一个工程,在软件左侧找到IP Catalog,这里存在许多IP核。在搜索栏输入Block Memory,找到如下图所示的IP核:
双击“Block Memory Generator”后弹出 IP 核的配置界面,接着我们就可以对 BMG IP 核进行配置了,“Basic”选项卡配置界面如下图所示。
Port A Options选项卡配置界面如下图所示:
其他两个页面配置都保持默认选项。
2.2 模块设计
读写模块框图如下图所示:
绘制波形图:
RTL代码ram_rw.v如下:
module ram_rw(
input clk,
input rst_n,
input [7:0] ram_rd_data,
output reg ram_en,
output ram_we,
output reg [4:0] ram_addr,
output reg [7:0] ram_wr_data
);
reg [5:0] rw_cnt; //计数从0-63,0-31时写数据,32-63时读数据。
assign ram_we = (rw_cnt < 5'd32 && ram_en == 1'b1) ? 1'd1 : 1'd0;
//使能RAM
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_en <= 1'b0;
else
ram_en <= 1'b1;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
rw_cnt <= 6'd0;
else if(ram_en == 1'b1) begin
if(rw_cnt == 6'd63)
rw_cnt <= 6'd0;
else
rw_cnt <= rw_cnt + 6'd1;
end
else
rw_cnt <= 6'd0;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_addr <= 5'd0;
else if(ram_en == 1'b1) begin
if(ram_addr == 5'd31)
ram_addr <= 5'd0;
else
ram_addr <= ram_addr +5'd1;
end
else
ram_addr <= 5'b0;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_wr_data <= 8'd0;
else if(ram_wr_data < 8'd31 && ram_we)
ram_wr_data <= ram_wr_data + 8'd1;
else
ram_wr_data <= 8'd0;
end
endmodule
顶层模块来例化 IP 核与读写模块,顶层模块如下:
module ip_1port_ram(
input sys_clk,
input sys_rst_n
);
wire ram_en;
wire ram_we;
wire [4:0] ram_addr;
wire [7:0] ram_rd_data;
wire [7:0] ram_wr_data;
blk_mem_gen_0 u_blk_mem_gen_0(
.clka(sys_clk), // input wire clka
.ena(ram_en), // input wire ena
.wea(ram_we), // input wire [0 : 0] wea
.addra(ram_addr), // input wire [4 : 0] addra
.dina(ram_wr_data), // input wire [7 : 0] dina
.douta(ram_rd_data) // output wire [7 : 0] douta
);
ram_rw u_ram_rw(
.clk (sys_clk),
.rst_n (sys_rst_n),
.ram_rd_data(ram_rd_data),
.ram_en (ram_en),
.ram_we (ram_we),
.ram_addr (ram_addr),
.ram_wr_data(ram_wr_data)
);
endmodule
2.3 Modelism联合仿真
仿真模块代码如下:
`timescale 1ns/1ns
module tb_ip_1port_ram();
parameter CLK_PERIOD = 20;
reg sys_clk; //周期20ns
reg sys_rst_n;
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
ip_1port_ram u_ip_1port_ram(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n)
);
endmodule
仿真结果: