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

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

3天内不再提示

基于FPGA BRAM的多端口地址查找表与FPGA BRAM的资源分析

网络交换FPGA 来源:网络交换FPGA 2024-05-01 14:03 次阅读

一、背景

在多端口交换机的设计中,交换机的每个端口都会各自维护一张查找表,数据帧进入到交换机后,需要进行查表和转发。但随着端口数量和表项需求的增加,每个端口都单独维护一张表使得FPGA的资源变得非常紧张。因此,需要一张查找表(本质是可读可写的RAM),能够满足多读多写的功能。但在Xilinx FPGA上,Xilinx提供的BRAM IP最高只能实现真双端口RAM。不能满足多读多写的需求。

补充:这里不使用其他RAM类型如URAM的原因是,BRAM拥有更好的时序,更适合在高速交换中用于查找表。

二、手写Multiport Ram

Multiport Ram,即多读多写存储器,本工程实现的是1个口写,同时满足11个口读的BRAM

为了让vivado在综合的时候把手写ram例化为BRAM,我们需要按照官方手册的要求编写multiport ram。这时需要通过(*ram_style="block"*)对array进行修饰。

查看Vivado的官方手册ug901可知,对于Distributed RAM(LUTRAM)和Dedicated Block RAM(BRAM),二者都是写同步的。主要区别在于读数据,前者为异步,后者为同步的。

1eb9cb74-0065-11ef-a297-92fbcf53809c.png

下面给出一种手写多端口bram的方案并给出一种优化FPGA bram资源利用的方法。

Multiport RAM 代码方案

实现多端口bram最简单的方法就是把读数据部分的逻辑复制11份,写数据部分的逻辑保留1份。

部分代码如下,实现位宽73bit,深度为16K的multiport ram:

(*ram_style="block"*)reg [DATA_WIDTH-1:0] bram [0:DEPTH-1];
/*-------------复制读端口11份---------------*/
    always @(posedge clk)
    begin
        if(re1)
            rd_data1 <= bram[rd_addr1];
        else
            rd_data1 <= rd_data1;
    end
/*-----------------------------------------*/
    //write
    always @(posedge clk)
    begin
        if(we)
            bram[wr_addr]<=wr_data;
    end
endmodule

资源评估

利用vivado综合实现后,消耗的资源如下

1ee47342-0065-11ef-a297-92fbcf53809c.png

MultiportRAM16K深度,73位宽的单口写,11口读的RAM消耗的BRAM数为192个。

普通真双口RAM:利用vivado IP核生成的16K深度,73bit位宽的真双口RAM消耗的BRAM数为32个。即如果11个端口各自维护一张地址查找表共使用352个RAM。

对比发现,在满足11个端口同时读地址查找表的条件下,多端口RAM比普通RAM节约了45%左右的BRAM资源

三、Multiport RAM 资源利用的优化

可能有的同学说,在某些大工程里面,192个BRAM还是有点多。下面我给出了一种降低BRAM资源消耗的方法。

首先我们把例化的ram array的位宽翻倍

//原本
(*ram_style="block"*)reg [DATA_WIDTH-1:0] bram [0:DEPTH-1];
//现在
(*ram_style="block"*)reg [DATA_WIDTH+DATA_WIDTH-1:0] bram [0:DEPTH-1];

(有同学会问了,这样资源消耗不是翻倍了吗?···别急!)

我们把需要写入RAM的数据,73位写data复制成两份,同时写进bram的高73位和低73位,地址不变,其中multi_wdata是我们要写进表中的73位表项,代码如下:

//bram例化模块的写使能、地址和数据
    .we       (   multi_wr),
    .wr_addr  (multi_waddr),
.wr_data({multi_wdata,multi_wdata})

在bram输出中,每两个端口共用一个143位的bram行,并根据使能情况赋值:

   //read1
    assign rd_data1_wire = rd_data1[72:0]  ;
    assign rd_data2_wire = rd_data2[145:73];
    always @(posedge clk)
    begin
        if (re1 & re2) begin
            rd_data1 <=  bram[rd_addr1];
            rd_data2 <=  bram[rd_addr2];
        end
        else 
        if(re1) begin
             rd_data1 <=  bram [rd_addr1];
        end
        else if (re2) begin
            rd_data2 <= bram [rd_addr2];
        end 


    end

***补充:具体代码在文章开头链接

资源评估

利用vivado综合实现后,消耗的资源如下

1efb0be8-0065-11ef-a297-92fbcf53809c.png

MultiportRAM:16K深度,146位宽的单口写,11口读的RAM消耗的BRAM数为112个。

