在FPGA 邏輯設(shè)計(jì)中經(jīng)常用到的數(shù)據(jù)存儲(chǔ)方式有ROM、RAM和FIFO,根據(jù)不同的應(yīng)用場(chǎng)景選擇不同的存儲(chǔ)方式。Xilinx 平臺(tái)三種存儲(chǔ)方式在使用過程中的區(qū)別如下:
1、ROM按照地址讀寫,使用初始化.ceo文件將地址和對(duì)應(yīng)的數(shù)據(jù)內(nèi)容存入,讀數(shù)據(jù)的時(shí)候給地址,輸出地址中存儲(chǔ)的數(shù)據(jù)。支持反復(fù)讀取,讀取過程中不會(huì)使數(shù)據(jù)減少;
2、RAM按照地址讀寫數(shù)據(jù),按照指定的地址寫入數(shù)據(jù),讀數(shù)據(jù)的時(shí)候給地址,輸出地址中存儲(chǔ)的數(shù)據(jù),支持反復(fù)讀取,讀取過程中不會(huì)使數(shù)據(jù)減少;
3、FIFO沒有地址參與,先寫入的數(shù)據(jù)被先讀出,就是先進(jìn)先出,讀取數(shù)據(jù)的過程中讀一個(gè)少一個(gè),就像雞蛋放在籃子中取出一個(gè)少一個(gè)。
01 RAM簡(jiǎn)介
RAM,random access memory,是隨機(jī)存取存儲(chǔ)器的縮寫,掉電后數(shù)據(jù)丟失。 這里使用簡(jiǎn)單雙端口RAM舉例,即端口A寫數(shù)據(jù),端口B讀數(shù)據(jù)。

端口A寫入數(shù)據(jù)的過程中WEA==1'b1 && ENA==1'b1,條件同時(shí)滿足的時(shí)候,DINA的數(shù)據(jù)被寫入到指定的內(nèi)存地址中。

端口B讀出數(shù)據(jù)的時(shí)候,讀使能和讀地址同時(shí)有效,讀出數(shù)據(jù)需要延遲一個(gè)時(shí)鐘周期。

1.1、vivado中添加RAM-IP核
step1:在ip-catalog中搜索ram,找到 block memory generator

step2:在ip核配置

step3:端口A設(shè)置(寫入數(shù)據(jù)位寬和深度)

step4:端口B設(shè)置(注意細(xì)節(jié))

step5:其他設(shè)置

02 RAM使用案例
2.1、簡(jiǎn)單雙端口RAM使用案例
簡(jiǎn)單雙端口RAM使用的案例有1、數(shù)據(jù)緩沖-實(shí)現(xiàn)位寬轉(zhuǎn)化;2、對(duì)應(yīng)連續(xù)待處理的數(shù)據(jù)流使用乒乓RAM,實(shí)現(xiàn)數(shù)據(jù)流不間斷的輸入到處理模塊。本文主要對(duì)乒乓RAM做一個(gè)詳細(xì)介紹和測(cè)試應(yīng)用。

2.2、乒乓RAM讀寫時(shí)序設(shè)計(jì)
乒乓RAM讀寫時(shí)序設(shè)計(jì)波形圖中讀寫時(shí)鐘使用了相同的時(shí)鐘信號(hào),當(dāng)讀寫數(shù)據(jù)的時(shí)鐘不同時(shí),就是異步乒乓RAM。首先對(duì)RAMA寫入數(shù)據(jù),按地址寫入數(shù)據(jù)結(jié)束以后讀取RAMA的數(shù)據(jù)給數(shù)據(jù)處理模塊,同時(shí)將外部輸入的數(shù)據(jù)緩存到RAMB中,保證同一時(shí)間內(nèi)既有數(shù)據(jù)緩存又有數(shù)據(jù)輸出,實(shí)現(xiàn)的效果就是外部不間斷地輸入數(shù)據(jù),經(jīng)過RAM處理以后不間斷地輸出到下一級(jí)處理模塊。

圖2-2-1、乒乓RAM讀寫時(shí)序設(shè)計(jì)
2.3、代碼實(shí)現(xiàn)
根據(jù)時(shí)序設(shè)計(jì)波形圖2-2-1,編寫邏輯代碼,
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/01/08 19:19:47
// Design Name: 
// Module Name: pingpang_ram
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module pingpang_ram(
input      wire                sclk,
input      wire                async_rst_n,   
input      wire                wr_valid, 
input      wire [7:0]          data_in,
output     wire [7:0]          data_out
    );
