单端口RAM IP核
RAM
RAM(Random Access Memory ):即随机访问存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据,其读写速度是由时钟频率决定的。RAM主要用来存放程序及程序执行过程中产生的中间数据、运算结果等。
RAM的分类

单端口RAM IP核端口

DINA:数据写入端口
ADDRA:数据写入对应地址
WEA:读写控制信号
ENA:使能端口,高电平有效
RSTA:复位端口
REGCEA:寄存器使能端口
CLKA:时钟
DOUTA:读出数据
实验任务
使用Vivado软件生成一个单端口的RAM并对其进行读写操作,然后通过仿真观察波形是否正确,最后通过在线调试工具对实验结果进行验证。如:将RAM设置的深度和宽度分别为32和8进行读写测试。
系统框图


波形图

IP核配置


ram_rw读写模块代码
module ram_rw(
input clk , //时钟信号
input rst_n , //复位信号,低电平有效
output reg ram_en , //ram使能信号
output ram_we , //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,写入数据;32~63时,读出数据
assign ram_we = (rw_cnt <= 6'd31 && ram_en == 1'b1) ? 1'b1 : 1'b0;
//控制RAM使能信号
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
ram_en <= 1'b0;
else
ram_en <= 1'b1;
end
//读写控制计数器,计数器范围0~63
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
rw_cnt <= 6'b0;
else if(rw_cnt == 6'd63 && ram_en)
rw_cnt <= 6'b0;
else if(ram_en)
rw_cnt <= rw_cnt + 1'b1;
else
rw_cnt <= 6'b0;
end
//读写地址信号 范围:0~31
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
ram_addr <= 5'b0;
else if(ram_addr == 5'd31 && ram_en)
ram_addr <= 5'b0;
else if (ram_en)
ram_addr <= ram_addr + 1'b1;
else
ram_addr <= 5'b0;
end
//在WE拉高期间产生RAM写数据,变化范围是0~31
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
ram_wr_data <= 8'b0;
else if(ram_wr_data < 8'd31 && ram_we)
ram_wr_data <= ram_wr_data + 1'b1;
else
ram_wr_data <= 8'b0 ;
end
ila_0 u_ila_0 (
.clk(clk), // input wire clk
.probe0(ram_en), // input wire [0:0] probe0
.probe1(ram_we), // input wire [0:0] probe1
.probe2(ram_addr), // input wire [4:0] probe2
.probe3(ram_wr_data),// input wire [7:0] probe3
.probe4(ram_rd_data) // input wire [7:0] probe4
);
endmodule
顶层模块代码,例化ram_rw模块和IP核
module ram_rw(
input clk , //时钟信号
input rst_n , //复位信号,低电平有效
output reg ram_en , //ram使能信号
output ram_we , //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,写入数据;32~63时,读出数据
assign ram_we = (rw_cnt <= 6'd31 && ram_en == 1'b1) ? 1'b1 : 1'b0;
//控制RAM使能信号
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
ram_en <= 1'b0;
else
ram_en <= 1'b1;
end
//读写控制计数器,计数器范围0~63
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
rw_cnt <= 6'b0;
else if(rw_cnt == 6'd63 && ram_en)
rw_cnt <= 6'b0;
else if(ram_en)
rw_cnt <= rw_cnt + 1'b1;
else
rw_cnt <= 6'b0;
end
//读写地址信号 范围:0~31
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
ram_addr <= 5'b0;
else if(ram_addr == 5'd31 && ram_en)
ram_addr <= 5'b0;
else if (ram_en)
ram_addr <= ram_addr + 1'b1;
else
ram_addr <= 5'b0;
end
//在WE拉高期间产生RAM写数据,变化范围是0~31
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
ram_wr_data <= 8'b0;
else if(ram_wr_data < 8'd31 && ram_we)
ram_wr_data <= ram_wr_data + 1'b1;
else
ram_wr_data <= 8'b0 ;
end
ila_0 u_ila_0 (
.clk(clk), // input wire clk
.probe0(ram_en), // input wire [0:0] probe0
.probe1(ram_we), // input wire [0:0] probe1
.probe2(ram_addr), // input wire [4:0] probe2
.probe3(ram_wr_data),// input wire [7:0] probe3
.probe4(ram_rd_data) // input wire [7:0] probe4
);
endmodule
FPGA激励文件(Testbench)编写,其用于验证FPGA设计功能正确性的测试脚本,通过模拟输入信号并检查输出响应,确保设计符合预期。
`timescale 1ns / 1ps //仿真单位/仿真精度
module tb_ip_1port_ram();
//parameter define
parameter CLK_PERIOD = 20; //时钟周期 20ns
//reg define
reg sys_clk;
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