异步FIFO

        FIFO 包括同步 FIFO 和异步 FIFO 两种,同步 FIFO 有一个时钟信号,读和写逻辑全部使用这一个时钟信号,异步 FIFO 有两个时钟信号,读和写逻辑用的各种的读写时钟,本节说的全部是异步 FIFO。

        异步 FIFO 有两个时钟信号,读和写接口分别采用不同时钟,这两个时钟可能时钟频率不同,也可能时钟相位不同,可能是同源时钟,也可能是不同源时钟。
        在现代逻辑设计中,随着设计规模的不断扩大,一个系统中往往含有数个时钟,多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步 FIFO 是这个问题的一种简便、快捷的解决方案,使用异步 FIFO 可以在两个不同时钟系统之间快速而方便地传输实时数据。

        一般异步 FIFO 的地址传递需要使用格雷码,每次地址变化格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到 gray 码的转换电路,将地址值转换为相应的 gray 码,然后将该 gray 码同步到另一个时钟域进行对比,作为空满状态的检测。

异步FIFO

         使用 gray 码解决了指针采样错误的问题,但同时也带来另一个问题,即在格雷码域如何判断空与满。
        对于“空”的判断依然依据二者完全相等(包括 MSB);
        而对于“满”的判断,如下图,由于 gray 码除了 MSB 外,具有镜像对称的特点,当读指针指向 7,写指针指向 8 时,除了 MSB,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在 gray 码上判断为满必须同时满足以下 3 条:
       (1)wptr 和同步过来的 rptr 的 MSB 不相等,因为 wptr 必须比 rptr 多折回一次。
       (2 )wptr 与 rptr 的次高位不相等,如下图位置 7 和位置 15,转化为二进制对应的是 0111 和 1111,MSB不同说明多折回一次,111 相同代表同一位置。
       (3)剩下的其余位完全相等。

异步FIFO

 异步FIFO空满状态

异步FIFO

 异步 FIFO 系统框图

 顶层程序:

`timescale 1ns / 1ps

module shousififo_top
#( parameter ASIZE=4,  //地址位宽
   parameter DSIZE=8   //数据位宽
)
(
input [DSIZE-1:0] wdata,
input             winc,wclk,wrst_n,//写请求信号、写时钟、写复位
input             rinc,rclk,rrst_n,
output[DSIZE-1:0] rdata,
output            wfull,
output            rempty
);
wire [ASIZE-1:0] waddr;
wire [ASIZE-1:0] raddr;
wire  [ASIZE:0]  wptr;
wire  [ASIZE:0]  rptr;
wire  [ASIZE:0]  wq2_rptr;
wire  [ASIZE:0]  rq2_wptr;

sync_r2w I1_sync_r2w(
 .wq2_rptr (wq2_rptr),
 .rptr     (rptr    ),
 .wclk     (wclk    ),
 .wrst_n   (wrst_n  )
);

sync_w2r  I2_sync_w2r(
.rq2_wptr(rq2_wptr),
.wptr    (wptr    ),
.rclk    (rclk    ),
.rrst_n  (rrst_n  )
);
DualRAM #(DSIZE,ASIZE)I3_DualRAM(
.raddr (raddr)  ,
.waddr (waddr)  ,
.wdata (wdata)  ,
.rdata (rdata)  ,
.wclken(winc) ,
.wclk  (wclk)
);

rptr_empty #(ASIZE) I4_rptr_empty(
 .rempty   (rempty  )       ,    
 .radddr   (radddr  )       ,
 .rptr     (rptr    )       ,
 .rq2_wptr (rq2_wptr)       ,
 .rinc     (rinc    )       ,
 .rclk     (rclk    )       ,
 .rrst_n   (rrst_n  )
);

wptr_full#(ASIZE) I5_wptr_full(
. wfull     (wfull    ),             
. waddr     (waddr    ),             
. wptr      (wptr     ),              
. wq2_rptr  (wq2_rptr ),         
. winc      (winc     ),
. wclk      (wclk     ),
. wrst_n    (wrst_n   )

);

endmodule

 读到写的同步:

`timescale 1ns / 1ps

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

写到读的同步:

`timescale 1ns / 1ps

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

 双端口ram:

`timescale 1ns / 1ps

module DualRAM
#(parameter   DATA_SIZE=8,//数据位宽
  parameter   ADDR_SIZE=4//地址位宽
)
(
 input            wclken,wclk,
 input [ADDR_SIZE-1:0] raddr,    //ram读地址
 input [ADDR_SIZE-1:0] waddr,    //ram写地址
 input [DATA_SIZE-1:0] wdata,    //数据输入
 input [DATA_SIZE-1:0] rdata     //数据输出

    );
localparam RAM_DEPTH=1<<ADDR_SIZE;   
 reg  [DATA_SIZE-1:0] Men [RAM_DEPTH-1:0];  //ram的深度=2^ADDR_SIZE
 
 always@(posedge wclk)begin
    if (wclken)
    Men[waddr]<=wdata;
    end

assign rdata=Men[raddr];

endmodule

读空:

`timescale 1ns / 1ps

module rptr_empty
#(parameter ADDRSIZE=4  
)
(
output reg                    rempty   ,
output        [ADDRSIZE-1:0]  radddr   ,
output  reg   [ADDRSIZE:0]    rptr     ,
input          [ADDRSIZE:0]   rq2_wptr  ,
input                         rinc,rclk,rrst_n );                                                                                                                       
reg  [ADDRSIZE:0]  rbin;
wire  [ADDRSIZE:0]  rgraynext,rbinnnext;
wire  rempty_val;

always@(posedge rclk or negedge rrst_n)begin
  if (!rrst_n)begin
    rbin<=0;
    rptr<=0;
  end
  else begin
     rbin<=rbinnnext;
     rptr<=rgraynext;
  end
 end
  
 //gray码计数逻辑
 assign rbinnnext=!rempty?(rbin+rinc):rbin;
 assign rgraynext=(rbinnnext>>1)^rbinnnext;
 assign radddr=rbin[ADDRSIZE-1:0];
 
 assign rempty_val=(rgraynext==rq2_wptr);
 
 always@(posedge rclk or negedge rrst_n)
       if (!rrst_n)
            rempty<=1'b1;
       else
            rempty<=rempty_val;
 
endmodule

 写满:

`timescale 1ns / 1ps

module wptr_full
#(
  parameter ADDRSIZE=4
)
(
  output reg                 wfull,
  output  [ADDRSIZE-1:0]     waddr,
  output  reg [ADDRSIZE-1:0] wptr,
  input   [ADDRSIZE:0]        wq2_rptr,
  input                        winc,wclk,wrst_n  );
  
 reg[ADDRSIZE:0] wbin;
 wire [ADDRSIZE:0]wgraynext,wbinnext;
 wire wfull_val;
 
 always@(posedge wclk or negedge wrst_n)begin
     if (!wrst_n)begin
        wbin<=0;
        wptr<=0;
     end
     else begin
        wbin<=wbinnext;
        wptr<=wgraynext;
 end
 end
 
 assign wbinnext=!wfull?wbin+winc:wbin;
 assign wgraynext=(wbinnext>>1)^wbinnext;
 assign waddr=wbin[ADDRSIZE-1:0];
 
 assign wfull_val=(wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],wq2_rptr[ADDRSIZE-2:0]});
 always@(posedge wclk or negedge wrst_n)begin
    if(!wrst_n)
      wfull<=1'b0;
    else
      wfull<=wfull_val;
  end
  
endmodule
异步FIFO

 

上一篇:磁盘I/O流程的场景分类和linux系统中的I/O调度策略


下一篇:队列的定义和特点