Dual-port RAM design
Introduction to dual-port RAM
A single port has only one set of data lines and address lines, so reading and writing cannot be performed at the same time; a dual port has two sets of data lines and address lines, and reading and writing can be performed at the same time.
Dual-port RAM is a memory that has two completely independent data lines, address lines, and read-write control lines on a memory, and allows two independent systems to perform random read and write access to the memory simultaneously and asynchronously.
Dual-port RAM can be used to improve RAM throughput and is suitable for real-time data caching.
Dual-port RAM example
The following program implements a dual-port RAM, one of which is write-only and the other is read-only. Reading and writing can be performed simultaneously and asynchronously.
dualram.v
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 2020/12/08
// Author Name: Sniper
// Module Name: dualram
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module dualram
#(
parameter WIDTH = 32,
parameter DEPTH = 1024
)
(
input wr_clk,
input [$clog2(DEPTH)-1:0] wr_addr,
input [WIDTH-1:0] wr_data,
input wr_en,
input rd_clk,
input [$clog2(DEPTH)-1:0] rd_addr,
output reg [WIDTH-1:0] rd_data,
input rd_en
);
localparam ADDR_WIDTH = $clog2(DEPTH);//$clog2(8)=3; $clog2(9)=4;
reg [WIDTH-1:0] mem[DEPTH-1:0];
always@(posedge wr_clk)
begin
if(wr_en)
mem[wr_addr] <= wr_data;
end
always@(posedge rd_clk)
begin
if(rd_en)
rd_data <= mem[rd_addr];
end
endmodule
tb_dualram.v
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 2020/12/08
// Author Name: Sniper
// Module Name: tb_dualram
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module tb_dualram;
//parameter
parameter WIDTH = 32;
parameter DEPTH = 1024;
//input
reg wr_clk;
reg [$clog2(DEPTH)-1:0] wr_addr;
reg [WIDTH-1:0] wr_data;
reg wr_en;
reg rd_clk;
reg [$clog2(DEPTH)-1:0] rd_addr;
reg rd_en;
//output
wire [WIDTH-1:0] rd_data;
integer i;
initial
begin
wr_clk = 0;
wr_addr = 0;
wr_data[WIDTH-1:0] = 0;
wr_en = 0;
#100;
for(i=0;i<16;i=i+1)
begin
@(posedge wr_clk);
wr_addr <= i;
wr_data <= i<<4;
wr_en <= 1;
end
@(posedge wr_clk);
wr_addr <= 0;
wr_data <= 0;
wr_en <= 0;
end
integer j;
initial
begin
rd_clk = 0;
rd_addr = 0;
rd_en = 0;
#100;
@(posedge wr_clk);
for(j=0;j<16;j=j+1)
begin
@(posedge rd_clk);
rd_addr <= j;
rd_en <= 1;
end
@(posedge rd_clk);
rd_addr <= 0;
rd_en <= 0;
end
//clock
always #5 wr_clk = ~wr_clk;
always #8 rd_clk = ~rd_clk;
//DUT
dualram
#(
.WIDTH(WIDTH),
.DEPTH(DEPTH)
)
DUT
(
.wr_clk(wr_clk),
.wr_addr(wr_addr),
.wr_data(wr_data),
.wr_en(wr_en),
.rd_clk(rd_clk),
.rd_addr(rd_addr),
.rd_data(rd_data),
.rd_en(rd_en)
);
initial
begin
$dumpfile("curve.vcd");
$dumpvars(0,DUT);
end
initial #1000 $finish;
endmodule
operation result
vcs -R dualram.v tb_dualram.v
Due to the use of register output, there will be a 1-cycle delay in reading data.