IC学习笔记3——异步FIFO

IC学习笔记3——异步FIFO

异步FIFO的工作内容与同步FIFO类似,但是异步FIFO的控制并不像同步FIFO那么简单,因为异步FIFO工作在不同的时钟域,这将会带来一些问题,比如空满检测?是否还可以像同步FIFO通过计数器来判断?是否需要同步电路?这些问题将会在本章节一一讨论。

一、异步FIFO的空满检测

1. 同步FIFO的空满检测

因为同步FIFO工作在一个时钟域,可以通过一个计数器来判断空满。
当同步FIFO写入一次数据,计数器加1.
当同步FIFO读出一次数据,计数器减1.
当同步FIFO同时进行一次读写操作,计数器的值不变。
这时就可以通过计数器的值来判断空满,当计数器的值为0,则表示同步FIFO中没有可读的数据,此时同步FIFO为空。
当计数器的值等于同步FIFO的深度时,则表示同步FIFO中已经写满了。

2. 异步FIFO的空满检测

2.1 计数器检测空满

异步FIFO是否可以通过同步FIFO这种计数器的方式实现空满检测。假如可以,那么在异步FIFO中对计数器的描述
always@(posedge wclk or posedge rclk),这种代码综合过程中是没有实际的触发器与之对应的。
实际的触发器只有两种,一种是是对一个时钟边沿敏感—>always@(posedge clk)。另一种是除了对一个时钟边沿敏感,还有一个异步复位端—>always@(posedge clk or negedge rst_n)

2.2 指针比较检测空满

可以通过比较写指针和读指针来判断空满,如下图所示,先对异步FIFO写入数据1,写两次,然后对异步FIFO读两次,把之前写进去的数据1都读出来,已经没有数据可读,所以此时异步FIFO处于空状态。注意此时写指针和读指针相等,都是指向地址为2的存储空间。
然后对异步FIFO写数据0,写6次,此时写指针重新指向地址0所对应的存储空间,此时的状态不是满状态,因为之前写入两次数据1已经被读出,此时地址0和地址1还是可以写入数据的,再对异步FIFO写数据0,写两次,此时异步FIFO中所有的存储空间都写入数据,并且没有一个数据是被读出过的,所以此时是满状态,此时也是写指针和读指针相等。

所以可以总结当读指针追上写指针时,异步FIFO处于空状态。
写指针追上读指针时,异步FIFO处于满状态。但是这种方法处理后,仍然有一个问题就是读写指针相等时,难以区分是空状态还是满状态。
IC学习笔记3——异步FIFO_第1张图片

2.3 扩展指针比较检测空满

针对上面指针比较空满出现的问题,有人提出,对指针最高位进行扩展,即指针加宽一位,当写指针超出FIFO深度时,这额外的一位就会发生改变。FIFO的深度决定了指针扩展前的宽度,而这扩展的一位与FIFO深度无关,是为了标志指针多转了一圈。
因此,当读写指针完全相同时,此时FIFO为空状态。
当读写指针最高位不同,其余位宽相同时,FIFO为满状态。
用扩展指针的方式分析上面的例子,如下图所示,空状态时,rptr=0010,wptr=0010,读写指针完全相同,为空状态。
满状态时,rptr=0010,wptr=1010,读写指针最高位不同,其余位宽相同,为满状态。
IC学习笔记3——异步FIFO_第2张图片
经过指针扩展,可以进行空满检测。但是异步FIFO读写时钟不同,而读写指针又是分属各自的时钟域,在进行空满检测的时候,是需要将读写指针进行跨时钟域处理的。
使用二进制的方式很容易出现错误,在跨时钟域的时候,相邻二进制地址变化时,不止一位发生变化。比如写指针从0111到1000跳变时,4位地址都可以发生改变,这样读时钟在进行写指针同步后得到的写指针可能是0000~1111中任意一个值,这些都是不可控的,出错的概率非常大。

2.4 格雷码指针比较检测空满

