【小白入门】Verilog实现异步FIFO

您所在的位置:网站首页 verilog仿真波形图有字母 【小白入门】Verilog实现异步FIFO

【小白入门】Verilog实现异步FIFO

2023-06-18 16:37| 来源: 网络整理| 查看: 265

 

 之前也在CSDN上面写过两个FIFO相关的文章,不过代码看起来比较复杂,且注释也比较少,不利于新手入门。很多时候都没有耐心继续看下去。

http://t.csdn.cn/0dPX6

http://t.csdn.cn/lYvoY 

因为自己本身是一个初学者,就从初学者的视角来看待并学习FIFO。

为什么选择学习FIFO?

在学完双端口RAM之后看待FIFO,会觉得为什么要用FIFO呢?双端口的RAM也可以实现数据的存储与读取,读写的时钟也可以不一样,为什么不用RAM而要基于RAM来设计一个FIFO呢?

FIFO与RAM的区别是先进先出,不需要读地址和写地址。 写时钟下,将数据写入FIFO中,在读时钟下将先写入的数据先读出来,不需要向FIFO输入写地址和读地址即可完成数据的存储以及不同时钟下的读写操作,这样一听是非常方便的。在SDRAM的学习过程中,我们知道有突发长度这个东西,当突发长度为1的时候,即一个写地址对应一个写数据,这样是非常麻烦的,所以很多SDRAM如DDR3这种,都会将突发长度设置为8,即给一个首地址,后面连续读取8个数据。

 

再贴一张异步FIFO的图

 

在写代码之前,需要了解几个概念。

 先思考,FIFO的存储空间和RAM是一样的,就像一个n行x1列的表格,每个表格里面存放一个数据,并且对应一个地址,在读写的过程中肯定会存在表格写满的情况和读的时候里面没有数据的情况,那应该怎么判断呢?

读写同时进行时

①首先是在读的视角,如果如果读一行数据的时候,刚好也在往这一行数据里面写数据,那这个时候即可判断读空了,如果再继续向下读的话,里面就没有写进的数据,读出的数据也不是我们写进去的,就是无效的。

所以读空的判断条件是:在读时钟的视角下,写时钟同步过来的地址等于我目前正在读的地址。

关于跨时钟域的问题,大家可以去搜索一下跨时钟域以及亚稳态。也可以看我的这篇文章。

http://t.csdn.cn/hvJTa

②在写的视角下, 那什么时候写满呢?因为地址是有限的嘛,当读完一个数据的时候,读对应哪个地址的数据就已经不需要了,因为我们以及读了,即读完的那个“位置”空了。所以当写完一圈,并且追上下一轮的读的时候,就代表写满了。

所以写满判断的条件是:在写的时钟下,写完一圈对应的地址,等于同步过来的读地址。

 

其次在写代码的时候,还需要了解格雷码,地址是按照0000-0001-0010-xxxx这种增长的,但是在地址变化的过程中,地址中的位数会存在”跳变“,如从0001-0010这两个相邻码的时候,有两位发生了变化,这样是不好的。 具体可以参考这篇文章

http://t.csdn.cn/OiesB

以下是代码Verilog的代码

`timescale 1ns / 1ps module asyn_fifo1 ( input rst_n , input wr_clk , input wr_en , input [7:0] data_in , input rd_clk , input rd_en , output full , output empty , output reg [7:0] data_out ); reg [7:0] ram_mem[255:0] ; //定义一个位宽为8bit深度为256的双端口RAM wire [7:0] rd_addr ; wire [7:0] wr_addr ; reg [8:0] rd_addr_ptr ; //格雷码需要移位运算,且判断写满信号也需要多一位 reg [8:0] wr_addr_ptr ; wire [8:0] rd_addr_gray ; reg [8:0] rd_addr_gray1 ; reg [8:0] rd_addr_gray2 ; wire [8:0] wr_addr_gray ; reg [8:0] wr_addr_gray1 ; reg [8:0] wr_addr_gray2 ; assign rd_addr[7:0] = rd_addr_ptr[7:0]; assign wr_addr[7:0] = wr_addr_ptr[7:0]; assign rd_addr_gray = (rd_addr_ptr>>1) ^ rd_addr_ptr; //bin to gray assign wr_addr_gray = (wr_addr_ptr>>1) ^ wr_addr_ptr; //dual port ram integer i; always @(posedge wr_clk or negedge rst_n) //写时钟下初始化RAM begin if(rst_n == 1'b0) for(i=0;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3