verilog 實現之RAM


  寫在前面的話:之前都是寫了一些關於在實踐中遇到的問題。今天在和同門討論中發現都在用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中並沒有此種沖突解決電路,設計者應該避免這種沖突。

 

 

 

 

 

 

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM