RAM(Random Access Memory),即随机存取存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据, 其读写速度是由时钟频率决定的。
RAM主要用来存放程序及程序执行过程中产生的中间数据、 运算结果等。
1.新建ram ip核,在ip catalog中搜索ram 选择如图选项
然后新建ip core文件夹,将其存为ram_1port
开始设计ip 核,将深度设为8,宽度设为32,ip核用什么单位搭起来选择auto,然后输入输出数据的时钟选择一个时钟控制,然后点击next
取消添加q寄存器,让输出缓存。然后勾上创建一个读使能信号
为了避免同时对一个值进行读写操作,所以选择读出的数据为don‘t care
第一个里面选择no就是不更新ROM里面的数据,选择yes就是要更新,然后下面有一个browse,就可以加载数据文件进去。然后下面那个如果勾选的话,就是允许在线更新ROM数据。这里如下图选择,然后一直点击next
到这里时,要勾选如图文件,方便例化ip 核
然后点击finish,完成ip核设计
2.编写程序,首先是读写模块
module ram_rw(
input clk , //时钟信号
input rst_n , //复位信号,低电平有效
output ram_wr_en , //ram写使能
output ram_rd_en , //ram读使能
output reg [4:0] ram_addr , //ram读写地址
output reg [7:0] ram_wr_data, //ram写数据
input [7:0] ram_rd_data //ram读数据
);
//reg define
reg [5:0] rw_cnt ; //读写控制计数器
//*****************************************************
//** main code
//*****************************************************
//rw_cnt计数范围在0~31,ram_wr_en为高电平;32~63时,ram_wr_en为低电平
assign ram_wr_en = ((rw_cnt >= 6'd0) && (rw_cnt <= 6'd31)) ? 1'b1 : 1'b0;
//rw_cnt计数范围在32~63,ram_rd_en为高电平;0~31时,ram_rd_en为低电平
assign ram_rd_en = ((rw_cnt >= 6'd32) && (rw_cnt <= 6'd63)) ? 1'b1 : 1'b0;
//读写控制计数器,计数器范围0~63
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
rw_cnt <= 6'd0;
else if(rw_cnt == 6'd63)
rw_cnt <= 6'd0;
else
rw_cnt <= rw_cnt + 6'd1;
end
//读写控制器计数范围:0~31 产生ram写使能信号和写数据信号
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
ram_wr_data <= 8'd0;
else if(rw_cnt >= 6'd0 && rw_cnt <= 6'd31)
ram_wr_data <= ram_wr_data + 8'd1;
else
ram_wr_data <= 8'd0;
end
//读写地址信号 范围:0~31
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
ram_addr <= 5'd0;
else if(ram_addr == 5'd31)
ram_addr <= 5'd0;
else
ram_addr <= ram_addr + 1'b1;
end
endmodule
然后是顶层模块
module ip_ram(
input sys_clk , //系统时钟
input sys_rst_n //系统复位,低电平有效
);
//wire define
wire ram_wr_en ; //ram写使能
wire ram_rd_en ; //ram读使能
wire [4:0] ram_addr ; //ram读写地址
wire [7:0] ram_wr_data ; //ram写数据
wire [7:0] ram_rd_data ; //ram读数据
//*****************************************************
//** main code
//*****************************************************
//ram读写模块
ram_rw u_ram_rw(
.clk (sys_clk),
.rst_n (sys_rst_n),
.ram_wr_en (ram_wr_en ),
.ram_rd_en (ram_rd_en ),
.ram_addr (ram_addr ),
.ram_wr_data (ram_wr_data),
.ram_rd_data (ram_rd_data)
);
//ram ip核例化
ram_1port u_ram_1port(
.address (ram_addr),
.clock (sys_clk),
.data (ram_wr_data),
.rden (ram_rd_en),
.wren (ram_wr_en),
.q (ram_rd_data)
);
endmodule
然后在modelsim中看波形
测试文件如图
`timescale 1 ns/ 1 ns
module ip_ram_tb();
parameter T = 20;
reg sys_clk;
reg sys_rst_n;
wire ram_wr_en ; //ram写使能
wire ram_rd_en ; //ram读使能
wire [4:0] ram_addr ; //ram读写地址
wire [7:0] ram_wr_data ; //ram写数据
wire [7:0] ram_rd_data ; //ram读数据
initial
begin
sys_clk = 1'b0;
sys_rst_n = 1'b0;
#200
sys_rst_n = 1'b1;
//模拟发送一帧数据
#1500000 $stop;
end
always #(T/2) sys_clk = ~sys_clk;
//ram读写模块
ram_rw u_ram_rw(
.clk (sys_clk),
.rst_n (sys_rst_n),
.ram_wr_en (ram_wr_en ),
.ram_rd_en (ram_rd_en ),
.ram_addr (ram_addr ),
.ram_wr_data (ram_wr_data),
.ram_rd_data (ram_rd_data)
);
//ram ip核例化
ram_1port u_ram_1port(
.address (ram_addr),
.clock (sys_clk),
.data (ram_wr_data),
.rden (ram_rd_en),
.wren (ram_wr_en),
.q (ram_rd_data)
);
endmodule