IP核——RAM


一、Quartus

1.打開Quartus ii,點擊Tools---MegaWizard Plug-In Manager

2.彈出創建頁面,選擇Creat a new custom megafunction variation,點Next

 

3.選擇IP核,可以直接搜索ram,選擇RAM:2-PORT,右上方選擇器件型號,語言選成Verilog,再填寫一下路徑名字,點Next,后面就是參數設置了。

4.設置讀寫需要幾個端口,深度計算按word還是bit。Next

5.設置深度,位寬,類型。Next

6.設置讀寫需要幾個端口,深度計算按word還是bit,一般選word。Next

7.是否為輸出添加一個寄存器(加了寄存器可以使RAM輸出的數據更穩定)?本來ram的輸出就是會慢1clk,勾選后又慢1clk,所以一般不勾選。Next

8.輸出的是新數據還是老數據,一般是要新數據,所以I don't care就行。Next

9.是否添加初始化文件mif ? Next

10.告訴你此IP核的編譯庫是什么,Next

11.輸出的文件列表,除了正常IP核,還可以選擇例化文件,注意bb.v文件用不到,一般是不勾選的。之后點finish就生成IP核了。

 

二、ISE

1.創建ISE工程,IP核需要在ISE工程里面進行調用。點擊Tools---Core Generator...

2.在新彈出來的界面中創建一個屬於IP核的工程:file---new project,並填寫文件存儲位置和文件名稱,一般為ipcore_dir文件夾,點擊保存

3.彈出的Part處填寫器件的系列、型號、封裝以及速度等級,Generation處設置語言為Verilog,點擊OK

4.點擊文件夾,找到Memories & Storage Elements---RAMs & ROMs---Block Memory Generator,(也可以直接搜索)雙擊打開,進行參數設置

5.設置模塊名稱,Next

6.類型選擇,一般選Single Dual RAM,該RAM為“a口負責寫,b口負責讀”,而對於真雙口RAM來說,a和b都是可讀可寫。其他選項根據需要勾選。Next

7.RAM的位寬、深度、使能選擇,Next

 

 8.是否在B端添加一個寄存器(加了寄存器可以使RAM輸出的數據更穩定)?本來ram的輸出就慢1clk,勾選了又慢1clk,所以一般不勾選。是否需要初始化並加載初始化ceo文件,Next

 9.是否對B口添加復位鍵,Next

 10.總結頁面,注意里面一句話:B口的讀取有1clk的延遲,點擊Generate即可生成RAM。大功告成!

 

三、單RAM讀寫操作(by威三學院FPGA教程)

本代碼針對Quartus的RAM:2-PORT

 1 //==========================================================================
 2 // --- 名稱 : ram_ctrl.v
 3 // --- 作者 : xianyu_FPGA
 4 // --- 日期 : 2019-06-23
 5 // --- 描述 : 單個ram讀寫操作
 6 //==========================================================================
 7 
 8 module ram_ctrl
 9 //---------------------<端口聲明>-------------------------------------------
