Verilog实现RAM(5-双端口同步读写SRAM)
在之前的工作中,我们对常见存储器件进行了名词扫盲,并通过调用IP核实现了简单的单端口同步读写SRAM、对单端口同步读写SRAM进行了Verilog描述、并进一步对单端口同步写,异步读SRAM进行了设计与分析;这部分工作见:
Verilog实现RAM(3-单端口同步写、异步读SRAM)
现在在之前工作的基础上,进一步实现双端口同步读写SRAM
一、原理
双端口同步读写SRAM与单端口同步读写SRAM,唯一区别就在于有两套信号(控制信号、数据输入输出、地址信号)
输入端口有:
reg clk;
reg [3:0]a1;//输入地址(RAM深度为16,对应地址位宽为4)
reg we1;// write enable,写使能时进行RAM写操作
reg oe1;// output enable,输出使能时RAM读取的结果才能输出
reg cs1;// 片选信号,选择读取哪一个RAM
// 第二套
reg [3:0]a2;//输入地址(RAM深度为16,对应地址位宽为4)
reg we2;// write enable,写使能时进行RAM写操作
reg oe2;// output enable,输出使能时RAM读取的结果才能输出
reg cs2;// 片选信号,选择读取哪一个RAM
输入输出端口有:
wire [7:0]d1;//读取RAM时数据输出/写入RAM时数据输入
wire [7:0]d2;//读取RAM时数据输出/写入RAM时数据输入
工作过程:
时钟来临时,两组端口分别根据cs/we/oe的值执行不同的操作;cs有效(为1)、we为1时,写使能,将d输入数据写入a对应地址处;cs有效(为1)、we为0时,读使能,oe有效(为1)时将a地址处的数据读出到d上;
双端口RAM同时进行读操作时不会冲突,即可以对同一地址进行读取,结果分别通过各自输出端口进行输出;但是双端口同时进行写操作时就可能出现写入冲突,即双端口对同一地址写入时就会出现问题;
为避免这一问题出现,将双端口SRAM设计为双端口同步读,非同步写;(可同时读,可同时一读一写,但是无法同时写,同时写时只能执行优先级高的端口写)
二、代码实现:
接着之前的工作,对双端口同步读写SRAM进行Verilog描述----实现一个位宽8bit,深度16bit的单端口SRAM;只需在之前单端口同步读写的基础上简单修改即可;
verilog描述如下:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer: CLL
//
// Create Date: 2020/02/24 19:10:35
// Design Name:
// Module Name: sram_dp_srsw
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sram_dp_srsw
#(parameter DW = 8,AW = 4)
(
input clk,
input [AW-1:0]a1,//address
input cs1,// chip select
input oe1,// output enable
input we1,// write enable
inout [DW-1:0]d1,// data
//
input [AW-1:0]a2,//address
input cs2,// chip select
input oe2,// output enable
input we2,// write enable
inout [DW-1:0]d2// data
);
//
parameter DP = 1 << AW;// depth
reg [DW-1:0]mem[0:DP-1];
reg [DW-1:0]reg_d1;
// port2
reg [DW-1:0]reg_d2;
//initialization
// synopsys_translate_off
integer i;
initial begin
for(i=0; i < DP; i = i + 1) begin
mem[i] = 8'h00;
end
end
// synopsys_translate_on
// read declaration
// port1
aaa@qq.com(posedge clk)
begin
if(cs1 & !we1 & oe1)
begin
reg_d1 <= mem[a1];
end
else
begin
reg_d1 <= reg_d1;
end
end
// port2
aaa@qq.com(posedge clk)
begin
if(cs2 & !we2 & oe2)
begin
reg_d2 <= mem[a2];
end
else
begin
reg_d2 <= reg_d2;
end
end
// wrirte declaration
aaa@qq.com(posedge clk)
begin
if(cs1 & we1)//port1 higher priority
begin
mem[a1] <= d1;
end
else if(cs2 & we2)
begin
mem[a2] <= d2;
end
else
begin
mem[a1] <= mem[a1];
mem[a2] <= mem[a2];
end
end
// 三态逻辑
assign d1 = (cs1 & !we1 & oe1) ? reg_d1 : {DW{1'bz}};
assign d2 = (cs2 & !we2 & oe2) ? reg_d2 : {DW{1'bz}};
endmodule
测试文件如下:
同步读,port1读地址0-15,port2读地址15-0
port1读地址15-0,port2写1-16到地址0-15
同步写地址0-15,port1写1,port2写2
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer: CLL
//
// Create Date: 2020/02/24 19:25:55
// Design Name:
// Module Name: sram_dp_srsw_tsb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sram_dp_srsw_tsb(
);
// port declaration
reg clk;
// port1
reg [3:0]a1;//address
reg cs1;
reg oe1;
reg we1;// write enable
wire [7:0]d1;//datain/out
// port2
reg [3:0]a2;//address
reg cs2;
reg oe2;
reg we2;// write enable
wire [7:0]d2;//datain/out
// reg declaration
reg [7:0]din1;
reg [7:0]din2;
//
initial
begin
clk = 1'b0;
forever #10 clk = ~clk;//period = 20
end
//
assign d1 = (cs1 & we1)?din1:8'bzzzz_zzzz;
assign d2 = (cs2 & we2)?din2:8'bzzzz_zzzz;
//
initial
begin
a1 = 4'b0000;
din1 = 8'd1;
we1 = 1'b0;
oe1 = 1'b1;
cs1 = 1'b1;
a2 = 4'b1111;
din2 = 8'd1;
we2 = 1'b0;
oe2 = 1'b1;
cs2 = 1'b1;
#20//同步读,port1读0-15,port2读15-0
repeat(15) begin
#20 a1 = a1+1'b1;
a2 = a2-1'b1;
end
#20//port1读15-0,port2写0-15
we2 = 1'b1;
repeat(15) begin
#20 a1 = a1-1'b1;
a2 = a2+1'b1;
din2 = din2+1'b1;
end
#20//同步写0-15,port1写1,port2写2
we1 = 1'b1;
we2 = 1'b1;
a1 = 4'b0000;
a2 = 4'b0000;
repeat(15) begin
#20 a1 = a1+1'b1;
din1 = 1'b1;
a2 = a2+1'b1;
din2 = 2'd2;
end
end
sram_dp_srsw inst (
.clk(clk),
.a1(a1), // input wire [3 : 0] a
.d1(d1), // input wire [7 : 0] d
.we1(we1), // input wire we
.cs1(cs1),
.oe1(oe1),
.a2(a2), // input wire [3 : 0] a
.d2(d2), // input wire [7 : 0] d
.we2(we2), // input wire we
.cs2(cs2),
.oe2(oe2)
);
endmodule
仿真结果如下:
可以看出:
同步读时,port1读地址0-15,port2读地址15-0,输出均为0;
port1读地址15-0,port2写1-16到地址0-15时:mem值从0-15逐步改变,d1输出从0直到port2写入了值的部分,证明确实可以同步读写;
同步写地址0-15,port1写1,port2写2,输出为1,证明同时写时确实port1优先级较高;