当前位置: 首页 > news >正文

异步FIFO设计详解

目录

一、FIFO介绍

二、FIFO的“空”/“满”检测

 三、同步化分析

四、异步FIFO设计与结构


一、FIFO介绍

FIFO存储器概念介绍_的博客-CSDN博客

二、FIFO的“空”/“满”检测

FIFO设计的关键:产生可靠的FIFO读写指针和生成FIFO“空”/“满”状态标志。

当读写指针相等时,表明FIFO为空,这种情况发生在复位操作时,或者当读指针读出FIFO中最后一个字后,追赶上了写指针时,如下图所示:

当读写指针再次相等时,表明FIFO为满,这种情况发生在,当写指针转了一圈,折回来(wrapped around)又追上了读指针,如下图:

为了区分到底是满状态还是空状态,可以采用以下方法:

方法1在指针中添加一个额外的位(extra bit)

当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零。对读指针也进行同样的操作。此时,对于深度为2的n次方的FIFO,需要的读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000~1000、1001~1111,MSB作为折回标志位,而低3位作为地址指针。

        如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。
        如果两个指针的MSB相同,则说明两个指针折回的次数相等,其余位也相等,即两个指针相等说明FIFO为空;

这个办法主要用于同步FIFO判断空满

将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测。

方法2使用gray码进行对比,如何判断“空”与“满”

使用gray码解决了一个问题,但同时也带来另一个问题,即在格雷码域如何判断空与满。

对于“空”的判断依然依据二者完全相等(包括MSB);

而对于“满”的判断,如下图,由于gray码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,除了MSB,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在gray码上判断为满必须同时满足以下3条:

  • wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次。
  • wptr与rptr的次高位不相等,如上图位置7和位置15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。
  •  剩下的其余位完全相等

 三、同步化分析

由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题,如何解决?
跨时钟域的问题:由于读指针是属于读时钟域的,写指针是属于写时钟域的,而异步FIFO的读写时钟域不同,是异步的,要是将读时钟域的读指针与写时钟域的写指针不做任何处理直接比较肯定是错误的,因此我们需要进行同步处理以后仔进行比较
解决方法: 加两级寄存器同步 + 格雷码(目的都是消除亚稳态)
 
1.使用异步信号进行使用的时候,好的设计都会对异步信号进行同步处理,同步一般采用多级D触发器级联处理,如下图。这种模型大部分资料都说的是第一级寄存器产生亚稳态后,第二级寄存器稳定输出概率为90%,第三极寄存器稳定输出的概率为99%,如果亚稳态跟随电路一直传递下去,那就会另自我修护能力较弱的系统直接崩溃

2.将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测。
那么,多位二进制码如何转化为格雷码?

verilog代码实现就一句:assign  gray_code = (bin_code>>1)  ^  bin_code;

顺便提一下,多位格雷码如何转化为二进制码

格雷码域如何判断空与满?前面已经讨论过,简单来说就是:

读空时:需要读时钟域的格雷码rgray_next和被同步到读时钟域的写指针rd2_wp每一位完全相同;

写满时:需要写时钟域的格雷码wgray_next和被同步到写时钟域的读指针wr2_rp高两位不相同,其余各位完全相同;

assign full = (wr_addr_gray == {~(rd_addr_gray_d2[addr_width-:2]),rd_addr_gray_d2[addr_width-2:0]}) ;//高两位不同

assign empty = ( rd_addr_gray == wr_addr_gray_d2 );

四、异步FIFO设计与结构

  • 总体结构

  • 设计代码
module asyn_fifo #(parameter DATA_WIDTH  =  4'd8;parameter DATA_DEPTH  =  5'd16;parameter ADDR_WIDTH  =  4'd4;
)(input      [DATA_WIDTH-1:0]   data_in;input                         wr_clk;input                         rst_n;input                         wr_en;output                        full;input                         rd_clk;input                         rd_en;output reg [DATA_WIDTH-1:0]   data_out;output                        empty
);wire [ADDR_WIDTH - 1'd1 : 0]   wr_addr;reg  [ADDR_WIDTH        : 0]   wr_ptr;wire [ADDR_WIDTH        : 0]   wr_gray;reg  [ADDR_WIDTH        : 0]   wr_gray_d1;reg  [ADDR_WIDTH        : 0]   wr_gray_d2;wire [ADDR_WIDTH - 1'd1 : 0]   rd_addr;reg  [ADDR_WIDTH        : 0]   rd_ptr;wire [ADDR_WIDTH        : 0]   rd_gray;reg  [ADDR_WIDTH        : 0]   rd_gray_d1;reg  [ADDR_WIDTH        : 0]   rd_gray_d2;reg  [DATA_WIDTH - 1'd1 : 0]    fifo_ram [DATA_DEPTH - 1'd1 : 0];assign  wr_addr = wr_ptr[data_addr - 1'd1 : 0];assign  rd_addr = rd_ptr[data_addr - 1'd1 : 0];//写指针always @(posedge wr_clk or negedge rst_n )beginif (!rst_n)wr_ptr <= 'd0;else if ( (wr_en) && (!full) )wr_ptr <= 'd1 + wr_ptr;elsewr_ptr <= wr_ptr;end//读指针always @(posedge rd_clk or negedge rst_n )beginif (!rst_n)rd_ptr <= 'd0;else if ( (rd_en) && (!empty) )rd_ptr <= 'd1 + rd_ptr;elserd_ptr <= rd_ptr;end//---------------------------------------------------------------assign wr_gray = (wr_ptr >> 1'd1) ^ wr_ptr;assign rd_gray = (rd_ptr >> 1'd1) ^ rd_ptr;always @(posedge rd_clk )beginwr_gray_d1 <= wr_gray;wr_gray_d2 <= wr_gray_d1;endalways @(posedge wr_clk )beginrd_gray_d1 <= rd_gray;rd_gray_d2 <= rd_gray_d1;end//------------------------------------------------------------------assign full  = (wr_gray == {~(rd_gray_d2[ADDR_WIDTH :ADDR_WIDTH-1 ]),rd_gray_d2[ADDR_WIDTH-2:0]});assign empty = (rd_gray == wr_gray_d2);//-------------------------------------------------------------write operationalways @(posedge wr_clk or negedge rst_n)beginif(!rst_n)beginfifo_ram [wr_addr] <= 'h0;endelse if ( (wr_en) && (!full) )fifo_ram[wr_addr] <= data_in;else  fifo_ram[wr_addr] <= fifo_ram[wr_addr];end//--------------------------------------------------------------read operationalways @(posedge rd_clk or negedge rst_n)beginif(!rst_n)data_out <= 'h0;else if( (rd_en) && (!empty) )data_out <= fifo_ram[rd_addr];else  data_out <= data_out;endendmodule
  •  测试代码
