一、异步FIFO与同步FIFO的区别
异步FIFO通常用于时钟域的过渡,是双时钟设计,即FIFO工作于独立的两个时钟之间,也就是读写时钟域不同。
二、难点及解决方法
一是如何同步异步信号以及处理亚稳态问题;针对这一难点,采用的是使用格雷码指针和二进制指针及握手信号。就是现将写指针同步到读时钟域,读指针同步到写时钟域,然后通过格雷码判断空满。
二是如何正确地设计空/满等信号的控制电路。针对这一难点,利用读写指针相互比较产生空/满标志,采用两种方法来辨别空/满两种状态:
一种是在读写地址前加一位附加位,通过附加位来辨别空/满状态;(本文使用该种方法,其实两种归根结底就是加一个标志)
另一种方法是通过划分地址空间来判断。
三、深度的计算
网上找的一个例子,一个8bit宽的AFIFO,输入时钟为100MHz,输出时钟为95MHz,设一个package为4Kbit,且两个package之间的发送间距足够大。问AFIFO的深度。
burst_length=4K/8=500
deep=500-500X95/100 =25
四、格雷码和二进制码之间的转换
1.gray to bin
always @ (gray)
for(i=0;i bin[i] = bin[i]^(gray>>i) 2.bin to gray assign gray = (bin>>1)^bin; 五、整体结构图(style #1 if you have saw SNUG user guide) Simulation and Synthesis Techniques for Asynchronous的网盘链接 链接:http://pan.baidu.com/s/1ntsqGjR 密码:scfz 五、Verilog关键代码 //top module asyn_fifo( wire [ASIZE-1:0] waddr, raddr; sync_r2w i_sync_r2w (.wq2_rptr(wq2_rptr), .rptr(rptr),.wclk(wclk), .wrst_n(wrst_n)); endmodule //read to write module sync_r2w reg [ADDRSIZE:0] wq1_rptr; always @(posedge wclk or negedge wrst_n) always @(posedge wclk or negedge wrst_n) endmodule //write full module wptr_full reg [ADDRSIZE:0] wbin; // GRAYSTYLE2 pointer endmodule module fifomem #(parameter DATASIZE = 8, // Memory data word width asign rdata = mem[raddr];
rdata, // Data path from FIFO
rempty, // Flag asserted high for empty stack
wfull , // Flag asserted high for full stack
wdata, // Data path into FIFO
winc,wclk,wrst_n,
rinc,rclk,rrst_n
);
parameter DSIZE = 8;
parameter ASIZE = 4;
output [DSIZE -1 : 0] rdata;
output rempty, wfull;
input [ASIZE -1 : 0] wdata;
input winc,wclk,wrst_n;
input rinc,rclk,rrst_n;
wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;
sync_w2r i_sync_w2r (.rq2_wptr(rq2_wptr), .wptr(wptr),.rclk(rclk), .rrst_n(rrst_n));
fifomem #(DSIZE, ASIZE) i_fifomem
(.rdata(rdata), .wdata(wdata),
.waddr(waddr), .raddr(raddr),
.wclken(winc), .wfull(wfull),
.wclk(wclk));
rptr_empty #(ASIZE) i_rptr_empty
(.rempty(rempty),
.raddr(raddr),
.rptr(rptr), .rq2_wptr(rq2_wptr),
.rinc(rinc), .rclk(rclk),
.rrst_n(rrst_n));
wptr_full #(ASIZE) i_wptr_full
(.wfull(wfull), .waddr(waddr),
.wptr(wptr), .wq2_rptr(wq2_rptr),
.winc(winc), .wclk(wclk),
.wrst_n(wrst_n));
#(parameter ADDRSIZE = 4)
(output reg [ADDRSIZE:0] wq2_rptr,
input [ADDRSIZE:0] rptr,
input wclk, wrst_n);
if (!wrst_n)
wq1_rptr <= 0;
else wq1_rptr <= rptr;
if (!wrst_n)
wq2_rptr <= 0;
else wq2_rptr <= wq1_rptr;
#(parameter ADDRSIZE = 4)
(output reg wfull,
output [ADDRSIZE-1:0] waddr,
output reg [ADDRSIZE :0] wptr,
input [ADDRSIZE :0] wq2_rptr,
input winc, wclk, wrst_n);
wire [ADDRSIZE:0] wgraynext, wbinnext;
always @(posedge wclk or negedge wrst_n)
if (!wrst_n) {wbin, wptr} <= 0;
else {wbin,wptr } <= {wbinnext, wgraynext};
// Memory write-address pointer (okay to use binary to address memory)
assign waddr = wbin[ADDRSIZE-1:0];
assign wbinnext = wbin + (winc & ~wfull);
assign wgraynext = (wbinnext>>1) ^ wbinnext;
//------------------------------------------------------------------
assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],wq2_rptr[ADDRSIZE-2:0]});
always @(posedge wclk or negedge wrst_n)
if (!wrst_n) wfull <= 1'b0;
else wfull <= wfull_val;
parameter ADDRSIZE = 4) // Number of mem address bits
(output [DATASIZE-1:0] rdata,
input [DATASIZE-1:0] wdata,
input [ADDRSIZE-1:0] waddr, raddr,
input wclken, wfull, wclk);
reg [DATASIZE-1:0] mem[15:0];
always @(posedge wclk)
if (wclken && !wfull) mem[waddr] <= wdata;
endmodule