普通真双口RAM:利用vivado IP核生成的16K深度,73bit位宽的真双口RAM消耗的BRAM数为32个。即如果11个端口各自维护一张表共使用352个RAM

对比发现,在满足11个端口同时读地址查找表的条件下,多端口RAM比普通RAM节约了68%左右的BRAM资源

四、防止读写冲突的组合逻辑设计(写优先)

代码原理,利用组合逻辑时序,当写入地址和读地址相同时,写入地址、数据正常进行但读端口不对RAM进行读取,而是将写入端的数据直接赋值给读出端的数据。

下一拍,即读写冲突结束后的下一拍,再读一拍RAM中的数据,使得读端口数据保持这一次读的结果(因为组合逻辑在读写冲突时没有真正读RAM,所以RAM输出data会保持上一次输出的data),但这一步不是必要的,纯粹为了好看。

部分代码如下:

//防止读写冲突,且为写优先逻辑
assign multi_rdata0 =(multi_raddr0_f ==multi_waddr_f && multi_raddr0_f !='b0 )?multi_wdata_f:multi_rdata0_ram ;
assign multi_rdata1 =(multi_raddr1_f ==multi_waddr_f && multi_raddr1_f !='b0 )?multi_wdata_f:multi_rdata1_ram ;
assign multi_rdata2 =(multi_raddr2_f ==multi_waddr_f && multi_raddr2_f !='b0 )?multi_wdata_f:multi_rdata2_ram ;
assign multi_rdata3 =(multi_raddr3_f ==multi_waddr_f && multi_raddr3_f !='b0 )?multi_wdata_f:multi_rdata3_ram ;
assign multi_rdata4 =(multi_raddr4_f ==multi_waddr_f && multi_raddr4_f !='b0 )?multi_wdata_f:multi_rdata4_ram ;
assign multi_rdata5 =(multi_raddr5_f ==multi_waddr_f && multi_raddr5_f !='b0 )?multi_wdata_f:multi_rdata5_ram ;
assign multi_rdata6 =(multi_raddr6_f ==multi_waddr_f && multi_raddr6_f !='b0 )?multi_wdata_f:multi_rdata6_ram ;
assign multi_rdata7 =(multi_raddr7_f ==multi_waddr_f && multi_raddr7_f !='b0 )?multi_wdata_f:multi_rdata7_ram ;
assign multi_rdata8 =(multi_raddr8_f ==multi_waddr_f && multi_raddr8_f !='b0 )?multi_wdata_f:multi_rdata8_ram ;
assign multi_rdata9 =(multi_raddr9_f ==multi_waddr_f && multi_raddr9_f !='b0 )?multi_wdata_f:multi_rdata9_ram ;
assign multi_rdata10=(multi_raddr10_f==multi_waddr_f && multi_raddr10_f!='b0 )?multi_wdata_f:multi_rdata10_ram;


assign multi_raddr0_ram =(multi_raddr0_f ==multi_waddr_f && multi_raddr0_f !='b0 )?multi_waddr_f: multi_raddr0;
assign multi_raddr1_ram =(multi_raddr1_f ==multi_waddr_f && multi_raddr1_f !='b0 )?multi_waddr_f: multi_raddr1;
assign multi_raddr2_ram =(multi_raddr2_f ==multi_waddr_f && multi_raddr2_f !='b0 )?multi_waddr_f: multi_raddr2;
assign multi_raddr3_ram =(multi_raddr3_f ==multi_waddr_f && multi_raddr3_f !='b0 )?multi_waddr_f: multi_raddr3;
assign multi_raddr4_ram =(multi_raddr4_f ==multi_waddr_f && multi_raddr4_f !='b0 )?multi_waddr_f: multi_raddr4;
assign multi_raddr5_ram =(multi_raddr5_f ==multi_waddr_f && multi_raddr5_f !='b0 )?multi_waddr_f: multi_raddr5;
assign multi_raddr6_ram =(multi_raddr6_f ==multi_waddr_f && multi_raddr6_f !='b0 )?multi_waddr_f: multi_raddr6;
assign multi_raddr7_ram =(multi_raddr7_f ==multi_waddr_f && multi_raddr7_f !='b0 )?multi_waddr_f: multi_raddr7;
assign multi_raddr8_ram =(multi_raddr8_f ==multi_waddr_f && multi_raddr8_f !='b0 )?multi_waddr_f: multi_raddr8;
assign multi_raddr9_ram =(multi_raddr9_f ==multi_waddr_f && multi_raddr9_f !='b0 )?multi_waddr_f: multi_raddr9;
assign multi_raddr10_ram=(multi_raddr10_f==multi_waddr_f && multi_raddr10_f!='b0 )?multi_waddr_f: multi_raddr10;






assign multi_rd0_ram =(multi_raddr0 ==multi_waddr && multi_raddr0!='b0  )?  1'b0:((multi_raddr0_f ==multi_waddr_f && multi_raddr0_f !='b0  )?multi_rd0_f :multi_rd0 );
assign multi_rd1_ram =(multi_raddr1 ==multi_waddr && multi_raddr1!='b0  )?  1'b0:((multi_raddr1_f ==multi_waddr_f && multi_raddr1_f !='b0  )?multi_rd1_f :multi_rd1 );
assign multi_rd2_ram =(multi_raddr2 ==multi_waddr && multi_raddr2!='b0  )?  1'b0:((multi_raddr2_f ==multi_waddr_f && multi_raddr2_f !='b0  )?multi_rd2_f :multi_rd2 );
assign multi_rd3_ram =(multi_raddr3 ==multi_waddr && multi_raddr3!='b0  )?  1'b0:((multi_raddr3_f ==multi_waddr_f && multi_raddr3_f !='b0  )?multi_rd3_f :multi_rd3 );
assign multi_rd4_ram =(multi_raddr4 ==multi_waddr && multi_raddr4!='b0  )?  1'b0:((multi_raddr4_f ==multi_waddr_f && multi_raddr4_f !='b0  )?multi_rd4_f :multi_rd4 );
assign multi_rd5_ram =(multi_raddr5 ==multi_waddr && multi_raddr5!='b0  )?  1'b0:((multi_raddr5_f ==multi_waddr_f && multi_raddr5_f !='b0  )?multi_rd5_f :multi_rd5 );
assign multi_rd6_ram =(multi_raddr6 ==multi_waddr && multi_raddr6!='b0  )?  1'b0:((multi_raddr6_f ==multi_waddr_f && multi_raddr6_f !='b0  )?multi_rd6_f :multi_rd6 );
assign multi_rd7_ram =(multi_raddr7 ==multi_waddr && multi_raddr7!='b0  )?  1'b0:((multi_raddr7_f ==multi_waddr_f && multi_raddr7_f !='b0  )?multi_rd7_f :multi_rd7 );
assign multi_rd8_ram =(multi_raddr8 ==multi_waddr && multi_raddr8!='b0  )?  1'b0:((multi_raddr8_f ==multi_waddr_f && multi_raddr8_f !='b0  )?multi_rd8_f :multi_rd8 );
assign multi_rd9_ram =(multi_raddr9 ==multi_waddr && multi_raddr9!='b0  )?  1'b0:((multi_raddr9_f ==multi_waddr_f && multi_raddr9_f !='b0  )?multi_rd9_f :multi_rd9 );
assign multi_rd10_ram=(multi_raddr10==multi_waddr && multi_raddr1!='b0  )?  1'b0:((multi_raddr10_f==multi_waddr_f && multi_raddr10_f!='b0  )?multi_rd10_f:multi_rd10);

***补充:具体代码在文章开头链接

读写冲突的仿真结果如下:

1f15203c-0065-11ef-a297-92fbcf53809c.png

五、Multiport RAM仿真和时序

所有写端口都是一拍写入。读端口是第一拍读使能,读地址,第二拍读出数据。

1.单口写数据

1f45b6b6-0065-11ef-a297-92fbcf53809c.png

2.单端口读数据

1f601862-0065-11ef-a297-92fbcf53809c.png

3.多口读相同数据

1f7fb438-0065-11ef-a297-92fbcf53809c.png

4.多口同时读不同数据

1fb0918e-0065-11ef-a297-92fbcf53809c.png


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

    关注

    1604

    文章

    21337

    浏览量

    594003
  • 存储器
    +关注

    关注

    38

    文章

    7177

    浏览量

    162175
  • 交换机
    +关注

    关注

    19

    文章

    2447

    浏览量

    95757
  • BRAM
    +关注

    关注

    0

    文章

    41

    浏览量

    10889
  • Vivado
    +关注

    关注

    18

    文章

    790

    浏览量

    65270

原文标题:Multiport RAM,多读多写寄存器-——基于FPGA BRAM的多端口地址查找表与FPGA BRAM的资源分析

文章出处:【微信号:gh_cb8502189068,微信公众号:网络交换FPGA】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    FPGA设计中BRAM的知识科普

    FPGA设计中,BRAM是一项非常关键的内置存储资源FPGA开发需要熟练使用BRAM,今天再复习一下B
    发表于 08-15 15:44 2493次阅读
    <b class='flag-5'>FPGA</b>设计中<b class='flag-5'>BRAM</b>的知识科普

    怎么从Virtex 6的FPGA中取出BRAM转储

    大家好请任何人告诉我。是否有任何方法可以从Virtex 6的FPGA中取出BRAM转储。提前致谢问候Vir_1602以上来自于谷歌翻译以下为原文Hi all would anyone please
    发表于 03-20 15:37

    如何在不使用DDR内存控制器的情况下设计FPGA BRAM大容量存储单元?

    来修改我的设计。我删除了mig_7series IP并将BRAM连接到AXI总线。我还将Microblaze M_AXI_IC和M_AXI_DC端口连接到BRAM,并检查了MB缓存地址
    发表于 04-04 15:10

    无法正确写入双端口BRAM

    嗨,我正在尝试使用自定义IP写入vhdl中的双端口BRAM,该IP生成地址并启用所有信号,但我无法正确写入双端口BRAM
    发表于 04-17 08:15

    BRAM阅读访问出现错误的原因?

    我正在使用具有真正双端口BRAM控制器来将FPGA逻辑与微型接口连接起来。我可以在UART上读取这些内存位置。但是,BRAM的读访问似乎存在一些问题。如图所示,当我写入多个位置(WE
    发表于 04-24 09:05

    在Virtex-5 FPGA中如何使用BRAM代替SRAM

    嗨,我正在开发一个项目,我们正在使用Virtex-5 FPGA从ADC捕获信号,样本存储在128K x 256 SRAM上,数据样本由PC采集。我相信Virtex-5为BRAM提供了一个选项,虽然我
    发表于 06-17 11:31

    URAM和BRAM的区别是什么

    。  工作模式  BRAM 可配置为单端口、简单双端口和真双端口,但对于 URAM,不能简单地将这三种模式映射过来,其工作行为如下图所示。可以看到,A/B
    发表于 12-23 16:57

    FPGA实现基于Vivado的BRAM IP核的使用

    核的使用。     BRAMFPGA定制的RAM资源,有着较大的存储空间,且在日常的工程中使用较为频繁。BRAM以阵列的方式排布于FPGA
    的头像 发表于 12-29 15:59 9949次阅读

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

    RAM),其中BRAM是block ram,是存在FPGA中的大容量的RAM,DRAM是FPGA中有LUT(look-up table 查找表)组成的。当使用的容量较小会综合成DRA
    发表于 12-30 16:27 9次下载

    URAM和BRAM有哪些区别

    无论是7系列FPGA、UltraScale还是UltraScale Plus系列FPGA,都包含Block RAM(BRAM),但只有UltraScale Plus芯片有UltraRAM也就是我们所说的URAM。
    的头像 发表于 07-25 17:54 4797次阅读
    URAM和<b class='flag-5'>BRAM</b>有哪些区别

    URAM和BRAM有什么区别

    无论是7系列FPGA、UltraScale还是UltraScale Plus系列FPGA,都包含Block RAM(BRAM),但只有UltraScale Plus芯片有UltraRAM也就是我们所说的URAM。
    发表于 01-27 06:55 12次下载
    URAM和<b class='flag-5'>BRAM</b>有什么区别

    Vivado中BRAM IP的配置方式和使用技巧

    FPGA开发中使用频率非常高的两个IP就是FIFO和BRAM,上一篇文章中已经详细介绍了Vivado FIFO IP,今天我们来聊一聊BRAM IP。
    的头像 发表于 08-29 16:41 3159次阅读
    Vivado中<b class='flag-5'>BRAM</b> IP的配置方式和使用技巧

    FPGABRAM资源使用优化策略

    FPGABRAM和LUT等资源都是有限的,在FPGA开发过程中,可能经常遇到BRAM或者LUT资源
    的头像 发表于 08-30 16:12 1180次阅读
    <b class='flag-5'>FPGA</b>的<b class='flag-5'>BRAM</b><b class='flag-5'>资源</b>使用优化策略

    FPGA实现基于Vivado的BRAM IP核的使用

    定制的RAM资源,有着较大的存储空间,且在日常的工程中使用较为频繁。BRAM以阵列的方式排布于FPGA的内部,是FPGA实现各种存储功能的主要部分,是真正的双读/写
    的头像 发表于 12-05 15:05 615次阅读

    基于FPGA设计的BRAM内部结构

    再看末级触发器对BRAM时序性能的影响,下图依次展示了7系列FPGA、UltraScale+和Versal芯片在未使用和使用末级触发器两种情形下时钟到输出的延迟。
    发表于 04-25 10:42 79次阅读
    基于<b class='flag-5'>FPGA</b>设计的<b class='flag-5'>BRAM</b>内部结构