欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Verilog实现RAM(7-异步双口SRAM:原理、实现、仿真、分析)

程序员文章站 2022-04-01 16:38:55
...

在之前的工作中,我们对常见存储器件进行了名词扫盲,通过调用IP核实现了简单的单端口同步读写SRAM、通过Verilog实现了单端口同步读写SRAM、单端口同步写,异步读SRAM、单端口异步读写SRAM,双端口同步读写SRAM,以及双端口异步读写SRAM,这些工作见:

Verilog实现RAM

但是随着深入学习发现,之前实现的异步RAM更像是一个时钟无关的RAM;异步双口SRAM应该是读写时钟不同,才能叫异步,像之前写的“异步”SRAM实际为时钟无关的RAM,都没有时钟,如何称为异步?因此,重新对异步双口SRAM进行设计和验证:

目录

一、原理

二、代码实现与仿真:

三、参考文献:


一、原理

异步双口SRAM与双端口同步读写SRAM类似,唯一区别就在于两组端口时钟不同,分别在其控制信号的作用下(如:片选、使能、地址等)进行读/写操作;

输入端口有:(异步应该有两组时钟)

    reg clk1;//端口1对应时钟

    reg [3:0]a1;//输入地址(RAM深度为16,对应地址位宽为4)

    reg we1;// write enable,写使能时进行RAM写操作

    reg oe1;// output enable,输出使能时RAM读取的结果才能输出

    reg cs1;// 片选信号,选择读取哪一个RAM

//  第二套

    reg clk2;//端口2对应时钟

    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同时读写时会出现冲突,如:同时对同一地址读操作,此时两个端口能直接同时读出数据吗?存在仲裁吗?再如:同时对同一地址进行写操作,此时写地址的结果应该是啥?是报错?是仲裁?写的内容是哪个端口的内容?还是说内容杂糅在一起;这就想起来之前看过的一句话,编写一个简单的RAM很容易,但是要编写一个稳定的,考虑全面的RAM绝非易事。这也是为什么推荐使用IP核的原因,因为IP核是众多工程师努力的结晶,相对来说更稳定,考虑的更全面。但是此处为了了解RAM的工作流程,暂不考虑复杂的情况,只对RAM的简单功能进行仿真实现。

 

二、代码实现与仿真:

接着之前的工作----仍旧实现一个位宽8bit,深度16bit的双口异步SRAM;

实现代码:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: guoliang CLL
// 
// Create Date: 2020/03/04 15:51:18
// Design Name: 
// Module Name: dsram
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module dsram
#(parameter DW = 8,AW = 4)
(
    input clk1,
    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 clk2,
    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 clk1)
begin
    if(cs1 & !we1 & oe1)
        begin
            reg_d1 <= mem[a1];
        end
    else
        begin
            reg_d1 <= reg_d1;
        end
end
// port2
aaa@qq.com(posedge clk2)
begin
    if(cs2 & !we2 & oe2)
        begin
            reg_d2 <= mem[a2];
        end
    else
        begin
            reg_d2 <= reg_d2;
        end
end

// wrirte declaration
// port1
aaa@qq.com(posedge clk1)
begin
    if(cs1 & we1)//port1 higher priority
        begin
            mem[a1] <= d1;
        end
    else
        begin
            mem[a1] <= mem[a1];
        end    
end
//port2
aaa@qq.com(posedge clk2)
begin
    if(cs2 & we2)
        begin
            mem[a2] <= d2;
        end
    else
        begin
            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对应快时钟clk1,port2对应慢时钟clk2;

1、port1在clk1驱动下从地址0-15写数据1-16;port2同时在clk2驱动下从地址0-15读数据;

2、port1在clk1驱动下从地址15-0读数据;port2同时在clk2驱动下从地址15-0写数据oxff;

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: CLL
// 
// Create Date: 2020/03/04 16:42:17
// Design Name: 
// Module Name: dsram_tsb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module dsram_tsb(

    );
// port declaration
reg clk1;
reg clk2;
// 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;
// clk1
initial
begin
    clk1 = 1'b0;
    forever #10 clk1 = ~clk1;//period = 20
end
// clk2
initial
begin
    clk2 = 1'b0;
    forever #25 clk2 = ~clk2;//period = 50
end
//
assign d1 = (cs1 & we1)?din1:8'bzzzz_zzzz;
assign d2 = (cs2 & we2)?din2:8'bzzzz_zzzz;
//port1
initial
begin
///////////////////////////////
    fork// port1写,port2读
        begin
            a1 = 4'b0000;
            din1 = 8'd1;
            we1 = 1'b1;
            oe1 = 1'b0;
            cs1 = 1'b1;
            repeat(15) begin//port1写1-16于地址0-15
            #20 a1 = a1+1'b1;
            din1 = din1+1'b1;
            end
        end
        begin
            a2 = 4'b0000;
            din2 = 8'd0;
            we2 = 1'b0;
            oe2 = 1'b1;
            cs2 = 1'b1;
            repeat(15) begin//port2读地址0-15
            #50 a2 = a2+1'b1;
            end
        end
    join
///////////////////////////////////////////////////
    #50//执行完后,port1读,port2写
    fork// port1写,port2读
        begin
            we1 = 1'b0;
            oe1 = 1'b1;
            cs1 = 1'b1;
            repeat(15) begin//port1读于地址15-0
            #20 a1 = a1-1'b1;
            end
        end
        begin
            din2 = 8'b1111_1111;
            we2 = 1'b1;
            oe2 = 1'b0;
            cs2 = 1'b1;
            repeat(15) begin//port2写11111111于地址15-0
            #50 a2 = a2-1'b1;
            end
        end
    join
end
dsram inst (
  .clk1(clk1),
  .a1(a1),      // input wire [3 : 0] a
  .d1(d1),      // input wire [7 : 0] d
  .we1(we1),    // input wire we
  .cs1(cs1), 
  .oe1(oe1),
  .clk2(clk2),  
  .a2(a2),      // input wire [3 : 0] a
  .d2(d2),      // input wire [7 : 0] d
  .we2(we2),    // input wire we
  .cs2(cs2), 
  .oe2(oe2)  
);
endmodule

仿真结果如下:

1、port1在clk1驱动下从地址0-15写数据1-16;port2同时在clk2驱动下从地址0-15读数据;如下:

可以看出,读写分别对应各自的clk上升沿,port1在clk1驱动下将数据1-16写入了mem的[0-15],port2在clk2驱动下以一个较慢的速度从地址0-15读出数据1-16,与设计一致;


Verilog实现RAM(7-异步双口SRAM:原理、实现、仿真、分析)

2、port1在clk1驱动下从地址15-0读数据;port2同时在clk2驱动下从地址15-0写数据oxff;如下:

可以看出,读写分别对应各自的clk上升沿,port1在clk1驱动下快速从地址15-0读出之前写进去的数据16-1,读数据较快不受port2新写入的oxff影响,port2在clk2驱动下以一个较慢的速度向地址15-0写数据oxff,与设计一致;

Verilog实现RAM(7-异步双口SRAM:原理、实现、仿真、分析)

RTL电路如下:

Verilog实现RAM(7-异步双口SRAM:原理、实现、仿真、分析)

三、参考文献:

verilog怎么写能综合出异步的RAM

verilog中的fork...join用法