There are many types RAM. These differ in terms of the number of ports, synchronous or asynchronous modes of operation etc.
Here in this post, I have written the Verilog code for a simple Dual port RAM, with two ports 0 and 1. The writing is allowed to only one port, on the positive edge the clock. The reading is done from both the ports asynchronously, that means we don't have to wait for the clock signal to read from the memory.
I have fixed the RAM size as 16*8 bits, meaning 16 elements of 8 bits each. These specifications can be changed easily by altering few lines in the code.
Verilog code:
module dual_port_ram
( input clk, //clock
input wr_en, //write enable for port 0
input [7:0] data_in, //Input data to port 0.
input [3:0] addr_in_0, //address for port 0
input [3:0] addr_in_1, //address for port 1
input port_en_0, //enable port 0.
input port_en_1, //enable port 1.
output [7:0] data_out_0, //output data from port 0.
output [7:0] data_out_1 //output data from port 1.
);
//memory declaration.
reg [7:0] ram[0:15];
//writing to the RAM
always@(posedge clk)
begin
if(port_en_0 == 1 && wr_en == 1) //check enable signal and if write enable is ON
ram[addr_in_0] <= data_in;
end
//always reading from the ram, irrespective of clock.
assign data_out_0 = port_en_0 ? ram[addr_in_0] : 'dZ;
assign data_out_1 = port_en_1 ? ram[addr_in_1] : 'dZ;
endmodule
Testbench code:
module tb;
// Inputs
reg clk;
reg wr_en;
reg [7:0] data_in;
reg [3:0] addr_in_0;
reg [3:0] addr_in_1;
reg port_en_0;
reg port_en_1;
// Outputs
wire [7:0] data_out_0;
wire [7:0] data_out_1;
integer i;
// Instantiate the Unit Under Test (UUT)
dual_port_ram uut (
.clk(clk),
.wr_en(wr_en),
.data_in(data_in),
.addr_in_0(addr_in_0),
.addr_in_1(addr_in_1),
.port_en_0(port_en_0),
.port_en_1(port_en_1),
.data_out_0(data_out_0),
.data_out_1(data_out_1)
);
always
#5 clk = ~clk;
initial begin
// Initialize Inputs
clk = 1;
addr_in_1 = 0;
port_en_0 = 0;
port_en_1 = 0;
wr_en = 0;
data_in = 0;
addr_in_0 = 0;
#20;
//Write all the locations of RAM
port_en_0 = 1;
wr_en = 1;
for(i=1; i <= 16; i = i + 1) begin
data_in = i;
addr_in_0 = i-1;
#10;
end
wr_en = 0;
port_en_0 = 0;
//Read from port 1, all the locations of RAM.
port_en_1 = 1;
for(i=1; i <= 16; i = i + 1) begin
addr_in_1 = i-1;
#10;
end
port_en_1 = 0;
end
endmodule
The code synthesised and simulated using Xilinx ISE 14.6 tool.
Simulation waveform:
Synthesis:
The synthesis was done for a Virtex 6 device. Note that, for this particular device the inbuilt BRAM's were not used to implement this RAM because of asynchronous read operations. Making it synchronous might use the available BRAM's.
Here in this post, I have written the Verilog code for a simple Dual port RAM, with two ports 0 and 1. The writing is allowed to only one port, on the positive edge the clock. The reading is done from both the ports asynchronously, that means we don't have to wait for the clock signal to read from the memory.
I have fixed the RAM size as 16*8 bits, meaning 16 elements of 8 bits each. These specifications can be changed easily by altering few lines in the code.
Verilog code:
module dual_port_ram
( input clk, //clock
input wr_en, //write enable for port 0
input [7:0] data_in, //Input data to port 0.
input [3:0] addr_in_0, //address for port 0
input [3:0] addr_in_1, //address for port 1
input port_en_0, //enable port 0.
input port_en_1, //enable port 1.
output [7:0] data_out_0, //output data from port 0.
output [7:0] data_out_1 //output data from port 1.
);
//memory declaration.
reg [7:0] ram[0:15];
//writing to the RAM
always@(posedge clk)
begin
if(port_en_0 == 1 && wr_en == 1) //check enable signal and if write enable is ON
ram[addr_in_0] <= data_in;
end
//always reading from the ram, irrespective of clock.
assign data_out_0 = port_en_0 ? ram[addr_in_0] : 'dZ;
assign data_out_1 = port_en_1 ? ram[addr_in_1] : 'dZ;
endmodule
Testbench code:
module tb;
// Inputs
reg clk;
reg wr_en;
reg [7:0] data_in;
reg [3:0] addr_in_0;
reg [3:0] addr_in_1;
reg port_en_0;
reg port_en_1;
// Outputs
wire [7:0] data_out_0;
wire [7:0] data_out_1;
integer i;
// Instantiate the Unit Under Test (UUT)
dual_port_ram uut (
.clk(clk),
.wr_en(wr_en),
.data_in(data_in),
.addr_in_0(addr_in_0),
.addr_in_1(addr_in_1),
.port_en_0(port_en_0),
.port_en_1(port_en_1),
.data_out_0(data_out_0),
.data_out_1(data_out_1)
);
always
#5 clk = ~clk;
initial begin
// Initialize Inputs
clk = 1;
addr_in_1 = 0;
port_en_0 = 0;
port_en_1 = 0;
wr_en = 0;
data_in = 0;
addr_in_0 = 0;
#20;
//Write all the locations of RAM
port_en_0 = 1;
wr_en = 1;
for(i=1; i <= 16; i = i + 1) begin
data_in = i;
addr_in_0 = i-1;
#10;
end
wr_en = 0;
port_en_0 = 0;
//Read from port 1, all the locations of RAM.
port_en_1 = 1;
for(i=1; i <= 16; i = i + 1) begin
addr_in_1 = i-1;
#10;
end
port_en_1 = 0;
end
endmodule
The code synthesised and simulated using Xilinx ISE 14.6 tool.
Simulation waveform:
Synthesis:
The synthesis was done for a Virtex 6 device. Note that, for this particular device the inbuilt BRAM's were not used to implement this RAM because of asynchronous read operations. Making it synchronous might use the available BRAM's.
I have written a VHDL version of the same RAM in my other blog. See VHDL code for Dual port RAM.
are dual address ram and dual port ram same?
ReplyDeletethere are many types of dual port rams. dual address ram could be considered as dual port ram as far i know.
Delete