直接扩展读写指针可能因为多位改变导致错误。因此采用格雷码的方式,利用格雷码每次只变化一位的特征,降低同步发生错误的概率。如下图所示,其中0~7为真实的FIFO地址,而8-15是指针多转一圈以后的地址,实际对应还是0-7对应的存储空间。此时应该注意,此时是按照格雷码方式编码,不能再用二进制的方式来判断空满。比如说位置6(0101)和位置9(1101),除最高位不同,其余位相同,应该是满状态,但是位置6(0101)对应的满状态应是14(1001)。

因此格雷码的检测标准为:
当最高位和次高位均相同,其余为相同,FIFO空
当最高位和次高位均相反,其余为相同,FIFO满

所以异步FIFO最终的空满检测方式为:将二进制指针转换为格雷码,用于另一时钟域接收,随后按照检测条件进行检测。
IC学习笔记3——异步FIFO_第3张图片

二、异步FIFO的模块端口和内部电路图

2.1 异步FIFO的模块端口

IC学习笔记3——异步FIFO_第4张图片
异步FIFO相比较同步FIFO外部端口引脚类似。
wclk为写时钟,rclk为读时钟。
wrst_n为写复位信号,rrst_n为读复位信号。
winc为写使能信号,rinc为读使能信号。
wdata[7:0]为输入数据。
rdata[7:0]为输出数据。
wfull为写满信号。
rempty为读空信号。

2.2 异步FIFO的内部电路

IC学习笔记3——异步FIFO_第5张图片
异步FIFO的内部电路主要分为5个部分,会在下面部分一一详细介绍。在这里主要介绍一下内部的信号。
wptr为写指针,写指针的位数比写地址多一位。
rptr为读指针,读指针的位数比读地址多一位。
waddr为写地址,为具体把数据写入FIFO_Memory的地址。
raddr为读地址,为具体读出FIFO_Memory中数据的地址。
wq2_rptr为将读指针同步到写时钟域的信号。
rq2_wptr为将写指针同步到读时钟域的信号。

三、异步FIFO的电路设计

3.1 写指针&满信号&写地址

第一部分就是异步FIFO的写指针、满信号和写地址产生的电路设计,详细电路图如下所示。
IC学习笔记3——异步FIFO_第6张图片
代码如下:

     module wptr_wfull #(
                               parameter ADDRSIZE=4)
                       (  
                        input                                        winc,
                        input                                        wclk,
                        input                                        wrst_n,
                        input         [ADDRSIZE:0]                   wq2_rptr,
                        output reg                                   wfull,
                        output reg    [ADDRSIZE:0]                   wptr,
                        output        [ADDRSIZE-1:0]                 waddr
                        );
                        wire              full_value;
                        wire [ADDRSIZE:0] wbinnext , wgraynext;
                        reg  [ADDRSIZE:0] wbin;
              //写地址产生     
              assign wbinnext=wbin+(winc&!wfull);                                              
              always@(posedge wclk or negedge wrst_n)  
              begin
                       if(wrst_n==1’b0) 
                            wbin<=0;           
                       else
                           wbin<=wbinnext;        
              end
              assign waddr=wbin[ADDRSIZE-1:0];        
              
              //写指针产生    
              assign wgraynext=wbinnext^(wbinnext>>1);
              always @(posedge wclk or negedge wrst_n) 
              begin
                       if(wrst_n==1’b0)
                             wptr <=0;
                       else
                             wptr<=wgraynext;
              end
              
              //满信号产生
              assign  full_value=wgraynext == ({~wq2_rptr[ADDRSIZE:ADDRSIZE-1],wq2_rptr[ADDRSIZE-2:0]});
              always@(posedge wclk or negedge wrst_n)
              begin
                   if(wrst_n==1’b0)
                       wfull<=1’b0;
                  else
                      wfull<=full_value; 
             end
             endmodule

3.2 读指针&空信号&读地址