//  信號(hào)定義 
localparam                  ADDR_MAX                  =              1024       -        1;  
// rama   
reg                        wr_en_a;
reg  [9  :  0]             wr_addr_a;           // 寫地址  
reg                        rd_en_a;
reg  [9  :  0]             rd_addr_a;           // 讀地址  
wire [7  :  0]             rd_data_a;      
reg                        wr_en_a_dly;
// ramb  
reg                        wr_en_b;
reg  [9  :  0]             wr_addr_b;           // 寫地址  
reg                        rd_en_b;
reg  [9  :  0]             rd_addr_b;           // 讀地址  
wire [7  :  0]             rd_data_b;     
//  
wire   sync_rst_n; 
reg    sync_rst_n1; 
reg    sync_rst_n2; 
assign      sync_rst_n           =              sync_rst_n2 ;
assign    data_out               =              (wr_en_a_dly   ==  1'b0 )  ?     rd_data_a    :    rd_data_b;         // 符合條件后---立即響應(yīng) 
// 異步復(fù)位,同步釋放,異步復(fù)位信號(hào),同步處理
always@(posedge sclk or negedge async_rst_n)   begin 
    if(!async_rst_n)   begin 
    sync_rst_n1    <=     1'b0;                             //  復(fù)位開始的時(shí)候 wr_en 就開始有效    
    sync_rst_n2    <=     1'b0;     
    end  
    else  begin 
    sync_rst_n1    <=       1'b1;   
    sync_rst_n2    <=       sync_rst_n1;  
     end 
end  
//  wr_en   
always@(posedge sclk or negedge sync_rst_n)   begin 
    if(!sync_rst_n)   begin 
    wr_en_a   <=     1'b0;                                
    end  
    else if (wr_valid  ==   1'b1   )  begin 
    wr_en_a     <=       1'b1;     
    end    
    else if(wr_addr_a   ==   ADDR_MAX)   begin  
    wr_en_a     <=      1'b0;
    end 
    else if(rd_addr_a   ==   ADDR_MAX)   begin  
    wr_en_a     <=      1'b1;
    end   
end 
//   寫地址信號(hào)  
always@(posedge sclk or negedge sync_rst_n)   begin 
     if(!sync_rst_n)   begin 
     wr_addr_a     <=      16'd0;                          
     end  
     else if(wr_addr_a   ==   ADDR_MAX) begin
     wr_addr_a     <=       16'd0;       
     end       
     else if(wr_en_a   ==  1'b1 )  begin                    
     wr_addr_a     <=    wr_addr_a      +     1'b1;
     end 
end 
//   讀使能信號(hào)  
always@(posedge sclk or negedge sync_rst_n)   begin 
     if(!sync_rst_n)   begin 
      rd_en_a          <=            1'b0;                          
     end  
     else if(wr_addr_a   ==   ADDR_MAX) begin                    
      rd_en_a          <=            1'b1;    
     end 
      else if (rd_addr_a    ==     ADDR_MAX) begin                  
      rd_en_a          <=            1'b0;     
     end 
end 
always@(posedge sclk or negedge sync_rst_n)   begin 
      wr_en_a_dly          <=            wr_en_a;                          
     end      
//   讀地址信號(hào)  
always@(posedge sclk  or  negedge sync_rst_n)   begin 
    if(!sync_rst_n)   begin 
      rd_addr_a          <=     10'd0;                             
    end  
    else if(rd_addr_a   ==  ADDR_MAX) begin
      rd_addr_a          <=         10'd0;  
    end      
    else if(rd_en_a    ==     1'b1)   begin                         
      rd_addr_a         <=     rd_addr_a          +        1'b1;
    end 
end 
// ---------RAMB   
always@(posedge sclk or negedge sync_rst_n)   begin 
    if(!sync_rst_n)   begin 
    wr_en_b   <=     1'b0;                                 
    end  
    else if(wr_addr_b   ==   ADDR_MAX)   begin  
    wr_en_b     <=      1'b0;
    end 
    else if(wr_addr_a   ==   ADDR_MAX)   begin                 //  寫完RAMA -開始寫RAMB    
    wr_en_b    <=      1'b1;
    end   
end 
//   寫地址信號(hào)  
always@(posedge sclk or negedge sync_rst_n)   begin 
     if(!sync_rst_n)   begin 
     wr_addr_b     <=      16'd0;                            
     end  
     else if(wr_addr_b   ==   ADDR_MAX) begin
     wr_addr_b     <=       16'd0;       
     end       
     else if(wr_en_b   ==  1'b1 )  begin                    
     wr_addr_b     <=    wr_addr_b      +     1'b1;
     end 
end 
//   讀使能信號(hào)  
always@(posedge sclk or negedge sync_rst_n)   begin 
     if(!sync_rst_n)   begin 
      rd_en_b          <=            1'b0;                          
     end  
     else if(wr_addr_b   ==   ADDR_MAX) begin                    
      rd_en_b          <=            1'b1;    
     end 
      else if (rd_addr_b    ==     ADDR_MAX) begin                  
      rd_en_b          <=            1'b0;     
     end 
end    
//   讀地址信號(hào)  
always@(posedge sclk  or  negedge sync_rst_n)   begin 
    if(!sync_rst_n)   begin 
      rd_addr_b          <=     10'd0;                              
    end  
    else if(rd_addr_b   ==  ADDR_MAX) begin
      rd_addr_b          <=         10'd0;  
    end      
    else if(rd_en_b    ==     1'b1)   begin                          
      rd_addr_b         <=     rd_addr_b          +         1'b1;
    end 
end 
//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
ram_8x1024       a_instance_name (
  .clka(sclk),            // input wire clka
  .ena(wr_en_a),       // input wire ena
  .wea(wr_en_a),       // input wire [0 : 0] wea
  .addra(wr_addr_a),   // input wire [9 : 0] addra
  .dina(data_in),         // input wire [7 : 0] dina
  .clkb(sclk),            // input wire clkb
  .enb(rd_en_a),       // input wire enb
  .addrb(rd_addr_a),   // input wire [9 : 0] addrb
  .doutb(rd_data_a)       // output wire [7 : 0] doutb
);
//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
ram_8x1024       b_instance_name (
  .clka(sclk),               // input wire clka
  .ena(wr_en_b),        // input wire ena
  .wea(wr_en_b),        // input wire [0 : 0] wea
  .addra(wr_addr_b),    // input wire [9 : 0] addra
  .dina(data_in),            // input wire [7 : 0] dina
  .clkb(sclk),               // input wire clkb
  .enb(rd_en_b),        // input wire enb
  .addrb(rd_addr_b),    // input wire [9 : 0] addrb
  .doutb(rd_data_b)          // output wire [7 : 0] doutb
);
endmodule
仿真激勵(lì)文件
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/01/08 20:24:11
// Design Name: 
// Module Name: tb_pingpang_ram
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module tb_pingpang_ram();
reg                       sclk;
reg                       async_rst_n;
reg                       wr_valid;
reg [7:0]                 data_in;
wire [7:0]                data_out;
initial  begin 
sclk    =        0;
forever          #5
sclk    =       ~sclk;
end  
initial  begin 
        async_rst_n          <=        0;
        wr_valid             <=        0;  
        #100  
        async_rst_n          <=        1;
        #10
        @(posedge    sclk)
        @(posedge    sclk)
        @(posedge    sclk)
        @(posedge    sclk)
        wr_valid                  <=             1;       
        #10
        wr_valid                  <=             0;
        gen_data(  );
end  
//@(posedge    wr_valid)
//gen_data(  );
//end 
task  gen_data;
integer     i;  
begin
    for(i= 0;      i   <   12288;      i =    i   +   1)  begin
        @(posedge   sclk)
           data_in     =       i[7:0];
        end  
    end 
endtask   
pingpang_ram     u_pingpang_ram(
    .sclk        ( sclk        ),
    .async_rst_n ( async_rst_n ),
    .wr_valid    ( wr_valid    ),
    .data_in     ( data_in     ),
    .data_out    ( data_out    )
);
endmodule
2.4、仿真驗(yàn)證結(jié)果

圖2-2-1、乒乓RAM仿真結(jié)果-輸出數(shù)據(jù)連續(xù)

圖2-2-2、乒乓RAM仿真結(jié)果-輸入-輸出數(shù)據(jù)對(duì)應(yīng)
- 
                                FPGA
                                +關(guān)注
關(guān)注
1652文章
22231瀏覽量
628548 - 
                                ROM
                                +關(guān)注
關(guān)注
4文章
578瀏覽量
88368 - 
                                RAM
                                +關(guān)注
關(guān)注
8文章
1397瀏覽量
119645 - 
                                Xilinx
                                +關(guān)注
關(guān)注
73文章
2190瀏覽量
129439 - 
                                邏輯設(shè)計(jì)
                                +關(guān)注
關(guān)注
1文章
41瀏覽量
11912 
發(fā)布評(píng)論請(qǐng)先 登錄
利用FPGA實(shí)現(xiàn)雙口RAM的設(shè)計(jì)及應(yīng)用
    
FPGA中塊RAM的分布和特性
    
如何實(shí)現(xiàn)ASIC RAM替換為FPGA RAM?
FPGA簡(jiǎn)介
基于Actel FPGA的雙端口RAM設(shè)計(jì)
FPGA的RAM存儲(chǔ)資源詳細(xì)資料說明
    
FPGA硬件基礎(chǔ)之FPGA的RAM存儲(chǔ)課件和工程文件
    
使用FPGA調(diào)用RAM資源的詳細(xì)說明
如何使用FPGA內(nèi)部的RAM以及程序?qū)υ?b class='flag-5'>RAM的數(shù)據(jù)讀寫操作
    
基于FPGA的ROM的實(shí)現(xiàn)簡(jiǎn)介
    
          
        
        
FPGA RAM簡(jiǎn)介和使用案例
                
 
    
           
            
            
                
            
評(píng)論