双端口RAM IP核
双端口RAM IP核端口

端口A、端口B都是独立的使能端口、时钟
ADDRA:数据写入对应地址
WEA:读写控制信号
ENA:使能端口,高电平有效
RSTB:复位端口
REGCEB:寄存器使能端口
DOUTB:读出数据
红杠端口:ECC功能错误纠正,单比特纠正,双比特检错
双端口RAM IP核存在问题


实验任务
使用Vivado软件生成一个简单双端口的RAM并对其进行读写操作,然后通过仿真观察波形是否正确,最后通过在线调试工具对实验结果进行验证。如:将RAM设置的深度和宽度分别为64和8进行读写测试
系统框图

波形图

IP核配置



ram_rw读写模块代码
module ram_wr(
input clk , //时钟信号
input rst_n , //复位信号,低电平有效
//RAM写端口操作
output ram_wr_we , //ram写使能
output reg ram_wr_en , //端口使能
output reg rd_flag , //读启动信号
output reg [5:0] ram_wr_addr , //ram写地址
output [7:0] ram_wr_data //ram写数据
);
//*****************************************************
//** main code
//*****************************************************
//ram_wr_we为高电平表示写数据
assign ram_wr_we = ram_wr_en ;
//写数据与写地址相同,因位宽不等,所以高位补0
assign ram_wr_data = {2'b0,ram_wr_addr} ;
//控制RAM使能信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_wr_en <= 1'b0;
else
ram_wr_en <= 1'b1;
end
//写地址信号 范围:0~63
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_wr_addr <= 6'd0;
else if(ram_wr_addr < 6'd63 && ram_wr_we)
ram_wr_addr <= ram_wr_addr + 1'b1;
else
ram_wr_addr <= 6'd0;
end
//当写入32个数据(0~31)后,拉高读启动信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
rd_flag <= 1'b0;
else if(ram_wr_addr == 6'd31)
rd_flag <= 1'b1;
else
rd_flag <= rd_flag;
end
endmodule
ram_rw读写模块代码
module ram_rd(
input clk , //时钟信号
input rst_n , //复位信号,低电平有效
//RAM读端口操作
input rd_flag , //读启动标志
input [7:0] ram_rd_data, //ram读数据
output ram_rd_en , //端口使能
output reg [5:0] ram_rd_addr //ram读地址
);
//*****************************************************
//** main code
//*****************************************************
//控制RAM使能信号
assign ram_rd_en = rd_flag;
//读地址信号 范围:0~63
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_rd_addr <= 6'd0;
else if(ram_rd_addr < 6'd63 && ram_rd_en)
ram_rd_addr <= ram_rd_addr + 1'b1;
else
ram_rd_addr <= 6'd0;
end
endmodule
顶层模块代码,例化ram_rw,ram_rd模块和IP核
module ip_2port_ram(
input sys_clk , //系统时钟
input sys_rst_n //系统复位,低电平有效
);
//wire define
wire ram_wr_en ; //端口A使能
wire ram_wr_we ; //ram端口A写使能
wire ram_rd_en ; //端口B使能
wire rd_flag ; //读启动标志
wire [5:0] ram_wr_addr; //ram写地址
wire [7:0] ram_wr_data; //ram写数据
wire [5:0] ram_rd_addr; //ram读地址
wire [7:0] ram_rd_data; //ram读数据
//*****************************************************
//** main code
//*****************************************************
//RAM写模块
ram_wr u_ram_wr(
.clk (sys_clk ),
.rst_n (sys_rst_n ),
.rd_flag (rd_flag ),
.ram_wr_en (ram_wr_en ),
.ram_wr_we (ram_wr_we ),
.ram_wr_addr (ram_wr_addr),
.ram_wr_data (ram_wr_data)
);
//简单双端口RAM
blk_mem_gen_0 u_blk_mem_gen_0 (
.clka (sys_clk ), // input wire clka
.ena (ram_wr_en ), // input wire ena
.wea (ram_wr_we ), // input wire [0 : 0] wea
.addra (ram_wr_addr), // input wire [5 : 0] addra
.dina (ram_wr_data), // input wire [7 : 0] dina
.clkb (sys_clk ), // input wire clkb
.enb (ram_rd_en ), // input wire enb
.addrb (ram_rd_addr), // input wire [5 : 0] addrb
.doutb (ram_rd_data) // output wire [7 : 0] doutb
);
//RAM读模块
ram_rd u_ram_rd(
.clk (sys_clk ),
.rst_n (sys_rst_n ),
.rd_flag (rd_flag ),
.ram_rd_en (ram_rd_en ),
.ram_rd_addr (ram_rd_addr),
.ram_rd_data (ram_rd_data)
);
ila_0 u_ila_0 (
.clk (sys_clk ), // input wire clk
.probe0 (ram_wr_en ), // input wire [0:0] probe0
.probe1 (ram_wr_we ), // input wire [0:0] probe1
.probe2 (ram_rd_en ), // input wire [0:0] probe2
.probe3 (rd_flag ), // input wire [0:0] probe3
.probe4 (ram_wr_addr), // input wire [5:0] probe4
.probe5 (ram_wr_data), // input wire [7:0] probe5
.probe6 (ram_rd_addr), // input wire [5:0] probe6
.probe7 (ram_rd_data) // input wire [7:0] probe7
);
endmodule
FPGA激励文件(Testbench)编写,其用于验证FPGA设计功能正确性的测试脚本,通过模拟输入信号并检查输出响应,确保设计符合预期。
`timescale 1ns / 1ps //仿真单位/仿真精度
module tb_ip_2port_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_2port_ram u_ip_2port_ram(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n )
);
endmodule
单端口RAM IP核的仿真

.xdc文件
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]