module asyn_fifo_tb;parameter DATA_W           =   8      ;
parameter ADDR_W           =   4      ;
parameter data_hight       =   16     ;reg                        wr_clk     ;
reg                        rd_clk     ;
reg                        rst_n      ;
reg                        wr_en      ;
reg    [DATA_W-1:0]        wr_data    ;
reg                        rd_en      ; wire   [DATA_W-1:0]        rd_data    ;
wire                       empty      ;
wire                       full       ;asyn_fifo u_FIFO_asyn 
(.data_out           (rd_data),           .data_in            (wr_data),.wr_clk             (wr_clk) ,.rst_n              (rst_n)  ,.full               (full)   ,.empty              (empty)  ,.rd_clk             (rd_clk) ,.rd_en              (rd_en)  ,.wr_en              (wr_en)  
);always #10 wr_clk = ~wr_clk;
always #5  rd_clk = ~rd_clk;initial beginwr_clk    = 1;rd_clk    = 0;rst_n     = 0;wr_en     = 0;wr_data   = 0;rd_en     = 0;#101;rst_n = 1;#20;gen_data;@(posedge rd_clk);rd_en=1;#1000 $finish;endtask gen_data;integer i;beginfor(i=0;i<15;i=i+1)beginwr_en      =  1;wr_data    =  i;#20;endwr_en   = 0;wr_data = 0;endendtask/*initial begin`ifdef DUMP_VPD$vcdpluson();`endifend*/initial begin $fsdbDumpfile("asy_fifo.fsdb");$fsdbDumpvars(0);endendmodule			

 理论参考:

Clifford E. Cummings《Simulation and Synthesis Techniques for Asynchronous FIFO Design》

https://blog.csdn.net/alangaixiaoxiao/article/details/81432144

http://www.xdnf.cn/news/832663.html

相关文章:

  • 【Xilinx Vivado时序分析/约束系列7】FPGA开发时序分析/约束-FPGA单沿采样数据input delay时序约束实操
  • 网络IP地址冲突故障,快速解决方案(非常详细)零基础入门到精通,收藏这一篇就够了_内网总提示有ip冲突
  • LDAP 是个啥你知道吗?
  • 面试常问-Alpha测试和Beta测试
  • 距离保护原理
  • TCP的核心系列 — SACK和DSACK的实现(一)
  • BigDecimal中divide方法与setScale方法详解
  • 详解a标签中href=javascript的几种用法
  • C语言scanf函数详解..
  • 【数据结构】树(四)—— 线索二叉树(C语言版)
  • 系统缺失GdiPlus.dll文件导致出现系统异常的解决办法
  • 影音先锋 android下载地址,影音先锋安卓版下载
  • leapftp怎么用,掌握leapftp的使用方法只需6步
  • MS17-010(永恒之蓝)漏洞分析与复现
  • Java Class 类文件格式看这一篇就够了
  • SEH异常处理学习总结
  • linux crw权限,linux中crw brw lrw等等文件属性是什么
  • input 的 disabled和readonly 及其 限制。
  • 长链接转短链接,短链接跳转对应页面
  • 什么是IT咨询?IT外包又是什么?
  • LIBSVM入门
  • 详解IP安全:IPSec协议簇 - AH协议 - ESP协议 - IKE协议
  • dhtml是基于html的一门语言,什么是DHTML
  • 【ISP】颜色的理解
  • Matlab中利用findpeaks找波峰和波谷
  • 招生|清华大学天基网络与通信全国重点实验室
  • 约束条件(constraint)
  • 基于javaweb+mysql的springboot物业管理系统(java+springboot+maven+ssm+thymeleaf+html+jquery+mysql)
  • win11检测工具在哪 win11检测工具位置介绍
  • c盘fakepath是什么意思_C盘越用越大?告诉你什么文件可以删!