【FPGA】双端口RAM的设计(同步读写)
之前的博文都是讲单端口RAM的,它们仅有一套控制输入,例如cs,we,oe,还有数据总线以及地址。
附上太多链接,我也累,自己找吧。
双端口RAM,顾名思义,有两套地址,数据总线,以及cs等。
从输入输出也可以看出来:
input clk , // Clock Input
input [ADDR_WIDTH - 1 : 0] address_0 , // address_0 Input
inout [data_0_WIDTH-1 : 0] data_0 , // data_0 bi-directional
input cs_0 , // Chip Select
input we_0 , // Write Enable/Read Enable
input oe_0 , // Output Enable
input [ADDR_WIDTH - 1 : 0] address_1 , // address_1 Input
inout [data_0_WIDTH-1 : 0] data_1 , // data_1 bi-directional
input cs_1 , // Chip Select
input we_1 , // Write Enable/Read Enable
input oe_1 // Output Enable
写部分:
//--------------Code Starts Here------------------
// Memory Write Block
// Write Operation : When we_0 = 1, cs_0 = 1
always @ (posedge clk)
begin : MEM_WRITE
if ( cs_0 && we_0 ) begin
mem[address_0] <= data_0;
end
else if (cs_1 && we_1) begin
mem[address_1] <= data_1;
end
end
读部分:
// Tri-State Buffer control
// output : When we_0 = 0, oe_0 = 1, cs_0 = 1
assign data_0 = (cs_0 && oe_0 && !we_0) ? data_0_out : 8'bz;// Memory Read Block
// Read Operation : When we_0 = 0, oe_0 = 1, cs_0 = 1
always @ (posedge clk)
begin : MEM_READ_0
if (cs_0 && !we_0 && oe_0) begin
data_0_out <= mem[address_0];
end
else begin
data_0_out <= 0;
end
end//Second Port of RAM
// Tri-State Buffer control
// output : When we_0 = 0, oe_0 = 1, cs_0 = 1
assign data_1 = (cs_1 && oe_1 && !we_1) ? data_1_out : 8'bz;
// Memory Read Block 1
// Read Operation : When we_1 = 0, oe_1 = 1, cs_1 = 1
always @ (posedge clk)
begin : MEM_READ_1
if (cs_1 && !we_1 && oe_1) begin
data_1_out <= mem[address_1];
end else begin
data_1_out <= 0;
end
end
可见,可以操作地址0以及地址1读写,因此可以实现同时读写操作。
如果对两套端口同时进行写操作,可见地址0优先,而读就不存在这种情况。(可不必考虑这句话!)
下面给出完整Verilog HDL设计代码:
-
`timescale 1ns / 1ps
-
//
-
// Create Date: 2019/05/28 20:50:48
-
// Design Name:
-
// Module Name: ram_dp_sr_sw
-
//
-
-
module ram_dp_sr_sw #(
-
parameter data_0_WIDTH = 8,
-
parameter ADDR_WIDTH = 8,
-
parameter RAM_DEPTH = 1 << ADDR_WIDTH
-
)(
-
input clk , // Clock Input
-
input [ADDR_WIDTH - 1 : 0] address_0 , // address_0 Input
-
inout [data_0_WIDTH-1 : 0] data_0 , // data_0 bi-directional
-
input cs_0 , // Chip Select
-
input we_0 , // Write Enable/Read Enable
-
input oe_0 , // Output Enable
-
input [ADDR_WIDTH - 1 : 0] address_1 , // address_1 Input
-
inout [data_0_WIDTH-1 : 0] data_1 , // data_1 bi-directional
-
input cs_1 , // Chip Select
-
input we_1 , // Write Enable/Read Enable
-
input oe_1 // Output Enable
-
);
-
-
-
-
//--------------Internal variables----------------
-
reg [data_0_WIDTH-1:0] data_0_out ;
-
reg [data_0_WIDTH-1:0] data_1_out ;
-
reg [data_0_WIDTH-1:0] mem [0:RAM_DEPTH-1];
-
-
-
//initialization
-
-
// synopsys_translate_off
-
integer i;
-
initial begin
-
for(i=0; i < RAM_DEPTH; i = i + 1) begin
-
mem[i] = 8'h00;
-
end
-
end
-
// synopsys_translate_on
-
-
-
//--------------Code Starts Here------------------
-
// Memory Write Block
-
// Write Operation : When we_0 = 1, cs_0 = 1
-
always @ (posedge clk)
-
begin : MEM_WRITE
-
if ( cs_0 && we_0 ) begin
-
mem[address_0] <= data_0;
-
end
-
else if (cs_1 && we_1) begin
-
mem[address_1] <= data_1;
-
end
-
end
-
-
-
-
// Tri-State Buffer control
-
// output : When we_0 = 0, oe_0 = 1, cs_0 = 1
-
assign data_0 = (cs_0 && oe_0 && !we_0) ? data_0_out : 8'bz;
-
-
// Memory Read Block
-
// Read Operation : When we_0 = 0, oe_0 = 1, cs_0 = 1
-
always @ (posedge clk)
-
begin : MEM_READ_0
-
if (cs_0 && !we_0 && oe_0) begin
-
data_0_out <= mem[address_0];
-
end
-
else begin
-
data_0_out <= 0;
-
end
-
end
-
-
//Second Port of RAM
-
// Tri-State Buffer control
-
// output : When we_0 = 0, oe_0 = 1, cs_0 = 1
-
assign data_1 = (cs_1 && oe_1 && !we_1) ? data_1_out : 8'bz;
-
// Memory Read Block 1
-
// Read Operation : When we_1 = 0, oe_1 = 1, cs_1 = 1
-
always @ (posedge clk)
-
begin : MEM_READ_1
-
if (cs_1 && !we_1 && oe_1) begin
-
data_1_out <= mem[address_1];
-
end else begin
-
data_1_out <= 0;
-
end
-
end
-
-
endmodule // End of Module ram_dp_sr_sw
下面对此进行测试:
过程如下:
两个端口同时对RAM初值:
端口0写,同时端口1读:
两端口同时读:
可见,读出来的数据与时钟同步。
最后给出测试文件:
-
`timescale 1ns / 1ps
-
-
module ram_dp_sr_sw_tb;
-
-
reg clk ; // Clock
-
reg [7 : 0] address_0 ; // address_0 input
-
wire [7 : 0] data_0 ; // data_0 bi-directional
-
reg cs_0 ; // Chip Select
-
reg we_0 ; // Write Enable/Read Enable
-
reg oe_0 ; // Output Enable
-
reg [7 : 0] address_1 ; // address_1 input
-
wire [7 : 0] data_1 ; // data_1 bi-directional
-
reg cs_1 ; // Chip Select
-
reg we_1 ; // Write Enable/Read Enable
-
reg oe_1 ; // Output Enable
-
-
-
initial begin
-
clk = 0;
-
forever
-
#2 clk = ~clk;
-
end
-
-
reg [7 : 0] data_in0; //写数据时候,双向总线与data_in0连接(这样做的目的是保证总线在某一时刻读和写,二者之一有效)
-
assign data_0 = (cs_0 && we_0 && !oe_0) ? data_in0 : 8'dz;
-
-
reg [7 : 0] data_in1; //写数据时候,双向总线与data_in1连接(这样做的目的是保证总线在某一时刻读和写,二者之一有效)
-
assign data_1 = (cs_1 && we_1 && !oe_1) ? data_in1 : 8'dz;
-
-
integer i = 0;
-
-
initial begin
-
oe_0 = 0;
-
oe_1 = 0;
-
we_0 = 0;
-
we_1 = 0;
-
cs_0 = 0;
-
cs_1 = 0;
-
address_0 = 0;
-
address_1 = 0;
-
data_in0 = 0;
-
data_in1 = 0;
-
//先读出初识值(两套地址一起读)
-
#4
-
cs_0 = 1;
-
cs_1 = 1;
-
oe_0 = 1;
-
oe_1 = 1;
-
-
for(i = 0; i < 256; i = i + 1) begin
-
@(negedge clk) begin
-
address_0 = i;
-
address_1 = i;
-
end
-
-
end
-
-
//地址0写,地址1读
-
@(negedge clk) begin
-
we_0 = 1;
-
we_1 = 0;
-
oe_0 = 0;
-
oe_1 = 1;
-
-
end
-
-
for(i = 0; i < 256; i = i + 1) begin
-
@(negedge clk) begin
-
address_0 = i;
-
data_in0 = data_in0 + 1;
-
address_1 = i;
-
end
-
-
end
-
-
//地址0读·,地址1读
-
@(negedge clk) begin
-
we_0 = 0;
-
we_1 = 0;
-
oe_0 = 1;
-
oe_1 = 1;
-
-
end
-
-
for(i = 0; i < 256; i = i + 1) begin
-
@(negedge clk) begin
-
address_0 = i;
-
address_1 = i;
-
end
-
-
end
-
-
-
//结束吧,片选结束
-
@(negedge clk) begin
-
cs_0 = 0;
-
cs_1 = 0;
-
end
-
-
#100 $stop;
-
-
-
end
-
-
-
ram_dp_sr_sw #(
-
.ADDR_WIDTH(8), //给参数
-
.data_0_WIDTH(8)
-
) u_ram(
-
.clk(clk),
-
.address_0(address_0),
-
.data_0(data_0),
-
.cs_0(cs_0),
-
.we_0(we_0),
-
.oe_0(oe_0),
-
.address_1(address_1),
-
.data_1(data_1),
-
.cs_1(cs_1),
-
.we_1(we_1),
-
.oe_1(oe_1)
-
);
-
-
-
-
endmodule
参考链接:http://www.asic-world.com/examples/verilog/ram_dp_sr_sw.html
文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。
原文链接:reborn.blog.csdn.net/article/details/90647784
- 点赞
- 收藏
- 关注作者
评论(0)