10 (
11 input  wire             clk                 , //時鍾,50Mhz
12 input  wire             rst_n               , //復位,低電平有效
13 input  wire [7:0]       din                 , //寫入的數據
14 output wire [7:0]       dout                  //讀出的數據
15 );
16 //---------------------<信號定義>-------------------------------------------
17 reg                     wr_en               ; //寫使能
18 reg  [7:0]              wr_addr             ; //寫地址
19 reg  [7:0]              rd_addr             ; //讀地址
20 
21 //--------------------------------------------------------------------------
22 //--   ram例化
23 //--------------------------------------------------------------------------
24 ram_256x8 u_ram_256x8
25 (
26     .clock              (clk                ),
27     .wren               (wr_en              ),
28     .wraddress          (wr_addr            ),
29     .data               (din                ),
30     .rdaddress          (rd_addr            ),
31     .q                  (dout               )
32 );
33 
34 //--------------------------------------------------------------------------
35 //--   產生寫使能
36 //--------------------------------------------------------------------------
37 always @(posedge clk or negedge rst_n) begin
38     if(!rst_n)
39         wr_en <= 1'b1;
40     else if(wr_addr==8'd255)
41         wr_en <= 1'b0;
42     else if(rd_addr==8'd255)
43         wr_en <= 1'b1;
44 end
45 
46 //--------------------------------------------------------------------------
47 //--   產生寫地址
48 //--------------------------------------------------------------------------
49 always @(posedge clk or negedge rst_n) begin
50     if(!rst_n)
51         wr_addr <= 8'd0;
52     else if(wr_en==1)
53         wr_addr <= wr_addr+1'd1;
54     else
55         wr_addr <= 8'd0;
56 end
57 
58 //--------------------------------------------------------------------------
59 //--   產生讀地址
60 //--------------------------------------------------------------------------
61 always @(posedge clk or negedge rst_n) begin
62     if(!rst_n)
63         rd_addr <= 8'd0;
64     else if(wr_en==0)
65         rd_addr <= rd_addr+1'd1;
66     else
67         rd_addr <= 8'd0;
68 end
69 
70 
71 
72 endmodule

 

四、雙RAM乒乓操作(by威三學院FPGA教程

RAM的簡單讀寫比較簡單,平常也用不太到,比較重要的是異步雙口RAM實現乒乓操作。

本代碼針對ise的Simple Dual PORT RAM

  1 //==========================================================================
  2 // --- 名稱 : ram_pp.v
  3 // --- 作者 : xianyu_FPGA
  4 // --- 日期 : 2019-06-23
  5 // --- 描述 : 異步雙口ram乒乓操作
  6 //==========================================================================
  7 
  8 module ram_pp
  9 //---------------------<端口聲明>-------------------------------------------
 10 (
 11 input  wire             clk                 , //時鍾,50Mhz
 12 input  wire             rst_n               , //復位,低電平有效
 13 input  wire [7:0]       din                 , //輸入的數據
 14 output wire [7:0]       dout                  //輸出的數據
 15 );
 16 //---------------------<信號定義>-------------------------------------------
 17 //ram_a
 18 reg                     wr_en_a             ;
 19 reg     [9:0]           wr_addr_a           ;
 20 reg     [9:0]           rd_addr_a           ;
 21 wire    [7:0]           dout_a              ;
 22 //ram_b
 23 reg                      wr_en_b            ;
 24 reg     [9:0]            wr_addr_b          ;
 25 reg     [9:0]            rd_addr_b          ;
 26 wire    [7:0]            dout_b             ;
 27 //緩一拍
 28 reg                      wr_en_a_r0         ;
 29 
 30 //--------------------------------------------------------------------------
 31 //--   ip核例化
 32 //--------------------------------------------------------------------------
 33 //ram_a
 34 ram_1024x8 u_ram_1024x8_a
 35 (
 36   .clka                 (clk                ), // input  clka
 37   .wea                  (wr_en_a            ), // input  [0 : 0] wea
 38   .addra                (wr_addr_a          ), // input  [9 : 0] addra
 39   .dina                 (din                ), // input  [7 : 0] dina
 40   .clkb                 (clk                ), // input  clkb
 41   .addrb                (rd_addr_a          ), // input  [9 : 0] addrb
 42   .doutb                (dout_a             )  // output [7 : 0] doutb
 43 );
 44 //ram_b
 45 ram_1024x8 u_ram_1024x8_b
 46 (
 47   .clka                 (clk                ), // input  clka
 48   .wea                  (wr_en_b            ), // input  [0 : 0] wea
 49   .addra                (wr_addr_b          ), // input  [9 : 0] addra
 50   .dina                 (din                ), // input  [7 : 0] dina
 51   .clkb                 (clk                ), // input  clkb
 52   .addrb                (rd_addr_b          ), // input  [9 : 0] addrb
 53   .doutb                (dout_b             )  // output [7 : 0] doutb
 54 );
 55 
 56 //--------------------------------------------------------------------------
 57 //--   ram_a
 58 //--------------------------------------------------------------------------
 59 // 寫使能
 60 always @(posedge clk or negedge rst_n) begin
 61     if(!rst_n)
 62         wr_en_a <= 1'b1;
 63     else if(rd_addr_a=='d1023)
 64         wr_en_a <= 1'b1;
 65     else if(wr_addr_a=='d1023)
 66         wr_en_a <= 1'b0;
 67 end
 68 
 69 // 寫地址
 70 always @(posedge clk or negedge rst_n) begin
 71     if(!rst_n)
 72         wr_addr_a <= 'd0;
 73     else if(wr_addr_a=='d1023)
 74         wr_addr_a <= 'd0;
 75     else if(wr_en_a==1'b1)
 76         wr_addr_a <= wr_addr_a + 1'b1;
 77 end
 78 
 79 // 讀地址
 80 always @(posedge clk or negedge rst_n) begin
 81     if(!rst_n)
 82         rd_addr_a <= 'd0;
 83     else if(rd_addr_a=='d1023)
 84         rd_addr_a <= 'd0;
 85     else if(wr_en_a==1'b0)
 86         rd_addr_a <= rd_addr_a + 1'b1;
 87 end
 88 
 89 //--------------------------------------------------------------------------
 90 //--   ram_b
 91 //--------------------------------------------------------------------------
 92 // 寫使能
 93 always @(posedge clk or negedge rst_n) begin
 94     if(!rst_n)
 95         wr_en_b <= 1'b0;
 96     else if(wr_addr_a=='d1023)    //關鍵之處!!!
 97         wr_en_b <= 1'b1;
 98     else if(wr_addr_b=='d1023)
 99         wr_en_b <= 1'b0;
100 end
101 
102 // 寫地址
103 always @(posedge clk or negedge rst_n) begin
104     if(!rst_n)
105         wr_addr_b <= 'd0;
106     else if(wr_addr_b=='d1023)
107         wr_addr_b <= 'd0;
108     else if(wr_en_b==1'b1)
109         wr_addr_b <= wr_addr_b + 1'b1;
110 end
111 
112 // 讀地址
113 always @(posedge clk or negedge rst_n) begin
114     if(!rst_n)
115         rd_addr_b <= 'd0;
116     else if(rd_addr_b=='d1023)
117         rd_addr_b <= 'd0;
118     else if(wr_en_b==1'b0)
119         rd_addr_b <= rd_addr_b + 1'b1;
120 end
121 
122 //--------------------------------------------------------------------------
123 //--   wr_en_a緩一拍時序才對齊
124 //--------------------------------------------------------------------------
125 always @(posedge clk or negedge rst_n) begin
126     if(!rst_n)
127         wr_en_a_r0 <= 0;
128     else
129         wr_en_a_r0 <= wr_en_a;
130 end
131 
132 //--------------------------------------------------------------------------
133 //--   數據輸出
134 //--------------------------------------------------------------------------
135 assign dout = (wr_en_a_r0==0) ? dout_a : dout_b;
136 
137 
138 
139 endmodule

 

五、單口,偽雙口,真雙口的區別

1.單口:只有一組數據線和地址線,只生成一個addr,因此不能同時進行讀寫。

2.雙口:擁有兩組數據線和地址線,可以生成wr_addr和rd_addr,因此可以同時進行讀寫。

    ①偽雙口:一個端口讀,一個端口寫。

    ②真雙口:兩個端口都能讀能寫。

ps:

無論是單口、偽雙口還是真雙口,他們都只使用一塊Memory,真雙口其實是兩組地址對同一塊Memory進行讀寫,如果真雙口的兩端口同時對同一地址進行寫入數據,那實際情況是未知(仿真也不可信)。

 

六、ROM、RAM和FIFO的區別

1.ROM有地址,只能讀而不能寫。用初始化文件mif/ceo將內容存進去,讀取不會使得數據減少消失。

2.RAM有地址,可以進行尋址讀寫,數據寫進去后,讀取不會使得數據減少消失。

3.FIFO沒有地址,只能是先進先出,數據寫進去后,讀取會使得數據減少消失,讀一個少一個。

 

參考資料:

[1]威三學院FPGA教程

[2]小梅哥FPGA教程


免責聲明!

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



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