4异步FIFO的设计.docx

上传人:b****7 文档编号:10417748 上传时间:2023-02-11 格式:DOCX 页数:16 大小:653.79KB
下载 相关 举报
4异步FIFO的设计.docx_第1页
第1页 / 共16页
4异步FIFO的设计.docx_第2页
第2页 / 共16页
4异步FIFO的设计.docx_第3页
第3页 / 共16页
4异步FIFO的设计.docx_第4页
第4页 / 共16页
4异步FIFO的设计.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

4异步FIFO的设计.docx

《4异步FIFO的设计.docx》由会员分享,可在线阅读,更多相关《4异步FIFO的设计.docx(16页珍藏版)》请在冰豆网上搜索。

4异步FIFO的设计.docx

4异步FIFO的设计

利用异步FIFO在跨时钟域中降低亚稳态发生概率

在数字电路设计中,时钟是整个电路最重要、最特殊的信号,系统内大部分器件的操作都是在时钟的跳变沿上进行,如果时序不满足要求,就可能造成逻辑状态出错甚至整个系统设计的失败。

随着SOC技术的不断发展,数字系统设计的复杂度也在日益增加,经常需要跨时钟域的数据传输,通信技术等异步设计才能实现特定的功能需求。

本文设计的异步FIFO就是为了解决将数据从一个时钟域同步的读/写到另一个时钟域,并且能很好的避免亚稳态的发生。

1.异步系统

任意的两个系统如果满足以下条件之一,如图1-2所示,就可称其为异步的:

(1)工作在不同的时钟频率上;

(2)工作在相同频率上,但相位不同

图1-2异步系统时钟

当两个不同时钟域的系统进行数据传输,由于接口处是异步的,就可能会违反建立时间和保持时间规则导致亚稳态以及不可靠的数据传输,因此处理起来较同步逻辑复杂困难。

在同步系统中,输入信号必须总是满足寄存器时序要求,所以亚稳态不会发生。

亚稳态问题通常发生在当一个信号在无关的线路中或异步时钟域中传输。

在所有的异步系统中,亚稳态是不可避免的。

1.1亚稳态

所有的数字器件寄存器都定义了一个信号时序要求,满足了这个要求寄存器才可以正确地在输入端获取(capture)数据在输出端产生数据。

为了确保数据的可靠与正确性,在数据传输过程中必须满足寄存器的建立时间和保持时间,如图1-1,即输入数据在时钟沿之前必须稳定一段时间(寄存器建立时间Tsu)并且在时钟沿之后稳定一段时间(寄存器保持时间Th),然后寄存器输出经过一个特定的时钟到输出延时(clocktooutput,Tco)后有效。

图1-1建立时间与保持时间

如果一个数据信号在翻转中违反了一个寄存器的建立和保持时间的要求,寄存器的输出可能就会出现亚稳态。

在亚稳态中,寄存器的输出值在高和低之间徘徊一段时间,这就意味着输出翻转到一个确定的高或低的延时会超过固定的时钟到输出延时。

亚稳态最初是描述是一种物理现象,用一个形象的例子“山丘上的小球”来类比这种不稳定平衡状态。

如图1-3所示,再将其对应到寄存器数据的输入,采样,输出过程,可以清楚地看到当数据的输入不满足Tsu或Th时,就会出现“小球在山顶徘徊”的亚稳态(暂态),导致违反Tco使得时序逻辑出错。

图1-3亚稳态示意图

一旦发生亚稳态,就无法预知寄存器数据输出以及输出时间延迟Tco。

对于系统整体来说,进入了不可测状态,是非常危险的,显然这也降低了系统的可靠性与稳定性。

1.2同步电路

在异步系统中亚稳态不可避免这一事实对设计提出了考验。

如何降低亚稳态发生的概率,提升系统的容错性能成为设计的关键。

经过大量的设计与验证,主要有两种方法用来解决跨时钟域所引起的亚稳态问题:

(1)握手协议;

(2)异步FIFO。

以上这两种方法都可归结为“同步技术”,通过寄存器链组成同步电路,大大降低亚稳态发生的概率。

由于取样(sampling)一般发生在新时钟域的跳变沿,而另一个时钟域的输出数据,传输到新时钟域的时,数据会在任意的翻转,可能会违反取样寄存器的建立或保持时间,很容易产生亚稳态。

所以同步寄存器链基于“冗余”原则,为跨时钟域的异步数据传输提供时间裕量,即亚稳态转稳态所需要的时间。

如图1-4为典型的两级寄存器连:

数据Data从Clock1时钟域传输到Clock2时钟域前需要进行同步,链中的第一个寄存器提供了同步作用。

