写在前面的话:之前都是写了一些关于在实践中遇到的问题。今天在和同门讨论中发现都在用Verilog实现一些IP核的功能,感觉自己有点落后了,不高兴。所以就开始着手试着实现一下,一开始有点蒙,一直用RAM但是正道自己用verilog 实现的时候,就发现你的了解的特别透彻。才能来时现。开始正文。

  RAM使我们经常用到的一个IP,在我们调用相关IP的时候就会发现RAM的种类还是挺多的。

第一步:认识RAM种类,并加以区别。

  单端口RAM:对应IP核中的Single-Port RAM,只有一组控制信号线、地址线和数据线,不能同时读写,某时刻只能在控制信号作用下作为数据输入或输出的一种;

  双端口RAM:对应IP核中的Dual-Port RAM,有两组独立的控制信号线、地址线和数据线,两组之间互不影响,允许两个独立的系统同时对其进行随机性的访问。即共享式多端口存储器,可以同时读写;

  伪双端口RAM:对应IP核中的Simple Dual-Port RAM,一个端口只读,一个端口只写;

注意双端口RAM同时对同一地址进行读写时,会出现仲裁;FIFO:先进先出数据缓冲器,也是一个端口只读,另一个端口只写。但是FIFO与伪双口RAM的不同,FIFO为先入先出,没有地址线,不能对存储单元寻址;而伪双口RAM两个端口都有地址线,可以对存储单元寻址。 

第二步:RAM与FIFO的相关联系以及应用场合   

  如FIFO实现专题所述,FIFO既可以利用寄存器实现,也可以使用RAM实现;实际上,规模较大的FIFO一般都是用RAM实现的(规模特别小的FIFO才会使用寄存器实现)。FIFO常用于数据传输缓存,避免数据丢失,如跨时钟域的数据传输就需要用到异步FIFO。RAM常用于暂存指令或中间数据,指令cache和数据cache就由RAM来实现。

第三步:实现这些RAM

  (1)单口RAM的实现:同步读,同步写

 

 1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2 // Project Name : 
 3 // Website      : https://home.cnblogs.com/lgy-gdeu/
 4 // Author         : LGY GUET Uiversity
 5 // Weixin         : li15226499835
 6 // Email          : 15277385992@163.com
 7 // File           : 
 8 // Create         : 2020
 9 // Revise         : 