第二部分就是异步FIFO的读指针、空信号和读地址产生的电路设计,电路图如第一部分类似,因此不再具体介绍。
代码如下:

     module rptr_rempty #(
                               parameter ADDRSIZE=4)
                     (  
                        input                                        rinc,
                        input                                        rclk,
                        input                                        rrst_n,
                        input        [ADDRSIZE:0]                    rq2_wptr,
                        output reg                                   rempty,
                        output reg   [ADDRSIZE:0]                    rptr,
                        output       [ADDRSIZE-1:0]                  raddr
                        );
                       wire empty_value;
                       wire [ADDRSIZE:0] rbinnext , rgraynext;
                       reg  [ADDRSIZE:0] rbin;

                     //读地址产生     
                     assign rbinnext=rbin+(rinc&!rempty);
                     always@(posedge rclk or negedge rrst_n)                   
                     begin
                             if(rrst_n ==1’b0)                   
                                 rbin <=0;            
                             else
                                 rbin <=rbinnext;        
                     end
                     assign raddr=rbin[ADDRSIZE-1:0];

                   //读指针产生    
                     assign rgraynext=rbinnext^(rbinnext>>1);
                     always@(posedge rclk or negedge rrst_n)
                     begin
                             if(rrst_n ==1’b0)           
                                 rptr <=0; 
                             else
                                 rptr<=rgraynext;
                      end
              
                      //空信号产生
                      assign  empty_value=rgraynext == rq2_wptr;
                      always@(posedge rclk or negedge rrst_n)
                      begin
                            if(rrst_n==1’b0)
                               rempty<=1’b0;
                            else
                               rempty<=empty_value; 
                      end
                 endmodule

3.3 读指针同步

第三部分是读指针的同步,将读指针打两拍同步到写时钟域去,具体电路如下图所示。IC学习笔记3——异步FIFO_第7张图片
代码如下:

           module sync_r2w #(
                               parameter ADDRSIZE=4)
                             (  
                                   input                       wclk,
                                   input                       wrst_n,
                                   input       [ADDRSIZE:0]    rptr,
                                   output reg  [ADDRSIZE:0]    wq2_rptr
                       );
                       
           reg [ADDRSIZE:0] wq1_rptr;
           always@(posedge wclk or negedge wrst_n)
           begin
                if(wrst_n==1’b0)
                                  {wq2_rptr, wq1_rptr}<=2’b0;
                else
                                  {wq2_rptr, wq1_rptr}<= {wq1_rptr, rptr} ;       
            end
            endmodule

3.4 写指针同步

第四部分是写指针的同步,将写指针打两拍同步到读时钟域去,电路图如第三部分类似,不再具体介绍。
代码如下:

      module sync_w2r #(
                               parameter ADDRSIZE=4)
                     (  
                        input                                    rclk,
                        input                                    rrst_n,
                        input         [ADDRSIZE:0]               wptr,
                        output reg    [ADDRSIZE:0]               rq2_wptr
                       );
     reg [ADDRSIZE:0] rq1_wptr;
     always@(posedge rclk or negedge rrst_n)
     begin
          if(rrst_n==1’b0)
             {rq2_wptr, rq1_wptr}<=2’b0;
          else
             {rq2_wptr, rq1_wptr}<= {rq1_wptr, wptr};       
     end
     endmodule

3.5 数据读取

第五部分是数据的读取,具体电路如2.2异步电路中标记为5的部分所示。
代码如下:

         module fifomem #(
                               parameter ADDRSIZE=4,
                               parameter DATASIZE=8)
                     (
                        input                                   winc,
                        input                                   wclk,
                        input                                   wfull,
                        input   [ADDRSIZE-1:0]   waddr , raddr,
                        input   [DATASIZE-1:0]   wdata ,  
                        output  [DATASIZE-1:0]   rdata
                       );
                       localparam DEPTH=1<

3.6 整合