图1-4两级寄存器同步链

同步链是由一系列的寄存器所组成,根据电路时序逻辑的需求来估算链中寄存器的个数,两级是其中最简单,也较为常用的结构。

其设计也需要满足一定的要求:

(1)链中的所有寄存器是由同一个时钟或相位相关时钟驱动;

(2)链中除了最后一个寄存器可以为多扇出,其余寄存器的扇出只能是单一的。

虽然同步技术可以很好地解决亚稳态问题,确保系统的稳定性,但是由于亚稳态转稳态期间寄存器取样的不确定性,可能会导致数据传输错误。

想想看,当山顶的小球回落山底时有两种选择,对应寄存器就是新旧数据的输出,这点就可以很容易理解。

握手协议是一种最直接的同步技术,就是通过“请求”与“应答”模式对异步接口进行同步。

但这种处理方式是以损失传输速率为代价的,“请求”与“应答”信号的发出都需要额外的时钟周期,加入两到三级寄存器同步异步时钟域的信号或数据,会有许多时钟周期浪费在了系统的“握手”过程中,特别是对需要进行频繁数据交互的系统。

对性能要求较高而不太计较资源,或者在高速电路中不期望浪费时间在握手信号的处理上时,通常会采用异步FIFO来处理跨时钟域可能引入的亚稳态问题。

2.异步FIFO的设计

FIFO(FirstInFirstOut)是一种先进先出的数据缓存器,只能按顺序进行数据的读写,其数据地址由内部读写指针自动加1完成,因此不需要单独的外部读写地址线,这是与一般存储器如RAM,SDRAM等的区别,使用起来非常简单。

异步FIFO一般用于不同时钟域之间的数据传输,如图1-5所示,模块A与模块B处于不同的时钟域,利用异步FIFO对异步数据传输进行同步。

一个常见的例子,若异步FIFO的一端是AD数据采集,另一端是计算机的PCI总线,假设其AD采集的速率为16位100KSPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率常为1056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。

图1-5异步FIFO的同步作用

2.1FIFO的重要参数

FIFO的宽度:

THEWIDTH,它指的是FIFO一次读写操作的数据位,就像MCU有8位和16位,ARM32位等等,FIFO的宽度在单片成品IC中是固定的,也有可选择的,如果用FPGA自己实现一个FIFO,其数据位,也就是宽度是可以自己定义的。

 FIFO的深度:

THEDEEPTH,指的是FIFO的存储单元个数,即可以存储多少个N位的数据(如果宽度为N)。

如一个8位的FIFO,若深度为8,它可以存储8个8位的数据,深度为12,就可以存储12个8位的数据,FIFO的深度可变,在兼顾系统性能和FIFO成本的情况下估算一个大概的宽度和深度就可以了。

 

满标志:

Full,FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。

 空标志:

Empty,FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。

 读时钟:

Readclock,读操作所遵循的时钟,在每个时钟沿来临时读数据。

 写时钟:

Writeclock,写操作所遵循的时钟,在每个时钟沿来临时写数据。

 读指针:

Readponter,指向下一个要读出地址,读完后自动加1。

 写指针:

Writeponter,指向下一个要写入地址,写完后自动加1。

读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。

2.2FIFO的工作原理

FIFO设计的难点在于怎样判断FIFO的空/满状态。

为了保证数据正确的写入或读出,而不发生益处或读空的状态出现,必须保证FIFO在满的情况下,不能进行写操作。

在空的状态下不能进行读操作。

怎样判断FIFO的满/空就成了FIFO设计的核心问题。

为了更好地设计异步FIFO可以先里理解较为简单的同步FIFO工作原理。

在单一时钟域内可以设置计数器来判断FIFO的“空/满”标志。

如果是复位信号则读写指针均指向“0”地址;进入只写不读状态时,写指针指向下一个要写入地址,写完后自动加1,计数器也随着写指针的移动自动加1,当计数器的值为FIFO的深度时,产生“满”信号,停止写入操作避免造成上溢;进入只读不写的状态时,读指针指向下一个要写入地址,写完后自动加1,计数器也随着写指针的移动自动减1,当计数器的值为0时,产生“空”信号,停止读操作避免造成下溢;进入保持状态(不读不写或者读写同时进行),计数器的值不受读写指针的影响且保持不变,即无需担心出现上溢或下溢的问题。

但对于异步FIFO来说,这种利用计数器判断“空/满”状态的方法不能继续使用,因为在两个不同的时钟域需要同时控制计数器,但这种异步的控制无法直接实现。

为了判断“空/满”状态,必须对读写指针进行比较。

2.3读写指针的处理

图1-6异步FIFO的空/满条件判断吧

