0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

FPGA RAM简介和使用案例

CHANBAEK 来源:工程实验室 作者:工程实验室 2023-08-22 16:12 次阅读

FPGA 逻辑设计中经常用到的数据存储方式有ROMRAM和FIFO,根据不同的应用场景选择不同的存储方式。Xilinx 平台三种存储方式在使用过程中的区别如下:

1、ROM按照地址读写,使用初始化.ceo文件将地址和对应的数据内容存入,读数据的时候给地址,输出地址中存储的数据。支持反复读取,读取过程中不会使数据减少;

2、RAM按照地址读写数据,按照指定的地址写入数据,读数据的时候给地址,输出地址中存储的数据,支持反复读取,读取过程中不会使数据减少;

3、FIFO没有地址参与,先写入的数据被先读出,就是先进先出,读取数据的过程中读一个少一个,就像鸡蛋放在篮子中取出一个少一个。

01 RAM简介

RAM,random access memory,是随机存取存储器的缩写,掉电后数据丢失。 这里使用简单双端口RAM举例,即端口A写数据,端口B读数据。

图片

端口A写入数据的过程中WEA==1'b1 && ENA==1'b1,条件同时满足的时候,DINA的数据被写入到指定的内存地址中。

图片

端口B读出数据的时候,读使能和读地址同时有效,读出数据需要延迟一个时钟周期。

图片

1.1、vivado中添加RAM-IP核

step1:在ip-catalog中搜索ram,找到 block memory generator

图片

step2:在ip核配置

图片

step3:端口A设置(写入数据位宽和深度)

图片

step4:端口B设置(注意细节)

图片

step5:其他设置

图片

02 RAM使用案例

2.1、简单双端口RAM使用案例

简单双端口RAM使用的案例有1、数据缓冲-实现位宽转化;2、对应连续待处理的数据流使用乒乓RAM,实现数据流不间断的输入到处理模块。本文主要对乒乓RAM做一个详细介绍和测试应用。

图片

2.2、乒乓RAM读写时序设计

乒乓RAM读写时序设计波形图中读写时钟使用了相同的时钟信号,当读写数据的时钟不同时,就是异步乒乓RAM。首先对RAMA写入数据,按地址写入数据结束以后读取RAMA的数据给数据处理模块,同时将外部输入的数据缓存到RAMB中,保证同一时间内既有数据缓存又有数据输出,实现的效果就是外部不间断地输入数据,经过RAM处理以后不间断地输出到下一级处理模块。

图片

图2-2-1、乒乓RAM读写时序设计

2.3、代码实现

根据时序设计波形图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
    );


//  信号定义 
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;         // 符合条件后---立即响应 


// 异步复位,同步释放,异步复位信号,同步处理
always@(posedge sclk or negedge async_rst_n)   begin 
    if(!async_rst_n)   begin 
    sync_rst_n1    <=     1'b0;                             //  复位开始的时候 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 


//   写地址信号  
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 
//   读使能信号  
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      
//   读地址信号  
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 
//   写地址信号  
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 
//   读使能信号  
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    
//   读地址信号  
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

仿真激励文件

