简单双口RAM有两个端口Port A和port B,其中Port A用于写数据,Port B用于读数据,读写接口可以独立时钟工作。这一点和真双口RAM是有区别的,真双口RAM的A B两个Port都可以进行读写操作。
RAM是FPGA中重要的数据结构,可用于数据的缓存和跨时钟域信号处理。本文就xilink 的简单双口RAM 进行读写测试。
本文对简单双口RAM做如下仿真:先对Port A进行连续写操作128次,每次数据和地址加1,结束后开始从Port B口读对应128个地址的数据,读写时钟独立,对比读写数据是否一致。
仿真结果如下:
数据写入仿真
数据读出仿真,数据在地址变化后延迟一个时钟输出。
ram ip的设置如下
注意不要勾选 Primitives Output Regster,不然Port B数据会延迟两个周期。
简单双口RAM的接口定义如下
直接上代码 dual_ram_top.v
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/03/22 20:18:12
// Design Name:
// Module Name: dual_ram_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module dual_ram_top(
input clka,
input clkb,
input rst_n,
output [7:0] doutb
);
reg [7:0]dina;
reg [12:0] addra;
reg ena;
reg wea;
reg [3:0] wr_state;
always@(posedge clka or negedge rst_n) begin
if(!rst_n) begin
wr_state <= 4'd0;
ena <= 1'b0;
wea <= 1'b0;
dina <= 8'd0;
addra <= 13'd0;
end
else begin
case(wr_state)
4'd0:begin
wr_state <= 4'd1;
wea <= 1'b1; // 写使能
end
4'd1:begin
wr_state <= 4'd2;
addra <= 13'd0;
dina <= 8'd0;
ena <= 1'b1;
end
4'd2:begin
if(addra == 13'd127) begin
wr_state <= 4'd3;
ena <= 1'b0;
addra <= 13'd0;
dina <= 8'd0;
end
else begin
wr_state <= wr_state;
addra <= addra + 13'd1;
dina <= dina + 8'd1;
ena <= 1'b1;
end
end
4'd3:begin // write end
wr_state <= 4'd4;
wea <= 1'b0; // 读使能
end
4'd4:begin
wr_state <= wr_state;
end
endcase
end
end
wire rd_start;
assign rd_start =(wr_state==4'd4)?1:0;
reg [12:0] addrb;
reg enb;
reg [3:0] rd_state;
always@(posedge clkb or negedge rst_n) begin
if(!rst_n) begin
rd_state <= 4'd0;
enb <= 1'b0;
addrb <= 13'd0;
end
else begin
case(rd_state)
4'd0:begin
if(rd_start) begin
rd_state <= 4'd1;
enb <= 1'd1;
addrb <= 13'd0;
end
else begin
rd_state <= rd_state;
enb <= 1'd0;
addrb <= 13'd0;
end
end
4'd1:begin
if(addrb == 13'd127) begin
rd_state <= 4'd2;
enb <= 1'd0;
addrb <= 13'd0;
end
else begin
rd_state <= rd_state;
enb <= 1'd1;
addrb <= addrb +13'd1;
end
end
4'd2:begin
rd_state <= rd_state;
enb <= 1'd0;
addrb <= 13'd0;
end
endcase
end
end
blk_mem_gen_0 blk_mem_gen_uut0 (
.clka(clka), // input wire clka
.ena(ena), // input wire ena
.wea(wea), // input wire [0 : 0] wea
.addra(addra), // input wire [12 : 0] addra
.dina(dina), // input wire [7 : 0] dina
.clkb(clkb), // input wire clkb
.enb(enb), // input wire enb
.addrb(addrb), // input wire [12 : 0] addrb
.doutb(doutb) // output wire [7 : 0] doutb
);
endmodule
仿真测试代码ram_wr_top.v
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/03/22 22:27:59
// Design Name:
// Module Name: ram_wr_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module ram_wr_top(
);
reg clka;
reg clkb;
reg rst_n;
wire [7:0]doutb;
localparam clk_prioda = 50;
localparam clk_priodb = 20;
initial begin
clka =1'b0;
clkb = 1'b0;
rst_n = 1'b0;
#(100)
rst_n = ~rst_n;
end
always#(clk_prioda/2) clka = ~clka;
always#(clk_priodb/2) clkb = ~clkb;
dual_ram_top dual_ram_top_uut0(
.clka(clka),
.clkb(clkb),
.rst_n(rst_n),
.doutb(doutb)
);
endmodule
通过连续读写对比 验证了IP读写的一致性。