2.4格雷码计数器

为了比较不同时钟产生的指针,需要把不同时钟域的信号同步到本时钟域中来,而使用格雷码的目的就是使这个异步同步化的过程发生亚稳态的机率最小。

2.4.1格雷码简介

在数字系统中只能识别0和1,各种数据要转换为二进制代码才能进行处理,格雷码是一种无权码,采用绝对编码方式,典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环、单步特性消除了随机取数时出现重大误差的可能,它的反射、自补特性使得求反非常方便。

格雷码属于可靠性编码,是一种错误最小化的编码方式,因为,自然二进制码可以直接由数/模转换器转换成模拟信号,但某些情况,例如从十进制的3转换成4时二进制码的每一位都要变,使数字电路产生很大的尖峰电流脉冲。

而格雷码则没有这一缺点,它是一种数字排序系统,其中的所有相邻整数在它们的数字表示中只有一个数字位不同。

它在任意两个相邻的数之间转换时,只有一个数位发生变化。

大大地减少了由一个状态到下一个状态时逻辑的混淆。

另外由于最大数与最小数之间也仅一个数不同,故通常又叫格雷反射码或循环码。

2.4.2格雷码与二进制码之间的转换

(1) 自然二进制码转换成二进制格雷码

其法则是保留自然二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高位与次高位相异或,而格雷码其余各位与次高位的求法相类似。

(2)二进制格雷码转换成自然二进制码

其法则是保留格雷码的最高位作为自然二进制码的最高位,而次高位自然二进制码为高位自然二进制码与次高位格雷码相异或,而自然二进制码的其余各位与次高位自然二进制码的求法相类似。

2.4.3格雷码计数器的电路设计

图1-7二进制格雷码计数器的设计

2.5异步FIFO的整体电路设计

图1-8异步FIFO的电路设计与代码层次结构

模块功能介绍:

Fifo.v:

顶层文件,包含各个子模块

Fifomem.v:

作为FIFO的缓冲存储器,用于数据的读写,功能类似于双端口的RAM。

Sync_w2r.v:

将写时钟域的指针同步到读时钟域。

Sync_r2w.v:

将读时钟域的指针同步到写时钟域。

Wptr_full.v:

利用读写指针值的对比来判断是否写满。

Rptr_empty.v:

利用读写指针值的对比来判断是否读空。

编写testbench,利用modelsim对以上RTL级代码进行行为级功能验证:

测试结果如下:

附:

源代码如下:

modulefifo#(parameterDSIZE=8,

parameterASIZE=4)

(output[DSIZE-1:

0]rdata,

outputwfull,

outputrempty,

input[DSIZE-1:

0]wdata,

inputwinc,wclk,wrst_n,

inputrinc,rclk,rrst_n);

wire[ASIZE-1:

0]waddr,raddr;

wire[ASIZE:

0]wptr,rptr,wq2_rptr,rq2_wptr;

sync_r2wsync_r2w(.wq2_rptr(wq2_rptr),.rptr(rptr),

.wclk(wclk),.wrst_n(wrst_n));

sync_w2rsync_w2r(.rq2_wptr(rq2_wptr),.wptr(wptr),

.rclk(rclk),.rrst_n(rrst_n));

fifomem#(DSIZE,ASIZE)fifomem

(.rdata(rdata),.wdata(wdata),

.waddr(waddr),.raddr(raddr),

.wclken(winc),.wfull(wfull),

.wclk(wclk));

rptr_empty#(ASIZE)rptr_empty

(.rempty(rempty),

.raddr(raddr),

.rptr(rptr),.rq2_wptr(rq2_wptr),

.rinc(rinc),.rclk(rclk),

.rrst_n(rrst_n));

wptr_full#(ASIZE)wptr_full

(.wfull(wfull),.waddr(waddr),

.wptr(wptr),.wq2_rptr(wq2_rptr),

.winc(winc),.wclk(wclk),

.wrst_n(wrst_n));

endmodule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

modulefifomem#(parameterDATASIZE=8,//Memorydatawordwidth

parameterADDRSIZE=4)//Numberofmemaddressbits

(output[DATASIZE-1:

0]rdata,

input[DATASIZE-1:

0]wdata,

input[ADDRSIZE-1:

0]waddr,raddr,

inputwclken,wfull,wclk);

`ifdefVENDORRAM

//instantiationofavendor'sdual-portRAM

vendor_rammem(.dout(rdata),.din(wdata),

.waddr(waddr),.raddr(raddr),

.wclken(wclken),

.wclken_n(wfull),.clk(wclk));

`else

//RTLVerilogmemorymodel

localparamDEPTH=1<