10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 // Modification History:
13 // Date             By              Version                 Change Description
14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 module signle_port_synrdwr #(
19     parameter           DATA_WIDTH   =   8,
20     parameter           ADDR_WIDTH   =   4,
21     parameter             DEEPTH  = 2**ADDR_WIDTH
22     )
23 (
24     //system signals
25     input                wire                             sclk       ,
26     input               wire                            sp_sy_oe  ,
27     input               wire                            sp_sy_wr  ,
28     input               wire                            sp_sy_cs  ,
29     input               wire   [ADDR_WIDTH-1:0]            spsy_addr ,
30     inout               wire   [DATA_WIDTH-1:0]            spsy_data 
31 );
32 
33 //========================================================================\
34 // ################ Define Parameter and Internal signals ################ 
35 //========================================================================/
36 reg                [DATA_WIDTH-1:0]       block_mem  [0:DEEPTH-1]   ; //相当于分配一个存储空间
37 reg             [DATA_WIDTH-1:0]       reg_spsy_data             ; //中间寄存器
38 
39 //=============================================================================
40 //+++++++++++++++++++++++++     Main Code    +++++++++++++++++++++++++++++++
41 //=============================================================================
42 //initialalization
43 integer    i ;
44 initial begin
45     for(i = 0 ; i< DEEPTH;i= i+1 )begin
46         block_mem[i]  = 8'h0 ;
47     end
48 end
49 
50 //out data 
51 assign  spsy_data  =  (sp_sy_cs & sp_sy_oe & !sp_sy_wr)? reg_spsy_data : 'hz;
52 
53 
54 //write port
55 always @(posedge sclk )begin
56     if(sp_sy_wr & sp_sy_cs )
57         block_mem[spsy_addr]    <=    reg_spsy_data;
58     else 
59         block_mem[spsy_addr]   <=   block_mem[spsy_addr];
60 end
61 
62 //read port 
63 always @(posedge sclk )begin
64     if(sp_sy_cs & !sp_sy_wr & sp_sy_oe)
65         reg_spsy_data    <=  block_mem[spsy_addr];
66 
67 end  
68 
69 endmodule
View Code

 

  1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2 // Project Name : 
  3 // Website      : https://home.cnblogs.com/lgy-gdeu/
  4 // Author         : LGY GUET Uiversity
  5 // Weixin         : li15226499835
  6 // Email          : 15277385992@163.com
  7 // File           : 
  8 // Create         : 2020
  9 // Revise         : 
 10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
 11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 12 // Modification History:
 13 // Date             By              Version                 Change Description
 14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
 16 // *********************************************************************************
 17 `timescale      1ns/1ns
 18 
 19 module tb_single_port_synrdwr();
 20 
 21 
 22 parameter           DATA_WIDTH   =   8;
 23 parameter           ADDR_WIDTH   =   4;
 24 parameter             DEEPTH  = 2**ADDR_WIDTH;
 25 
 26 reg                              sclk        ;
 27 reg                             sp_sy_oe   ;
 28 reg                             sp_sy_wr   ;
 29 reg                             sp_sy_cs   ;
 30 reg    [ADDR_WIDTH-1:0]            spsy_addr  ;
 31 wire   [DATA_WIDTH-1:0]            spsy_data  ;
 32 
 33 
 34 //========================================================================\
 35 // ################ Define Parameter and Internal signals ################ 
 36 //========================================================================/
 37 reg    [DATA_WIDTH-1:0]         reg_spsy_data ;
 38 
 39 assign   spsy_data   =    (sp_sy_cs & sp_sy_wr & !sp_sy_oe ) ? reg_spsy_data : 'hz ;
 40 
 41 
 42 //=============================================================================
 43 //+++++++++++++++++++++++++     Main Code    +++++++++++++++++++++++++++++++
 44 //=============================================================================
 45 
 46 //first  generate  sclk 
 47 initial begin
 48     sclk   =   0;
 49     forever 
 50         #5 sclk = ~sclk ;
 51 end
 52 
 53 //second  generate tiaojian 
 54 
 55 initial begin
 56     sp_sy_cs   =  1'b0 ;
 57     sp_sy_wr   =  1'b0 ;
 58     sp_sy_oe   =  1'b0 ;
 59     spsy_addr  =  4'b000;
 60     reg_spsy_data = 8'd0;
 61     #20
 62     @(negedge  sclk)begin  //read
 63         sp_sy_oe   =  1'b1 ;
 64         sp_sy_cs   =  1'b1 ;
 65     end
 66     repeat(15)  #20 spsy_addr = spsy_addr + 1 ;
 67 
 68     #40
 69     @(negedge sclk)begin  //write 
 70         sp_sy_cs  = 1'b1 ;
 71         sp_sy_wr  = 1'b1 ;
 72     end
 73     repeat(15) #20 begin
 74         spsy_addr = spsy_addr + 1 ;
 75         reg_spsy_data = reg_spsy_data + 1;
 76     end
 77     
 78     #40
 79     @(negedge sclk )begin
 80         sp_sy_oe = 1;
 81         sp_sy_cs = 1;
 82     end
 83     repeat(15)  #20begin
 84         spsy_addr = spsy_addr + 1'b1 ;
 85     end
 86 
 87 
 88     @(negedge sclk)
 89     sp_sy_cs = 0;
 90     #40
 91     $stop ;
 92 
 93 end
 94 
 95 //lihua mon=ban 
 96     signle_port_synrdwr #(
 97             .DATA_WIDTH(DATA_WIDTH),
 98             .ADDR_WIDTH(ADDR_WIDTH),
 99             .DEEPTH(DEEPTH)
100         ) inst_signle_port_synrdwr (
101             .sclk      (sclk),
102             .sp_sy_oe  (sp_sy_oe),
103             .sp_sy_wr  (sp_sy_wr),
104             .sp_sy_cs  (sp_sy_cs),
105             .spsy_addr (spsy_addr),
106             .spsy_data (spsy_data)
107         );
108 
109 
110 
111 
112 
113 
114 endmodule 
View Code

在实现的时候其实,并不是太难,关键是要注意测试文件的写法。所谓的同步是时钟同步并不是读写同时。这一点要弄清楚,还有测试激励中的repeat 的使用方法,注意只能在激励中使用,如果使用在行为电路中的话综合不成电路。

  (2)单口RAM的实现:同步写,异步读

 

 1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2 // Project Name : 
 3 // Website      : https://home.cnblogs.com/lgy-gdeu/
 4 // Author         : LGY GUET Uiversity
 5 // Weixin         : li15226499835
 6 // Email          : 15277385992@163.com
 7 // File           : 
 8 // Create         : 2020-6-16
 9 // Revise         : 
10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 // Modification History:
13 // Date             By              Version                 Change Description
14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 module single_port_asyrdwr #(
19     parameter       ADDR_WIDTH = 4 ,
20     parameter       DATA_WIDTH = 8 ,
21     parameter       DEEPTH = ADDR_WIDTH << 1
22     ) 
23 (
24     //system signals
25     input                     wire                   asy_spram_cs        , 
26     input                     wire                   asy_spram_wr        ,
27     input                    wire                   asy_spram_oe        ,
28     input                    wire [ADDR_WIDTH-1:0]  asy_spram_addr        ,
29     inout                    wire [DATA_WIDTH-1:0]    asy_spram_data    
30     
31 
32 );
33 
34 //========================================================================\
35 // ################ Define Parameter and Internal signals ################ 
36 //========================================================================/
37 reg    [DATA_WIDTH-1:0]     block_mem [0:DEEPTH-1] ;  //相当于是给一个存储空间
38 reg    [DATA_WIDTH-1:0]     reg_asy_spram_data     ;  //数据的中间变量
39 
40 //=============================================================================
41 //+++++++++++++++++++++++++     Main Code    +++++++++++++++++++++++++++++++
42 //=============================================================================
43 //initiallization
44 integer  i ;
45 initial begin
46     for (i = 0; i <= DEEPTH-1; i = i + 1)
47     begin
48         block_mem[i] = 8'h00;
49     end
50     
51 end
52 
53 //wr_port
54 always @(*) begin
55     if(asy_spram_wr & asy_spram_cs)begin
56         block_mem[asy_spram_addr]  = asy_spram_data;
57     end
58     else begin
59         block_mem[asy_spram_addr]  = block_mem[asy_spram_addr];
60     end
61 end
62 
63 //rd_port
64 
65 always @( * )begin
66     if(asy_spram_cs & !asy_spram_wr & asy_spram_oe)begin
67         reg_asy_spram_data  =  block_mem[reg_asy_spram_data];
68     end
69 end
70 
71 //out data
72 assign asy_spram_data = (asy_spram_cs & !asy_spram_wr & asy_spram_oe)?reg_asy_spram_data:{DATA_WIDTH{1'bz}};
73 
74     
75 endmodule
View Code

 

 1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2 // Project Name : 
 3 // Website      : https://home.cnblogs.com/lgy-gdeu/
 4 // Author         : LGY GUET Uiversity
 5 // Weixin         : li15226499835
 6 // Email          : 15277385992@163.com
 7 // File           : 
 8 // Create         : 2020
 9 // Revise         : 
10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 // Modification History:
13 // Date             By              Version                 Change Description
14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 module   tb_single_port_asyrdwr();
19 
20 
21 //========================================================================\
22 // ################ Define Parameter and Internal signals ################ 
23 //========================================================================/
24 
25 parameter       ADDR_WIDTH = 4     ;
26 parameter       DATA_WIDTH = 8     ;
27 parameter       DEEPTH = ADDR_WIDTH << 1 ;
28 
29 reg                       asy_spram_cs    ;
30 reg                       asy_spram_wr    ;
31 reg                       asy_spram_oe    ;
32 reg  [ADDR_WIDTH-1:0]     asy_spram_addr    ;
33 wire [DATA_WIDTH-1:0]    asy_spram_data  ;
34 
35 reg  [DATA_WIDTH-1:0]  reg_asy_spram_data;
36 reg                      sclk            ;
37 
38 //=============================================================================
39 //+++++++++++++++++++++++++     Main Code    +++++++++++++++++++++++++++++++
40 //=============================================================================
41 
42 initial begin
43     sclk = 0;
44     forever #10 begin
45         sclk = ~sclk ;
46     end
47 end
48 
49 assign asy_spram_data = (asy_spram_cs & asy_spram_wr )?reg_asy_spram_data:8'bzzzz_zzzz;
50 
51 
52 initial begin
53     asy_spram_cs = 1'b1 ;
54     asy_spram_oe = 1'b1 ;
55     asy_spram_wr = 1'b0 ;
56     asy_spram_addr = 4'b0000;
57     reg_asy_spram_data = 8'd1;
58     #20//read
59     repeat(15) #20 begin
60         asy_spram_addr = asy_spram_addr + 1;
61     end
62     #20//write
63     asy_spram_wr = 1'b1 ;    
64     repeat(15)  begin
65         #20
66         asy_spram_addr = asy_spram_addr+ 1;
67         reg_asy_spram_data = reg_asy_spram_data + 1 ;
68     end
69     #20//
70     asy_spram_wr = 1'b0 ;
71     repeat(15)  begin
72         #20
73         asy_spram_addr = asy_spram_addr + 1;
74     end
75 
76     
77 end
78 
79 
80 
81     single_port_asyrdwr #(
82             .ADDR_WIDTH(ADDR_WIDTH),
83             .DATA_WIDTH(DATA_WIDTH),
84             .DEEPTH(DEEPTH)
85         ) inst_single_port_asyrdwr (
86             .asy_spram_cs   (asy_spram_cs),
87             .asy_spram_wr   (asy_spram_wr),
88             .asy_spram_oe   (asy_spram_oe),
89             .asy_spram_addr (asy_spram_addr),
90             .asy_spram_data (asy_spram_data)
91         );
92 
93 
94 endmodule
View Code

 

    (3)双口RAM的实现,同步读,同步写

  1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2 // Project Name : 
  3 // Website      : https://home.cnblogs.com/lgy-gdeu/
  4 // Author         : LGY GUET Uiversity
  5 // Weixin         : li15226499835
  6 // Email          : 15277385992@163.com
  7 // File           : 
  8 // Create         : 2020-06-16
  9 // Revise         : 
 10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
 11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 12 // Modification History:
 13 // Date             By              Version                 Change Description
 14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
 16 // *********************************************************************************
 17 `timescale      1ns/1ns
 18 module double_port_synrdwr_ram #(
 19     parameter            ADDR_WIDTH     =     4,
 20     parameter             DATA_WIDTH     =     8,
 21     parameter            DEEPTH = 2**ADDR_WIDTH
 22     )
 23 (
 24     //system signals
 25     input                    wire                    sclk             , 
 26 
 27     input                    wire                   port1_wr            ,
 28     input                   wire                    port1_oe         ,
 29     input                     wire                    port1_cs         ,
 30     input                     wire  [ADDR_WIDTH-1:0] port1_addr       ,
 31     inout                   wire  [DATA_WIDTH-1:0] port1_data       ,
 32 
 33     input                     wire                      port2_wr           ,
 34     input                      wire                     port2_oe          ,
 35     input                   wire                   port2_cs         ,
 36     input                     wire  [ADDR_WIDTH-1:0] port2_addr        ,
 37     inout                     wire  [DATA_WIDTH-1:0] port2_data        
 38         
 39 );
 40 //========================================================================\
 41 // ################ Define Parameter and Internal signals ################ 
 42 //========================================================================/
 43 reg       [DATA_WIDTH-1:0]  block_mem  [0:DEEPTH-1]        ;
 44 reg       [DATA_WIDTH-1:0]    reg_port1                   ;
 45 reg       [DATA_WIDTH-1:0]  reg_port2                    ;
 46 
 47 //=============================================================================
 48 //+++++++++++++++++++++++++     Main Code    +++++++++++++++++++++++++++++++
 49 //=============================================================================
 50 //initiallization
 51 //block_mem
 52 integer i;
 53 initial begin
 54      
 55     for (i = 0; i <=DEEPTH-1 ; i = i + 1)
 56         begin
 57             block_mem[i] = 8'h00;
 58         end
 59 end
 60 
 61 //write path
 62 //port1 write 
 63 always @(posedge sclk)begin
 64     if(port1_cs & port1_wr)begin
 65         block_mem[port1_addr] <= port1_data ;
 66     end
 67 //    else begin
 68 //        block_mem[port1_addr] <= block_mem[port1_addr];
 69 //    end
 70 end
 71 //port2 write
 72 always @(posedge sclk)begin
 73     if(port2_wr & port2_cs)begin
 74         block_mem[port2_addr] <= port2_data ;
 75     end
 76 //    else begin
 77 //        block_mem[port2_addr] <= block_mem[port2_addr];
 78 //    end
 79 end  
 80 
 81 
 82 //read path
 83 //port1_read
 84 always @(posedge sclk )begin
 85     if(port1_cs & port1_oe & !port1_wr)begin
 86         reg_port1  <= block_mem[port1_addr];
 87     end
 88 //    else begin
 89 //        reg_port1  <= reg_port1 ;
 90 //    end
 91 end
 92 
 93 //port2_read
 94 always @(posedge sclk)begin
 95     if(port2_cs & port2_oe & !port2_wr)begin
 96         reg_port2  <= block_mem[port2_addr];
 97     end
 98 //    else begin
 99 //        reg_port2 <= reg_port2 ;