将上述5个部分整合在一起就形成一个完整的异步FIFO。

         module afifo #(
                        parameter ADDRSIZE=4,
                        parameter DATASIZE=8)
                       (
                          input   wclk,
                          input   rclk,

                          input   wrst_n,
                          input   rrst_n,

                          input   winc,
                          input   rinc,

                         input    [DATASIZE-1:0]  wdata,
                         
                         output   [DATASIZE-1:0]  rdata,
                         
                         output   rempty,
                         output   wfull
                        );
                wire [ ADDRSIZE:0] wq2_rptr;
                wire [ ADDRSIZE:0] wptr;
                wire [ ADDRSIZE-1:0] waddr;
                
                wire [ ADDRSIZE:0] rq2_wptr;
                wire [ ADDRSIZE:0] rptr;
                wire [ ADDRSIZE-1:0] raddr;
                
                 wptr_wfull u1(
                               .winc(winc),
                               .wclk(wclk),
                               .wrst_n(wrst_n),
                               .wq2_rptr(wq2_rptr),
                               .wfull(wfull),
                               .wptr(wptr),
                               .waddr(waddr)
                               );
                rptr_rempty u2(  
                               .rinc(rinc),
                               .rclk(rclk),
                               .rrst_n(rrst_n),
                               .rq2_wptr(rq2_wptr),
                               .rempty(rempty),
                               .rptr(rptr),
                               .raddr(raddr)
                        );
                  sync_r2w  u3(  
                                .wclk(wclk),
                                .wrst_n(wrst_n),
                                .rptr(rptr),
                                .wq2_rptr(wq2_rptr)
                       );
                  sync_w2r u4(
                                .rclk(rclk),
                                .rrst_n(rrst_n),
                                .wptr(wptr),
                                .rq2_wptr(rq2_wptr)
                       );
                  fifomem u5(
                                .winc(winc),
                                .wclk(wclk),
                                .wfull(wfull),
                                .waddr(waddr), 
                                .raddr(raddr),
                                .wdata(wdata),  
                                .rdata(rdata)
                       );
                  
          endmodule

四、仿真验证

4.1 仿真代码

  module afifo_tb();
  reg        wclk;
  reg        rclk;
  reg        wrst_n;
  reg        rrst_n;
  reg        winc;
  reg        rinc;
  reg  [7:0] wdata;
  wire [7:0] rdata;
  wire       rempty;
  wire       wfull;
  
              afifo u6(
                       .wclk(wclk),
                       .rclk(rclk), 
                       .wrst_n(wrst_n),
                       .rrst_n(rrst_n),
                       .winc(winc),
                       .rinc(rinc),
                       .wdata(wdata),
                       .rdata(rdata),
                       .rempty(rempty),
                       .wfull(wfull)
                       );
                       
          initial begin                    //设置写时钟,写周期是20ns,50Mhz
                             wclk=0;
                             forever    #10     wclk=~wclk;
                    end
                    
           initial begin                    //设置读时钟,读周期是10ns,100Mhz
                             rclk=0;
                             forever    #5      rclk=~rclk;
                    end
                    
           initial begin
                 
                           wrst_n=1'b0;     //写复位
                           rrst_n=1'b0;     //读复位
                            winc =1'b0;     //写无效
                            rinc =1'b0;     //读无效
                            wdata=0;        //初始写数据为0
                           
                    #28     wrst_n=1'b1;    //松开写复位
                               rrst_n=1'b1;    //松开读复位
                            winc =1'b1;     //写有效
                            wdata=1;        //输入数据为1
                            @(posedge wclk);//写入数据     

                            repeat(7)       //接着写入2,3,4,5,6,7,8这些数据
                                    begin
                                         #18;
                                         wdata=wdata+1'b1;
                                         @(posedge wclk);  
                                     end
                     #18    wdata=wdata+1'b1;  //此时异步FIFO已经写满了,在往同步FIFO中写数据8
                                     //8这个数据不会被写进
                            
                            @(posedge rclk);   
                                
                                #8      rinc=1’b1;      //读使能,写无效 
                                            winc=1'b0;
                                @(posedge rclk);     //第一个读出的数为1
                                repeat(7)        //读取剩余的数
                                   begin
                                       @(posedge rclk);   
                                   end
                                   #2;
                                     rinc=1‘b0;        //结束读操作
                                    
              end    
endmodule

4.2 仿真波形

IC学习笔记3——异步FIFO_第8张图片

你可能感兴趣的:(IC学习,学习,fpga开发)