reg[DATASIZE-1:

0]mem[0:

DEPTH-1];

assignrdata=mem[raddr];

always@(posedgewclk)

if(wclken&&!

wfull)mem[waddr]<=wdata;

`endif

endmodule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

modulesync_r2w#(parameterADDRSIZE=4)

(outputreg[ADDRSIZE:

0]wq2_rptr,

input[ADDRSIZE:

0]rptr,

inputwclk,wrst_n);

reg[ADDRSIZE:

0]wq1_rptr;

always@(posedgewclkornegedgewrst_n)

if(!

wrst_n){wq2_rptr,wq1_rptr}<=0;

else{wq2_rptr,wq1_rptr}<={wq1_rptr,rptr};

endmodule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

modulesync_w2r#(parameterADDRSIZE=4)

(outputreg[ADDRSIZE:

0]rq2_wptr,

input[ADDRSIZE:

0]wptr,

inputrclk,rrst_n);

reg[ADDRSIZE:

0]rq1_wptr;

always@(posedgerclkornegedgerrst_n)

if(!

rrst_n){rq2_wptr,rq1_wptr}<=0;

else{rq2_wptr,rq1_wptr}<={rq1_wptr,wptr};

endmodule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

modulerptr_empty#(parameterADDRSIZE=4)

(outputregrempty,

output[ADDRSIZE-1:

0]raddr,

outputreg[ADDRSIZE:

0]rptr,

input[ADDRSIZE:

0]rq2_wptr,

inputrinc,rclk,rrst_n);

reg[ADDRSIZE:

0]rbin;

wire[ADDRSIZE:

0]rgraynext,rbinnext;

//-------------------

//GRAYSTYLE2pointer

//-------------------

always@(posedgerclkornegedgerrst_n)

if(!

rrst_n){rbin,rptr}<=0;

else{rbin,rptr}<={rbinnext,rgraynext};

//Memoryread-addresspointer(okaytousebinarytoaddressmemory)

assignraddr=rbin[ADDRSIZE-1:

0];

assignrbinnext=rbin+(rinc&~rempty);

assignrgraynext=(rbinnext>>1)^rbinnext;

//---------------------------------------------------------------

//FIFOemptywhenthenextrptr==synchronizedwptroronreset

//---------------------------------------------------------------

assignrempty_val=(rgraynext==rq2_wptr);

always@(posedgerclkornegedgerrst_n)

if(!

rrst_n)rempty<=1'b1;

elserempty<=rempty_val;

endmodule

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

modulewptr_full#(parameterADDRSIZE=4)

(outputregwfull,

output[ADDRSIZE-1:

0]waddr,

outputreg[ADDRSIZE:

0]wptr,

input[ADDRSIZE:

0]wq2_rptr,

inputwinc,wclk,wrst_n);

reg[ADDRSIZE:

0]wbin;

wire[ADDRSIZE:

0]wgraynext,wbinnext;

//GRAYSTYLE2pointer

always@(posedgewclkornegedgewrst_n)

if(!

wrst_n){wbin,wptr}<=0;

else{wbin,wptr}<={wbinnext,wgraynext};

//Memorywrite-addresspointer(okaytousebinarytoaddressmemory)

assignwaddr=wbin[ADDRSIZE-1:

0];

assignwbinnext=wbin+(winc&~wfull);

assignwgraynext=(wbinnext>>1)^wbinnext;

//------------------------------------------------------------------

//Simplifiedversionofthethreenecessaryfull-tests:

//assignwfull_val=((wgnext[ADDRSIZE]!

=wq2_rptr[ADDRSIZE])&&

//(wgnext[ADDRSIZE-1]!

=wq2_rptr[ADDRSIZE-1])&&

//(wgnext[ADDRSIZE-2:

0]==wq2_rptr[ADDRSIZE-2:

0]));

//------------------------------------------------------------------

assignwfull_val=(wgraynext=={~wq2_rptr[ADDRSIZE:

ADDRSIZE-1],

wq2_rptr[ADDRSIZE-2:

0]});

always@(posedgewclkornegedgewrst_n)

if(!

wrst_n)wfull<=1'b0;

elsewfull<=wfull_val;

endmodule

参考文献:

[1]CliffordE.CummingandPeterAlfke,“SimulationandSynthesisTechniquesforAsynchronousFIFODesignwithAsynchronousPointerComparisons,”SNUG2002(SynopsysUsersGroupConference,SanJose,CA,2002)UserPapers,March2002,SectionTB2,3rdpaper.Alsoavailableatwww.sunburst-

[2]Altercompany,TheWhitePaperUnderstandingtheMetastabilityofFPGA

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 判决书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1