100 //    end
101         
102 end
103 
104 //out 
105 assign    port1_data    =   (port1_cs & port1_oe & !port1_wr)? reg_port1:{DATA_WIDTH{1'bz}};
106 assign    port2_data    =   (port2_cs & port2_oe & !port2_wr)? reg_port2:{DATA_WIDTH{1'bz}};
107 endmodule
View Code
  1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2 // Project Name : 
  3 // Website      : https://home.cnblogs.com/lgy-gdeu/
  4 // Author         : LGY GUET Uiversity
  5 // Weixin         : li15226499835
  6 // Email          : 15277385992@163.com
  7 // File           : 
  8 // Create         : 2020-06-16
  9 // Revise         : 
 10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
 11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 12 // Modification History:
 13 // Date             By              Version                 Change Description
 14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
 16 // *********************************************************************************
 17 `timescale      1ns/1ns
 18 module tb_double_port_synrdwr_ram();
 19 
 20 parameter            ADDR_WIDTH     =     4 ;
 21 parameter             DATA_WIDTH     =     8 ;
 22 parameter            DEEPTH = ADDR_WIDTH<<1 ;
 23 
 24 reg                    sclk             ; 
 25 reg                    port1_wr              ;
 26 reg                    port1_oe         ;
 27 reg                    port1_cs         ;
 28 reg   [ADDR_WIDTH-1:0] port1_addr       ;
 29 wire  [DATA_WIDTH-1:0] port1_data       ;
 30 reg                      port2_wr             ;
 31 reg                     port2_oe            ;
 32 reg                    port2_cs         ;
 33 reg   [ADDR_WIDTH-1:0] port2_addr          ;
 34 wire  [DATA_WIDTH-1:0] port2_data          ;
 35 
 36 //========================================================================\
 37 // ################ Define Parameter and Internal signals ################ 
 38 //========================================================================/
 39 
 40 reg   [DATA_WIDTH-1:0] reg_port1;
 41 reg   [DATA_WIDTH-1:0] reg_port2;
 42 
 43 assign    port1_data    =   (port1_cs & !port1_oe & port1_wr)? reg_port1:{DATA_WIDTH{1'bz}};
 44 assign    port2_data    =   (port2_cs & !port2_oe & port2_wr)? reg_port2:{DATA_WIDTH{1'bz}};  
 45 
 46 
 47 //generate clock
 48 initial  begin
 49     sclk  =   0;
 50     forever begin
 51         #10 sclk = ~sclk ;
 52     end
 53 end
 54 
 55 //start read&write
 56 initial begin
 57 #100
 58     port1_wr = 0 ;
 59     port1_oe = 0 ;
 60     port1_cs = 0 ;
 61     port1_addr = 4'b0000;
 62     reg_port1 = 8'd0;
 63     port2_oe = 0;
 64     port2_cs = 0;
 65     port2_wr = 0;
 66     port2_addr = 4'b1111;
 67     reg_port2 = 8'd0;
 68     //同步读,port1读0-15,port2 读15-0
 69     @(posedge sclk)begin
 70         port1_wr = 0 ;
 71         port1_oe = 1 ;
 72         port1_cs = 1 ;
 73         port2_oe = 1;
 74         port2_cs = 1;
 75         port2_wr = 0;
 76     end
 77     repeat(15) begin
 78         #20
 79         port1_addr = port1_addr + 1;
 80         port2_addr = port2_addr - 1;
 81     end 
 82 
 83     //设置port1读15-0,port2写0-15
 84     @(posedge sclk )begin
 85         port1_wr = 0 ;
 86         port1_oe = 1 ;
 87         port1_cs = 1 ;
 88         port2_oe = 0;
 89         port2_cs = 1;
 90         port2_wr = 1;
 91     end
 92     repeat(15)begin
 93         #20 
 94         port1_addr = port1_addr - 1;
 95         port2_addr = port2_addr + 1; 
 96         reg_port2  = reg_port2 + 1;
 97     end
 98     //设置同步写0-15
 99     @(posedge sclk) begin
100         port1_wr = 1 ;
101         port1_oe = 0 ;
102         port1_cs = 1 ;
103         port2_oe = 0;
104         port2_cs = 1;
105         port2_wr = 1;
106            port2_addr  = 4'b0000;
107            port1_addr  = 4'b0000;
108            reg_port2 =  0;
109            reg_port1 = 0;
110     end
111     repeat(15) begin
112         #20
113         port1_addr = port1_addr + 1;
114         port2_addr = port2_addr + 1;
115         reg_port1  = reg_port1+1;
116         reg_port2  = reg_port2+1;
117     end
118 end
119 
120 
121 //inst
122 double_port_synrdwr_ram #(
123         .ADDR_WIDTH(ADDR_WIDTH),
124         .DATA_WIDTH(DATA_WIDTH),
125         .DEEPTH(DEEPTH)
126     ) inst_double_port_synrdwr_ram (
127         .sclk       (sclk),
128         .port1_wr   (port1_wr),
129         .port1_oe   (port1_oe),
130         .port1_cs   (port1_cs),
131         .port1_addr (port1_addr),
132         .port1_data (port1_data),
133         .port2_wr   (port2_wr),
134         .port2_oe   (port2_oe),
135         .port2_cs   (port2_cs),
136         .port2_addr (port2_addr),
137         .port2_data (port2_data)
138     );
139 
140 
141 
142 
143 
144 endmodule
View Code

 

    (4)双口RAM的实现,异步读,同步写

 1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2 // Project Name : 
 3 // Website      : https://home.cnblogs.com/lgy-gdeu/
 4 // Author         : LGY GUET Uiversity
 5 // Weixin         : li15226499835
 6 // Email          : 15277385992@163.com
 7 // File           : 
 8 // Create         : 2020
 9 // Revise         : 
10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 // Modification History:
13 // Date             By              Version                 Change Description
14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
16 // *********************************************************************************
17 `timescale      1ns/1ns
18 module double_port_asyrdwr_ram #(
19     parameter     ADDR_WIDTH   =   4 ,
20     parameter     DATA_WIDTH   =   8 ,
21     parameter     DEEPTH   =  1<<ADDR_WIDTH 
22     )
23 (
24     //system signals
25     input                    wire                    sclk1            , 
26     input                    wire                    port1_wr        ,
27     input                   wire                    port1_cs        ,
28     input                    wire                    port1_oe        ,
29     input                     wire [ADDR_WIDTH-1:0]    port1_addr      ,
30     inout                     wire [DATA_WIDTH-1:0]    port1_data        ,
31 
32     input                    wire                    sclk2            ,
33     input                     wire                    port2_wr        ,
34     input                    wire                    port2_cs        ,
35     input                    wire                    port2_oe        ,
36     input                    wire [ADDR_WIDTH-1:0]    port2_addr        ,
37     inout                    wire [DATA_WIDTH-1:0]    port2_data
38     
39 
40 );
41 
42 //========================================================================\
43 // ################ Define Parameter and Internal signals ################ 
44 //========================================================================/
45 reg            [DATA_WIDTH-1:0]   block_mem   [0:DEEPTH-1] ;
46 reg            [DATA_WIDTH-1:0]   reg_port1                ;
47 reg         [DATA_WIDTH-1:0]   reg_port2                ;
48 
49 //=============================================================================
50 //+++++++++++++++++++++++++     Main Code    +++++++++++++++++++++++++++++++
51 //=============================================================================
52 //initiallization
53 integer  i ;
54 initial begin
55 for (i = 0; i <= DEEPTH-1; i = i + 1)
56     begin
57         block_mem[i]  = 8'h00;
58     end
59 end 
60 
61 //write path
62 always @(posedge sclk1)begin
63     if(port1_cs & port1_wr)begin
64         block_mem[port2_addr] <= port2_data;
65     end
66 end
67 
68 always @(posedge sclk2)begin
69     if(port2_cs & port2_wr)begin
70         block_mem[port2_addr]   <= port2_data;
71     end
72 end
73 
74 //read path
75 always @(posedge sclk1)begin
76     if(port1_oe & port2_cs & !port1_wr)begin
77         reg_port1  <= block_mem[port1_addr];
78     end
79 end
80 
81 always @(posedge sclk2)begin
82     if(port2_cs & port2_oe & !port2_wr)begin
83         reg_port2    <=  block_mem[port2_addr];
84     end
85 end
86 
87 //out data 
88 assign    port1_data   =    (port1_cs & port1_oe & !port1_wr)?reg_port1:{DATA_WIDTH{1'bz}};
89 assign    port2_data   =    (port2_cs & port2_oe & !port2_wr)?reg_port2:{DATA_WIDTH{1'bz}};
90     
91 endmodule
View Code
  1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2 // Project Name : 
  3 // Website      : https://home.cnblogs.com/lgy-gdeu/
  4 // Author         : LGY GUET Uiversity
  5 // Weixin         : li15226499835
  6 // Email          : 15277385992@163.com
  7 // File           : 
  8 // Create         : 2020
  9 // Revise         : 
 10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
 11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 12 // Modification History:
 13 // Date             By              Version                 Change Description
 14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
 16 // *********************************************************************************
 17 `timescale      1ns/1ns
 18 module   tb_double_port_asyrdwr_ram();
 19 
 20 parameter     ADDR_WIDTH   =   4 ;
 21 parameter     DATA_WIDTH   =   8 ;
 22 parameter     DEEPTH   =  1<<ADDR_WIDTH;
 23 
 24 reg                     sclk1            ;
 25 reg                     port1_wr        ;
 26 reg                     port1_cs        ;
 27 reg                     port1_oe        ;
 28 reg  [ADDR_WIDTH-1:0]    port1_addr      ;
 29 wire [DATA_WIDTH-1:0]    port1_data        ;
 30 reg                     sclk2            ;
 31 reg                     port2_wr        ;
 32 reg                     port2_cs        ;
 33 reg                     port2_oe        ;
 34 reg  [ADDR_WIDTH-1:0]    port2_addr        ;
 35 wire [DATA_WIDTH-1:0]    port2_data        ;
 36 //========================================================================\
 37 // ################ Define Parameter and Internal signals ################ 
 38 //========================================================================/
 39   
 40  reg      [DATA_WIDTH-1:0]          reg_port1    ;
 41  reg      [DATA_WIDTH-1:0]            reg_port2    ;
 42 
 43 assign   port1_data  =  (port1_cs & port1_wr)? reg_port1 : {DATA_WIDTH{1'bz}};
 44 assign   port2_data  =  (port2_cs & port2_wr)? reg_port2 : {DATA_WIDTH{1'bz}};
 45 
 46 
 47 initial begin
 48     sclk1 = 0;
 49     forever #10 sclk1 = ~sclk1 ;
 50 end
 51 
 52 
 53 initial begin
 54     sclk2 = 0;
 55     forever #25 sclk2 = ~sclk2 ;
 56 end
 57 
 58 initial begin
 59     fork begin
 60             
 61             port1_addr = 4'b0000;
 62             reg_port1 = 8'd0;
 63             port1_wr = 1'b1;
 64             port1_oe = 1'b0;
 65             port1_cs = 1'b1;
 66             repeat(15) begin//port1写1-15于地址0-15
 67             #20 port1_addr = port1_addr+1'b1;
 68                    reg_port1  = reg_port1+1'b1;
 69                end 
 70         end
 71         begin
 72             
 73             port2_addr = 4'b0000;
 74             reg_port2 = 8'd0;
 75             port2_wr = 1'b0;
 76             port2_oe = 1'b1;
 77             port2_cs = 1'b1;
 78             repeat(15) begin//port2读地址0-15
 79             #40 port2_addr = port2_addr+1'b1;
 80             end
 81         end
 82     join 
 83 
 84     #40
 85     fork begin
 86             port1_wr = 1'b0;
 87             port1_oe = 1'b1;
 88             port1_cs = 1'b1;
 89             repeat(15) begin//port1读于地址15-0
 90             #20 port1_addr = port1_addr-1'b1;
 91             end
 92         end
 93         begin
 94             reg_port2 = 8'b1111_1111;
 95             port2_wr = 1'b1;
 96             port2_oe = 1'b0;
 97             port2_cs = 1'b1;
 98             repeat(15) begin//port2写11111111于地址15-0
 99             #40 port2_addr = port2_addr-1'b1;
100             end
101         end
102     join
103 end
104 
105 
106     double_port_asyrdwr_ram #(
107             .ADDR_WIDTH(ADDR_WIDTH),
108             .DATA_WIDTH(DATA_WIDTH),
109             .DEEPTH(DEEPTH)
110         ) inst_double_port_asyrdwr_ram (
111             .sclk1      (sclk1),
112             .port1_wr   (port1_wr),
113             .port1_cs   (port1_cs),
114             .port1_oe   (port1_oe),
115             .port1_addr (port1_addr),
116             .port1_data (port1_data),
117             .sclk2      (sclk2),
118             .port2_wr   (port2_wr),
119             .port2_cs   (port2_cs),
120             .port2_oe   (port2_oe),
121             .port2_addr (port2_addr),
122             .port2_data (port2_data)
123         );
124 
125 
126 endmodule 
View Code

 

总结:这里没有对代码和时序图的具体分析。关于实现的过程主要要有一个大概的输入输出框图。

单口的RAM:记住下面的框图,和接口的走向,剩下的了解逻辑就可以写出来了。注意:DATA的数据类型。

 

 

 伪双口RAM:

 

 

双口RAM:

 

实际应用注意:

  (1)无论是简单双口RAM还是真双口RAM,在没有读操作的情况下,应将读使能rden信号拉成低电平,节省功耗。

  (2)在两种情况下,都应当避免read-during-write,虽然可在软件中进行设置,但是,作为设计者,应当尽量避免此种情况。

  (3)对于真双口RAM,还应当避免两个读端口或者两个写端口同时操作同一个地址,RAM中并没有此种冲突解决电路,设计者应该避免这种冲突。