首页 > 编程知识 正文

fpga 分布式ram,双口ram工作原理

时间:2023-05-05 10:31:50 阅读:230761 作者:2539

文章目录 前言设计介绍关于仿真老生常谈最后想说的话

前言

RAM是一个好东西,FIFO也是,关键是适应你的设计场景,本文是一个记录性质的博文,所以也没必要什么都交代清楚了,只是在项目开发中,有过FIFO和RAM的取舍思考,最终 RAM更符合需求。
想到哪里写到哪里吧,正双口RAM,一边是A端口,另一边是B端口,A端口用于dsp总线(emif总线)写,写入RAM中,同时另一边仅仅用于读取写入的数据,可以说是一边写一边读了。

既然A端口是供dsp总线写,那么肯定有地址,因此这里选择RAM而非FIFO的因素大些(至于为什么想到了FIFO,还不是因为边读边写嘛)。

设计介绍

关于设计介绍,其实前言也已经说明了本次使用RAM的背景,也就是选择RAM的原因。
继续想到哪里说到哪里:
对于RAM的使用,在FPGA开发中,这里理所当然地使用了IP核,尽管我之前也写过多篇博文自己写过多种RAM,无论是同步读写,或者异步读写都有。
其中一些链接:同步读写双端口RAM

其实直接在我的博文首页搜索框中搜索RAM 即可:

博文首页地址:
申请了新域名,还挺满意!


当然,加上一系列综合属性,也可以控制FPGA使用资源了。
好了,这里就不磨叽了,直接使用IP核,还是比较信得过IP核,比较成熟,反正以后也是做FPGA的(又不是做IC逻辑设计),用IP核理所当然呢。
在IP的定制中,可以选择原语输出以及IP输出是否寄存?
当然,原语是更下层的东西,被iP核包裹,因此,如果选择某一个寄存,则输出肯定会延迟一拍,当然,选择二者都寄存,延迟两拍。
本设计选择了IP核寄存,又因为输出固有的一拍延迟,共两拍延迟(如果不信,可以都选上,看看最后结果是不是延迟三拍):

这在心里要有底,后面仿真会用到这里的信息。
由于A端口用来写,B端口用来读,因此A端口的输出douta就是废弃了,B端口的写数据dinb也废弃了,我的例化如下:

关于仿真

其实以上所说还都是废话,或者说不是我想 记录的东西,我想记录的东西在仿真方面:
先说正常的情况,在行为仿真时候,我们在时钟的下降沿给地址以及要写入a端口的数据,设计仿真文件如下:

`timescale 1ns / 1ps//// Company: // Engineer: // // Create Date: 2020/05/07 17:58:42// Design Name: // Module Name: gt0_data_gen_tb// Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision:// Revision 0.01 - File Created// Additional Comments:// //module gt0_data_gen_tb( );// User Interfacewire [15:0] TX_DATA_OUT;wire [1:0] TXCTRL_OUT; // System Interfacereg USER_CLK;reg SYSTEM_RESET; // Dsp Interfacereg [10:0]dsp_addr;reg [15:0]dsp_data;//____________________ generate clk ________________________________________initial beginUSER_CLK = 0;forever begin#5 USER_CLK = ~USER_CLK;end // end // // always begin// USER_CLK = 0;// #5USER_CLK = ~ USER_CLK;// end // //__________________ generate address and data ______________________________initial beginSYSTEM_RESET = 1;dsp_addr = 0;dsp_data = 0;#14 SYSTEM_RESET = 0;#7forever begin@(negedge USER_CLK) begindsp_addr = dsp_addr + 1;dsp_data = dsp_data + 2;end // endend // //___________________ instantiate the module under test ______________________gt0_data_gen inst_gt0_data_gen(.TX_DATA_OUT (TX_DATA_OUT),.TXCTRL_OUT (TXCTRL_OUT),.USER_CLK (USER_CLK),.SYSTEM_RESET (SYSTEM_RESET),.dsp_addr (dsp_addr),.dsp_data (dsp_data));endmodule

关键语句为:

initial beginSYSTEM_RESET = 1;dsp_addr = 0;dsp_data = 0;#14 SYSTEM_RESET = 0;#7forever begin@(negedge USER_CLK) begindsp_addr = dsp_addr + 1;dsp_data = dsp_data + 2;end // endend //

我们进行行为仿真结果如下:
可见,在b端口给地址后,延迟两拍输出结果。符合预期:

当然,如果在上升沿给A端口地址和数据的话,因为是行为仿真,不考虑组合逻辑延迟之类的,我们肯定也能得到同样的结论,因为这是事实:

针对002地址输出,延迟两拍没有问题。
但对比下降沿存储时候还是有区别的,区别就是001地址哪去了?
(这里不得不提出必要说明,B端口的地址是A端口的地址延迟一拍所得!):

在上升沿对ram进行存储数据时候,仿真情况貌似看不出来B地址对A地址进行了延迟。
这一点在下降沿存储时候是可以看出的。
单纯的地址对比:
下降沿对A端口写数据:

上升沿对A端口写数据:

B端口001地址被吞了吗?

老生常谈

这还是一个老生常谈的话题:
先这样说吧,事实上,怎么会有这么巧的事情呢?
我们都知道,这个IP核在对A端口写数据是在时钟上升沿写数据的,而你在时钟上升沿给数据和地址,放在现实情况中,也就是板子上,存在延迟,就是建立时间不满足嘛!所以仿真的时候在下降沿或者什么地方(只要不是上升沿)给地址和数据,就不会出现这种仿真现象。
好了,你又要说了,那行为仿真不是没有延迟吗?也就是理想情况呀,即使在上升沿给数据以及地址,就写不进数据到RAM中吗?
当然不是呀,你不是也看了吗?从B端口也能读出写进去的数据呀!
只不过出现的问题是地址没有相对于写地址延迟明显的一个时钟?
其实不然,因为地址是你在仿真文件中直接给的,然后进入设计文件中,然后寄存地址,这一操作属于同步到时钟域操作,如果在寄存一拍,则就是同一个时钟域内的操作了,就可以明显看出一个时钟的延迟。

最后想说的话

这篇博客属于想到哪里写到哪来,到这里也告一段落了,至于这一篇博客最后的问题,和上升沿检测仿真时候一样,如果使用当前信号与延迟一拍的信号进行逻辑操作取得上升沿,也会出现这种情况,原因一致,何不同步一下,在延迟一拍,然后再取上升沿呢?
这就是解决之道。
最后想说的是,设想每年都会新建立一个微信群,供应届同行找工作讨论问题所用。
目前已经有两个群了,第一个是我那一届2019秋招,群已满,对于2020秋招,又新建了一个,供应届以及有兴趣的非应届的加入,共同讨论FPGA以及IC设计问题:

路过的同行可以加我微信(ljs521615)之后,进群,记得备注CSDN,我才知道是CSDN过来的。
IC/FPGA技术交流群2020

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。