zoukankan      html  css  js  c++  java
  • Verilog实现之异步fifo

      上节课我们介绍了,同步fifo,感觉就是在双口异步RAM中进行了一些简单的外围操作,加了一些空满标志,内部用指针来进行寻址,从而取消了外部的地址接口。FIFO的一侧是读。一侧是写。所以具有了''wr_en"和"rd_en",一边是写数据,一边是读数据,所以就有了“wr_data”和“rd_data”,写会写满,读会读空所以具有了“empty”和“full”标志位。同步的fifo就是这么点东西。那么对于异步fifo 又该怎么样呢?

      一、分析异步FIFO

      由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题。此处的跨时钟主要是读指针属于读时终域的,写指针属于写时钟域的。而异步FIFO的读写时钟是不同的。这种异步情况就会导致我们在处理空满标志的时候出现错误的判断。所以必须对其进行同步化处理后在进行空满标志的判断。同步化解决的方案是:加两级寄存器同步 + 格雷码(目的都是消除亚稳态)

       1、加寄存器法

      使用异步信号进行使用的时候,好的设计都会对异步信号进行同步处理,同步一般采用多级D触发器级联处理,如上图。这种模型大部分资料都说的是第一级寄存器产生亚稳态后,第二级寄存器稳定输出概率为90%,第三极寄存器稳定输出的概率为99%,如果亚稳态跟随电路一直传递下去,那就会另自我修护能力较弱的系统直接溃。转化为代码:

     1 // 加两级寄存器同步
     2 always @( sclk_rd )begin
     3     if(!rd_rst)begin
     4         wr_ptr_gray_d1     <=   0;
     5         wr_ptr_gray_d2     <=   0;
     6     end
     7     else begin
     8         wr_ptr_gray_d1     <=   wr_ptr_gray     ;
     9         wr_ptr_gray_d2     <=   wr_ptr_gray_d1  ;
    10     end
    11 end
    12 
    13 always @( sclk_wr )begin
    14     if(!wr_rst)begin
    15         rd_ptr_gray_d1     <=   0  ;
    16         rd_ptr_gray_d2     <=   0  ;
    17     end
    18     else begin
    19         rd_ptr_gray_d1     <=  rd_ptr_gray   ;
    20         rd_ptr_gray_d2     <=  rd_ptr_gray_d1;
    21     end
    22 end

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

     1 assign wr_ptr_gray = wr_pointer ^(wr_pointer>>>1); 2 assign rd_ptr_gray = rd_pointer ^(rd_pointer>>>1); 二进制转换为格雷码。

      3、在格雷码的域进行空满标志的判断

      同步FIFO可以使用计数方式来判断空满,但是异步FIFO不能,因为写指针和读指针根本不在同一个时钟域,计数器无法处理这样的计数。那么如何对独处的数据和写入的数据进行判断。并给出空满标志呢?解决方案:对读写指针的位宽多添1位,这样可以在读写指针相等时,表示FIFO空,而在写指针和读指针最高位不同,而其他位相等时,也即写指针大于读指针一个FIFO深度的数值,表示FIFO满,这不就是意味着写指针绕了一圈,又追上了读指针了吗?恰是如此,用来解决不用计数而具体判断FIFO空满的问题。  

     1 //full
     2 always @(posedge sclk_wr)begin
     3     if(!wr_rst)begin
     4         full      <=    1'b0 ;
     5     end
     6     else if((rd_ptr_gray_d2[$clog2(DATA_DEPTH)-1:0]==wr_ptr_gray[$clog2(DATA_DEPTH)-1:0])
     7             && (rd_ptr_gray_d2[$clog2(DATA_DEPTH)]!=wr_ptr_gray[$clog2(DATA_DEPTH)]))begin
     8         full      <=    1'b1 ;
     9     end
    10     else 
    11         full      <=    1'b0 ;
    12 end
    13 //empty
    14 always @(posedge sclk_rd)begin
    15     if(!rd_rst)begin
    16         empty     <=     1'b0 ;
    17     end
    18     else if(rd_ptr_gray==wr_ptr_gray_d2)begin
    19         empty     <=     1'b1 ;
    20     end
    21     else 
    22         empty     <=     1'b0 ;
    23 end

      二、Verilog实现如下

      1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      2 // Project Name : 
      3 // Website      : https://home.cnblogs.com/lgy-gdeu/
      4 // Author         : LGY GUET Uiversity
      5 // Weixin         : li15226499835
      6 // Email          : 15277385992@163.com
      7 // File           : 
      8 // Create         : 2020
      9 // Revise         : 
     10 // Editor         : sublime text{SUBLIME_VERSION}, tab size ({TABS})
     11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     12 // Modification History:
     13 // Date             By              Version                 Change Description
     14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     15 // {DATE} {TIME}    LGY           1.0                        ++++++++++++++++ 
     16 // *********************************************************************************
     17 `timescale      1ns/1ns
     18 module asyn_fifo #(
     19 parameter      DATA_WIDTH = 8,
     20 parameter       DATA_DEPTH = 32   
     21     )
     22 
     23 (    
     24     input            wire                      sclk_wr        , 
     25     input            wire                    wr_rst         ,
     26     input             wire                    wr_en       ,
     27     input           wire[DATA_WIDTH-1:0]    wr_data     ,    
     28     output          reg                     full        ,
     29     input           wire                    sclk_rd       ,
     30     input           wire                    rd_en       ,
     31     input           wire                    rd_rst      ,
     32     output          reg [DATA_WIDTH-1:0]    rd_data     ,
     33     output          reg                     empty
     34 );
     35 
     36 //========================================================================
     37 // ################ Define Parameter and Internal signals ################ 
     38 //========================================================================/
     39 reg       [DATA_DEPTH-1:0]            fifo_buffer [0:DATA_WIDTH-1] ;//space 
     40 reg       [$clog2(DATA_DEPTH):0]    wr_pointer                    ;//zhi zheng
     41 reg          [$clog2(DATA_DEPTH):0]    rd_pointer                    ;
     42 wire      [$clog2(DATA_DEPTH):0]    wr_ptr_gray                   ;//geleijishu
     43 wire      [$clog2(DATA_DEPTH):0]    rd_ptr_gray                   ;
     44 reg       [$clog2(DATA_DEPTH):0]    wr_ptr_gray_d1               ;
     45 reg       [$clog2(DATA_DEPTH):0]    wr_ptr_gray_d2               ;
     46 reg       [$clog2(DATA_DEPTH):0]    rd_ptr_gray_d1               ;
     47 reg       [$clog2(DATA_DEPTH):0]    rd_ptr_gray_d2               ;        
     48 //=============================================================================
     49 //+++++++++++++++++++++++++     Main Code    +++++++++++++++++++++++++++++++
     50 //=============================================================================
     51 //wr_pointer
     52 always @(posedge sclk_wr)begin
     53     if(!wr_rst)begin
     54         wr_pointer     <=   0 ;
     55     end
     56     else if(wr_en)begin
     57         wr_pointer     <=  wr_pointer + 1'b1 ;
     58         fifo_buffer[wr_pointer] <= wr_data   ;
     59     end
     60 end
     61 
     62 //rd_pointer
     63 always @(posedge sclk_rd )begin
     64     if(!rd_rst)begin
     65         rd_pointer     <=    0 ;
     66     end
     67     else if(rd_en)begin
     68         rd_pointer     <= rd_pointer+ 1'b1;
     69         rd_data        <= fifo_buffer[rd_pointer];
     70     end
     71 
     72 end
     73 //wr_ptr_gray,rd_ptr_gray
     74 assign        wr_ptr_gray  =  wr_pointer ^(wr_pointer>>>1);
     75 assign        rd_ptr_gray  =  rd_pointer ^(rd_pointer>>>1);
     76 
     77 // 加两级寄存器同步
     78 always @( sclk_rd )begin
     79     if(!rd_rst)begin
     80         wr_ptr_gray_d1     <=   0;
     81         wr_ptr_gray_d2     <=   0;
     82     end
     83     else begin
     84         wr_ptr_gray_d1     <=   wr_ptr_gray     ;
     85         wr_ptr_gray_d2     <=   wr_ptr_gray_d1  ;
     86     end
     87 end
     88 
     89 always @( sclk_wr )begin
     90     if(!wr_rst)begin
     91         rd_ptr_gray_d1     <=   0  ;
     92         rd_ptr_gray_d2     <=   0  ;
     93     end
     94     else begin
     95         rd_ptr_gray_d1     <=  rd_ptr_gray   ;
     96         rd_ptr_gray_d2     <=  rd_ptr_gray_d1;
     97     end
     98 end
     99 
    100 //full
    101 always @(posedge sclk_wr)begin
    102     if(!wr_rst)begin
    103         full      <=    1'b0 ;
    104     end
    105     else if((rd_ptr_gray_d2[$clog2(DATA_DEPTH)-1:0]==wr_ptr_gray[$clog2(DATA_DEPTH)-1:0])
    106             && (rd_ptr_gray_d2[$clog2(DATA_DEPTH)]!=wr_ptr_gray[$clog2(DATA_DEPTH)]))begin
    107         full      <=    1'b1 ;
    108     end
    109     else 
    110         full      <=    1'b0 ;
    111 end
    112 //empty
    113 always @(posedge sclk_rd)begin
    114     if(!rd_rst)begin
    115         empty     <=     1'b0 ;
    116     end
    117     else if(rd_ptr_gray==wr_ptr_gray_d2)begin
    118         empty     <=     1'b1 ;
    119     end
    120     else 
    121         empty     <=     1'b0 ;
    122 end
    123 
    124 
    125     
    126 endmodule

    tb测试代码:

      1 `timescale 1ns / 1ps
      2 //////////////////////////////////////////////////////////////////////////////////
      3 // Company: 
      4 // Engineer: 
      5 // 
      6 // Create Date: 2020/06/27 22:23:25
      7 // Design Name: 
      8 // Module Name: asyn_fifo_tb
      9 // Project Name: 
     10 // Target Devices: 
     11 // Tool Versions: 
     12 // Description: 
     13 // 
     14 // Dependencies: 
     15 // 
     16 // Revision:
     17 // Revision 0.01 - File Created
     18 // Additional Comments:
     19 // 
     20 //////////////////////////////////////////////////////////////////////////////////
     21 
     22 
     23 module asyn_fifo_tb();
     24 parameter DATA_WIDTH = 8;
     25 
     26 parameter DATA_DEPTH = 16;
     27 
     28     reg wr_clk;
     29     reg wr_rst;
     30     reg wr_en;
     31     reg [DATA_WIDTH - 1 : 0] wr_data;
     32     wire full;
     33 
     34     reg rd_clk;
     35     reg rd_rst;
     36     reg rd_en;
     37     wire [DATA_WIDTH - 1 : 0] rd_data;
     38     wire empty;
     39 
     40     initial begin
     41         wr_clk = 0;
     42         forever begin
     43             #5 wr_clk = ~wr_clk;
     44         end
     45     end
     46 
     47     initial begin
     48         rd_clk = 0;
     49         forever begin
     50             #10 rd_clk = ~rd_clk;
     51         end
     52     end
     53 
     54     initial begin
     55         wr_rst = 0;
     56         rd_rst = 0;
     57         wr_en = 0;
     58         rd_en = 0;
     59         #30 
     60         wr_rst = 1;
     61         rd_rst = 1;
     62 
     63         //write data into fifo buffer
     64         @(negedge wr_clk) 
     65         wr_data = $random;
     66         wr_en = 1;
     67 
     68         repeat(7) begin
     69             @(negedge wr_clk) 
     70             wr_data = $random; // write into fifo 8 datas in all;
     71         end
     72 
     73         // read parts
     74         @(negedge wr_clk) 
     75         wr_en = 0;
     76 
     77         @(negedge rd_clk) 
     78         rd_en = 1;
     79 
     80         repeat(7) begin
     81             @(negedge rd_clk);  // read empty 
     82         end 
     83         @(negedge rd_clk)
     84         rd_en = 0;
     85 
     86         //write full
     87         # 150
     88 
     89         @(negedge wr_clk)
     90         wr_en = 1;
     91         wr_data = $random;
     92 
     93         repeat(15) begin
     94         @(negedge wr_clk)
     95             wr_data = $random;
     96         end
     97 
     98         @(negedge wr_clk)
     99         wr_en = 0;
    100 
    101 
    102         #50 $finish;
    103 end
    104 
    105 asyn_fifo #(
    106         .DATA_WIDTH(DATA_WIDTH),
    107         .DATA_DEPTH(DATA_DEPTH)
    108     )asyn_fifo_inst (
    109         .sclk_wr (wr_clk),
    110         .wr_rst  (wr_rst),
    111         .wr_en   (wr_en),
    112         .wr_data (wr_data),
    113         .full    (full),
    114         .sclk_rd (rd_clk),
    115         .rd_en   (rd_en),
    116         .rd_rst  (rd_rst),
    117         .rd_data (rd_data),
    118         .empty   (empty)
    119     );
    120 endmodule 
    View Code

      1、系统函数$clog2();求对数函数。使用方法很简单,主要求指针的位宽来使用。例如:

     1 parameter DATA_WIDTH = 8;
     2 parameter DATA_DEPTH = 8;
     3 
     4 reg [DATA_WIDTH - 1 : 0] fifo_buffer[0 : DATA_DEPTH - 1];
     5 
     6 reg [$clog2(DATA_DEPTH) - 1 : 0] wr_pointer = 0;
     7 reg [$clog2(DATA_DEPTH) - 1 : 0] rd_pointer = 0;
     8 
     9 $clog2(DATA_DEPTH)                  // = 3;
    10 
    11 reg [$clog2(DATA_DEPTH) - 1 : 0] wr_pointer = 0;
    12 reg [$clog2(DATA_DEPTH) - 1 : 0] rd_pointer = 0;

      2综合属性控制资源使用

     1 (*ram_style = "distributed"*) reg [DATA_WIDTH - 1 : 0] fifo_buffer[0 : DATA_DEPTH - 1]; 则使用分布式ram来搭建存储空间。

     1 (*ram_style = "block"*) reg [DATA_WIDTH - 1 : 0] fifo_buffer[0 : DATA_DEPTH - 1]; 则使用块ram来搭建存储空间。

       三、参考文献

      1、https://www.cnblogs.com/ylsm-kb/p/9068449.html 

      2、https://so.csdn.net/so/search/s.do?q=%E5%BC%82%E6%AD%A5FIFO&t=blog&u=Reborn_Lee

      

      

  • 相关阅读:
    FineUIPro v5.1.0 发布了!
    FineUI十周年纪念版即将发布(基于像素的响应式布局,独此一家)!
    FineUIPro/Mvc/Core/JS v4.2.0 发布了(老牌ASP.NET控件库,WebForms,ASP.NET MVC,Core,JavaScript)!
    选择IT公司的雇主提问
    项目管理趋势
    突发事件下的项目管理
    12-Factor与微服务
    CQRS(Command and Query Responsibility Segregation)与EventSources实例
    阅读理解力的四个层次
    2018年Code Review状态报告
  • 原文地址:https://www.cnblogs.com/lgy-gdeu/p/13201486.html
Copyright © 2011-2022 走看看