`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、仿真验证结果

图片

图2-2-1、乒乓RAM仿真结果-输出数据连续

图片

图2-2-2、乒乓RAM仿真结果-输入-输出数据对应

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1625

    文章

    21648

    浏览量

    601444
  • ROM
    ROM
    +关注

    关注

    4

    文章

    562

    浏览量

    85641
  • RAM
    RAM
    +关注

    关注

    8

    文章

    1366

    浏览量

    114496
  • Xilinx
    +关注

    关注

    71

    文章

    2161

    浏览量

    120920
  • 逻辑设计
    +关注

    关注

    1

    文章

    41

    浏览量

    11564
收藏 人收藏

    评论

    相关推荐

    利用FPGA实现双口RAM的设计及应用

    利用FPGA实现双口RAM的设计及应用 概述:为了在高速采集时不丢失数据,在数据采集系统和
    发表于 04-16 14:08 1.2w次阅读
    利用<b class='flag-5'>FPGA</b>实现双口<b class='flag-5'>RAM</b>的设计及应用

    如何实现ASIC RAM替换为FPGA RAM

    大家好, 我使用Ultrascale Virtex Devices和Vivado工具, 在ASIC RAM中,ther是一个单独的奇偶校验写使能位,但在FPGA RAM中没有单独的Pariaty写使能位。 如何实现ASIC
    发表于 04-24 09:37

    FPGA简介

    (06)FPGA资源评估1.1 目录1)目录2)FPGA简介3)Verilog HDL简介4)FPGA资源评估5)结语1.2
    发表于 02-23 06:31

    基于FPGA的双口RAM实现及应用

      为了在高速采集时不丢失数据,在数据采集系统和CPU之间设置一个数据暂存区。介绍双口RAM的存储原理及其在数字系统中的应用。采用FPGA技术构造双口RAM,实现高速信号采集系
    发表于 02-11 11:20 69次下载

    基于Actel FPGA的双端口RAM设计

    基于Actel FPGA 的双端口RAM 设计双端口RAM 芯片主要应用于高速率、高可靠性、对实时性要求高的场合,如实现DSP与PCI 总线芯片之间的数据交换接口电路等。但普通双端口RAM
    发表于 11-15 17:44 82次下载

    Cyclone FPGA系列简介

    Cyclone FPGA系列简介
    发表于 12-26 22:02 0次下载

    _FPGA内部的RAM M9K

    FPGA内部的RAM M9K
    发表于 04-07 11:40 4次下载

    技术控:FPGARAM使用技巧探索

    FPGARAM的使用探索。以4bitX4为例,数据位宽为4,深度为4。
    的头像 发表于 03-28 17:07 1w次阅读
    技术控:<b class='flag-5'>FPGA</b>中<b class='flag-5'>RAM</b>使用技巧探索

    FPGARAM存储资源详细资料说明

    本文档的主要内容详细介绍的是FPGARAM存储资源详细资料说明包括了:1、 FPGA存储资源简介,2、 不同厂家的 Block RAM
    发表于 12-09 15:31 10次下载
    <b class='flag-5'>FPGA</b>的<b class='flag-5'>RAM</b>存储资源详细资料说明

    FPGA硬件基础之FPGARAM存储课件和工程文件

    本文档的主要内容详细介绍的是FPGA硬件基础之FPGARAM存储课件和工程文件。
    发表于 12-10 15:27 30次下载
    <b class='flag-5'>FPGA</b>硬件基础之<b class='flag-5'>FPGA</b>的<b class='flag-5'>RAM</b>存储课件和工程文件

    使用FPGA调用RAM资源的详细说明

    FPGA可以调用分布式RAM和块RAM两种RAM,当我们编写verilog代码的时候如果合理的编写就可以使我们想要的RAM被综合成BRAM(
    发表于 12-30 16:27 9次下载

    如何使用FPGA内部的RAM以及程序对该RAM的数据读写操作

    RAMFPGA中常用的基础模块,可广泛用于缓存数据的情况,同样它也是ROM,FIFO的基础。本实验将为大家介绍如何使用FPGA内部的RAM以及程序对该
    的头像 发表于 02-08 15:50 1.4w次阅读
    如何使用<b class='flag-5'>FPGA</b>内部的<b class='flag-5'>RAM</b>以及程序对该<b class='flag-5'>RAM</b>的数据读写操作

    基于FPGA的ROM的实现简介

    基于FPGA的ROM的实现简介(嵌入式开发工程师培训学校)-该文档为基于FPGA的ROM的实现简介资料,讲解的还不错,感兴趣的可以下载看看…………………………
    发表于 07-30 09:08 5次下载
    基于<b class='flag-5'>FPGA</b>的ROM的实现<b class='flag-5'>简介</b>

    FPGA电源简介

    FPGA电源简介
    发表于 11-04 09:51 0次下载
    <b class='flag-5'>FPGA</b>电源<b class='flag-5'>简介</b>

    fpga双口ram的使用

    FPGA双口RAM的使用主要涉及配置和使用双端口RAM模块。双端口RAM的特点是有两组独立的端口,可以对同一存储块进行读写操作,从而实现并行访问。
    的头像 发表于 03-15 13:58 914次阅读