(完整word版)异步FIFO的实现方式
quartus 异步fifo用法 -回复
quartus 异步fifo用法-回复quartus异步FIFO用法引言:在数字电路设计中,FIFO(First In First Out)是一种常见的数据存储器,它允许数据以先进先出的顺序进出。
在使用Quartus进行FPGA设计时,异步FIFO是一种非常有用的工具,它可以帮助我们处理不同速度的数据流,并实现数据的缓冲和流量控制。
本文将介绍Quartus异步FIFO的基本概念和使用方法,并给出一些实例。
第一部分:Quartus异步FIFO概述1.1 什么是异步FIFO?异步FIFO是一种数据存储器,在其中数据可以以不同速度进入和退出。
与同步FIFO不同,异步FIFO的读写时钟可以是不同的,这使得它可以处理速度不匹配的数据流。
Quartus提供了异步FIFO的库函数和IP核,使得它可以在FPGA设计中方便地使用。
1.2 Quartus异步FIFO的特点Quartus异步FIFO具有以下特点:- 可以使用不同的时钟频率进行读写操作。
- 可以配置不同的缓冲深度来满足特定的设计需求。
- 可以实现流量控制和数据的重排序。
- 可以支持并行读写和读写使能信号。
- 可以适应不同的数据宽度和时钟域要求。
第二部分:Quartus异步FIFO的使用方法2.1 创建异步FIFO在Quartus中创建异步FIFO的方式有两种:使用库函数和使用IP核。
使用库函数创建异步FIFO的步骤如下:- 首先,在Quartus中打开设计工程,并创建一个新的源文件。
- 然后,将异步FIFO的库函数导入到源文件中,以便在设计中调用它。
- 接着,实例化异步FIFO,并通过参数配置其属性,例如宽度,深度,时钟域等。
- 最后,将异步FIFO连接到其他逻辑模块,完成设计。
使用IP核创建异步FIFO的步骤如下:- 首先,在Quartus中打开设计工程,并创建一个新的IP核。
- 然后,在IP核的界面中选择合适的FIFO类型和配置参数。
- 接着,将异步FIFO实例化到设计中,将其连接到其他逻辑模块。
跨时钟域之异步FIFO
跨时钟域之异步FIFOAsynchronous FIFO Design异步FIFO的读写指针写指针写指针指向当前将要写⼊数据的位置,复位之后,读写指针被置零。
执⾏写操作的时候,向写指针指向的存储区写⼊数据,之后写指针加1,指向接下来要被写⼊数据的位置。
On a FIFO-write operation, the memory location that is pointed to by the write pointer is written, and then the write pointer is incremented to point to the next location to be written.读指针:读指针指向当前要被读取数据的位置,复位时,读写指针被置零,FIFO为空读指针指向⼀个⽆效的数据(FIFO为空,empty信号有效——拉⾼)。
当第⼀个有效数据被写⼊FIFO之后,写指针增加,empty flag信号被拉低,且读指针⼀直指向FIFO第⼀FIFO空标志:当读写指针是相等的时候:分两种情况1.当读写指针执⾏复位操作的时候。
2.当读指针赶上写指针的时候,最后⼀笔数据从FIFO读出后FIFO为空FIFO满标志:读写指针相等,当FIFO⾥⾯的写指针写满⼀圈之后⼜转回到和读指针同样的位置。
有个问题,读写指针相等的时候怎么判断FIFO是empty还是full?设计的时候增加⼀位bit去辅助判断FIFO是空还是满。
当写指针超过FIFO的最⼤寻址范围时,写指针将使辅助位zhi⾼,其余位为0.FIFO满的时候:读写指针的低位(n-1位bit)相等,⾼位(第n位bit)不同。
FIFO空的时候,读写指针的低位和⾼位都相等。
(针对⼆进制)但是⼆进制FIFO指针综合电路复杂,⼀般采⽤**格雷码**,⽂章中采⽤⼆进制转换格雷码的⽅法,判断FIFO的空满标志4位⼆进制格雷码,有效地址位为三位。
⼆进制转换为格雷码的算法:rgraynext = (rbinnext>>1) ^ rbinnext;1.顶层模块fifo:例化各个⼦模块//顶层模块实例化各个⼦模块module fifo#(parameter DSIZE = 8, //读写数据位宽均设置为8位parameter ASIZE = 4 // 存储地址位宽设置)(output [DSIZE-1:0] rdata,output wfull,output rempty,input [DSIZE-1:0] wdata,input winc, wclk, wrst_n,input rinc, rclk, rrst_n);wire [ASIZE-1:0] waddr, raddr;wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;// 内部线⽹// synchronize the read pointer into the write-clock domainsync_r2w sync_r2w(.wq2_rptr (wq2_rptr),.rptr (rptr ),.wclk (wclk ),.wrst_n (wrst_n ));// synchronize the write pointer into the read-clock domainsync_w2r sync_w2r(.rq2_wptr(rq2_wptr),.wptr(wptr),.rclk(rclk),.rrst_n(rrst_n));//this is the FIFO memory buffer that is accessed by both the write and read clock domains.//This buffer is most likely an instantiated, synchronous dual-port RAM.//Other memory styles can be adapted to function as the FIFO buffer.fifomem#(DSIZE, ASIZE)fifomem(.rdata(rdata),.wdata(wdata),.waddr(waddr),.raddr(raddr),.wclken(winc),.wfull(wfull),.wclk(wclk));//this module is completely synchronous to the read-clock domain and contains the FIFO read pointer and empty-flag logic.rptr_empty#(ASIZE)rptr_empty(.rempty(rempty),.raddr(raddr),.rptr(rptr),.rq2_wptr(rq2_wptr),.rinc(rinc),.rclk(rclk),.rrst_n(rrst_n));//this module is completely synchronous to the write-clock domain and contains the FIFO write pointer and full-flag logicwptr_full#(ASIZE)wptr_full(.wfull(wfull),.waddr(waddr),.wptr(wptr),.wq2_rptr(wq2_rptr),.winc(winc),.wclk(wclk),.wrst_n(wrst_n));endmodule2.时钟域同步模块sync_r2w:读指针同步到写时钟域wclk// 采⽤两级寄存器同步读指针到写时钟域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)if (!wrst_n) beginwq1_rptr <= 0;wq2_rptr <= 0;endelse beginwq1_rptr<= rptr;wq2_rptr<=wq1_rptr;endendmodule原理图3.时钟域同步模块sync_w2r:写指针同步到读时钟域rclk//采⽤两级寄存器同步写指针到读时钟域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)if (!rrst_n)beginrq1_wptr <= 0;rq2_wptr <= 0;endelse beginrq1_wptr <= wptr;rq2_wptr <= rq1_wptr;endendmoduleRTL原理图4.存储模块//存储模块module fifomem#(parameter DATASIZE = 8, // Memory data word widthparameter ADDRSIZE = 4 // 深度为8即地址为3位即可,这⾥多定义⼀位的原因是⽤来判断是空还是满,详细在后⽂讲到) // 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);////////////////////////////////这部分没⽤到,可以单独写⼀个模块来调⽤//////////////`ifdef RAM //可以调⽤⼀个RAM IP核// instantiation of a vendor's dual-port RAMmy_ram mem(.dout(rdata),.din(wdata),.waddr(waddr),.raddr(raddr),.wclken(wclken),.wclken_n(wfull),.clk(wclk));//////////////////////////这部分没⽤到,可以单独写⼀个模块来调⽤//////////////////`else //⽤数组⽣成存储体// RTL Verilog memory modellocalparam DEPTH = 1<<ADDRSIZE; // 左移相当于乘法,2^4 将1左移4位reg [DATASIZE-1:0] mem [0:DEPTH-1]; //⽣成2^4个位宽位8的数组assign rdata = mem[raddr];always @(posedge wclk) //当写使能有效且还未写满的时候将数据写⼊存储实体中,注意这⾥是与wclk同步的if (wclken && !wfull)mem[waddr] <= wdata;`endifendmodule原理图5. rptr_empty模块:产⽣rempty和raddr信号//产⽣empty信号和raddar信号的模块module rptr_empty#(parameter ADDRSIZE = 4)(output reg rempty,output [ADDRSIZE-1:0] raddr, //⼆进制形式的读指针output reg [ADDRSIZE :0] rptr, //格雷码形式的读指针input [ADDRSIZE :0] rq2_wptr, //同步后的写指针同步到读时钟域input rinc, rclk, rrst_n);reg [ADDRSIZE:0] rbin;wire [ADDRSIZE:0] rgraynext, rbinnext;// GRAYSTYLE2 pointer//将⼆进制的读指针与格雷码进制的读指针同步always @(posedge rclk or negedge rrst_n)if (!rrst_n) beginrbin <= 0;rptr <= 0;endelse beginrbin<=rbinnext; //直接作为存储实体的地址rptr<=rgraynext;//输出到 sync_r2w.v模块,被同步到 wrclk 时钟域end// Memory read-address pointer (okay to use binary to address memory)assign raddr = rbin[ADDRSIZE-1:0]; //直接作为存储实体的地址,⽐如连接到RAM存储实体的读地址端。
异步fifo的工作原理
异步fifo的工作原理今天咱们来唠唠异步FIFO这个超有趣的东西哦。
你可以把异步FIFO想象成一个特别的小仓库,这个小仓库是用来存放数据的呢。
不过它可有点特别,和咱们平常那种规规矩矩同步的仓库不太一样。
异步FIFO主要是在不同时钟域之间工作的。
就好比啊,有两个世界,一个世界的节奏快,另一个世界的节奏慢,异步FIFO就在这两个节奏不一样的世界之间搭起了一座数据的桥梁。
那它怎么存数据呢?当有数据要进来的时候,就像是有人要往这个小仓库里送货。
在写端口这边,有一个写指针,这个写指针就像一个小向导,它告诉大家数据应该放在仓库的哪个位置。
每次有新的数据要存进来,写指针就会指向下一个空闲的地方。
就像我们在图书馆书架上找空位放书一样,写指针就是那个帮我们找空位的小助手。
再说说读这边吧。
读端口有个读指针,这个读指针就负责从仓库里取数据。
它就像一个小管家,知道哪些数据已经被取走了,哪些还在仓库里等着被取。
读指针也是一步一步地移动,每次取走一个数据,就会指向下一个要取的数据的位置。
这里面有个超关键的东西,就是空满标志的判断。
你想啊,如果仓库满了,还往里塞东西,那不就乱套了嘛;或者仓库都空了,还在傻乎乎地去取数据,那也不行呀。
对于空满标志的判断呢,其实有点小巧妙。
因为是异步的,时钟不一样,所以不能简单地用一个计数器来判断。
一般会采用一些特殊的编码方式,像是格雷码。
为啥用格雷码呢?这就像是给这个小仓库的货物管理上了一道保险。
格雷码的好处就是相邻的码值只有一位不同。
这样在不同时钟域转换的时候,就不容易出错啦。
比如说,写指针和读指针在判断满的时候,不是简单地看数字大小哦。
因为时钟不一样,数字可能会乱套。
用格雷码就不一样啦,它能很准确地判断出是不是真的满了。
就好像是两个人在不同的节奏下数数,但是通过一种特殊的规则,能准确知道什么时候仓库满了。
还有哦,异步FIFO的深度也是个很重要的概念。
深度就像是这个小仓库的大小。
如果数据来的太快,而读的速度又跟不上,那仓库就得大一点,不然就容易满了溢出来。
异步fifo_gray code异步fifo的多种约束方式
异步fifo_gray code异步fifo的多种约束方式英文版Asynchronous FIFOs, also known as Gray code asynchronous FIFOs, are widely used in digital systems to facilitate communication between different clock domains. They are essential for ensuring data integrity and preventing data loss in asynchronous systems. However, designing and implementing asynchronous FIFOs can be challenging due to the potential for metastability issues and timing violations.There are several constraints that need to be considered when designing an asynchronous FIFO. One common constraint is the need for proper synchronization between the read and write pointers to prevent data corruption. This can be achieved using handshaking signals or other synchronization techniques.Another important constraint is the need to ensure proper data transfer between the two clock domains. This requires careful consideration of the setup and hold times of the data signals, as well as the use of Gray code encoding to minimize the chances of metastability.In addition, designers must also consider the impact of clock skew and jitter on the performance of the asynchronous FIFO. Clock skew can lead to timing violations and data corruption, while jitter can cause data loss and synchronization issues.Overall, designing an asynchronous FIFO with Gray code encoding requires careful consideration of various constraints and trade-offs. By carefully analyzing the system requirements and implementing appropriate design techniques, designers can ensure the reliable and efficient operation of their asynchronous FIFOs.中文版异步FIFO,也称为Gray码异步FIFO,在数字系统中被广泛应用,以促进不同时钟域之间的通信。
基于FPGA的异步FIFO设计与实现
基于FPGA的异步FIFO设计与实现王伟国;张振东【摘要】随着现代数字电路系统密度和规模的不断扩大,一个系统中通常会包含多个时钟,因此不同时钟之间的数据传输成为亟待解决的问题.而一种可靠易行的解决方案就是异步FIFO.异步FIFO需要非常严格的多时钟技术,难以作出正确的设计合成和分析.本文提出了一种利用格雷码作为读写地址计数器的异步FIFO的设计方法,有效的避免了数据在不同时钟时间传输时遇到的亚稳态问题.并给出了综合仿真结果.%With the expanding of the density and scale of modern digital circuitry,a system will contain multiple clock.Therefore,the transfer of data between different clock becomes a serious problem needs to be solved.A reliable and feasible solution is asynchronous FIFO.Asynchronous FIFO require very strict clock technology,it is difficult to make the correct design of synthesis and analysis.This paper presents a design method of asynchronous FIFO which based on read/write counter in terms of gray code.This method effectively avoid the metastable state in the data transmission between different clock and given a comprehensive simulation results.【期刊名称】《聊城大学学报(自然科学版)》【年(卷),期】2012(025)003【总页数】6页(P79-84)【关键词】多时钟;异步fifo;verilog;HDL;格雷码【作者】王伟国;张振东【作者单位】中国科学院长春光学精密机械与物理研究所,吉林长春130033;中国科学院长春光学精密机械与物理研究所,吉林长春130033/中国科学院研究生院,北京100039【正文语种】中文【中图分类】TN4330 引言随着现代数字电路系统的实时数据处理能力的不断提高,逻辑电路的复杂程度和内核处理器的运算速度也快速增长,在使得一些复杂算法得以实现的同时也加剧了快速CPU与慢速外设之间的冲突.异步FIFO大量数据缓存的能力成功的解决了这一问题,但专用的高速异步FIFO芯片价格昂贵,且容量受限,随着现场可编程逻辑器件容量和速度的不断提高,利用现场可编程逻辑器件设计异步FIFO成为可行的方法.本文首先讨论了异步FIFO设计中经常出现的亚稳态问题和二进制计数器多位同时改变的问题,并给出解决办法,然后讨论了两种格雷码计数器的形式并作出比较,最后给出一种以格雷码为读写地址计数器的异步FIFO的设计方法和在设计异步FIFO时必须要注意的细节.1 多时钟电路中的亚稳态问题在一个时序电路中,合理的建立时间和保持时间是触发器正常工作的前提条件.对于下降沿触发的触发器而言,下降沿触发之前输入数据持续的最短时间是建立时间(setup time),下降沿触发之后输入数据持续的最短时间是保持时间(hold time).当电路时序不能满足setup time/hold time的要求时,系统时序就会出现混乱.在异步时序电路中,不同时钟之间是不存在任何关系的,必然会产生建立时间和保持时间冲突.解决系统时序问题常用双锁存器法如下图1所示,即在不同时钟之间传输数据时连续锁存两次.但是这种方法只是保证了电平的稳定,而在实际的系统中还需要FIFO作为不同时钟之间传输多位数据的接口.图1 避免亚稳态出现的双锁存器法2 异步FIFO指针对于同步FIFO来说,使用一个计数器计算读出和写入到FIFO缓存器中的数据量,计数器在只有写没读是递增,只读没写是递减,既读又写和没读也没写时保持不变.当计数器到达设定值时FIFO满信号置位,为零时空信号置位.在异步FIFO中,由于这种计算数据个数增减的计数器会被两个不同的时钟控制,因此这种计数器不能使用.所以,为了决定FIFO“空”和“满”状态,读指针和写指针必须相互比较.设计FIFO最主要的困难是生成FIFO指针和找到一个决定FIFO“空”和“满”状态的可靠方法.在FIFO设计中,读指针和写指针总是指向下一个要读和写的地址空间.当读或写操作完成后指针自动递增,当FIFO是空时读指针和写指针相等,当FIFO满时读指针和写指针也是相等.一种解决的方法是增加一个多余的MSB位来区分两种状态,当写指针递增超过地址范围时,写指针会递增MSB位,其他位清零,读指针同样也是.当读指针和写指针的MSB位不同时,意味着写指针比读指针多走了一圈,当MSB位相同时意味着走的圈数相等(如图2所示)图2 增加多余MSB后区分FIFO空和FIFO满的方法示意图当FIFO存储缓冲区需要(n-1)位地址时,地址指针用n位,当指针相等(包括MSB位)时空标志置位,当指针低(n-1)位相等且MSB位不等时满标志置位.2.1 二进制FIFO指针的情况二进制地址计数量会有多个位同时变化,因此在把二进制量在不同时钟域之间同步时会出现问题.一个解决的方法是取样并把周期计数量寄存在一个保持寄存器中,并发出一个ready信号,新时钟域收到信号并发出确认信号,这样变化的计数量就安全的传送到新时钟域.用这种方法不会产生上溢和下溢,因为当读指针递增到与写指针相等时,空信号置位,取样的写指针不反映当前写指针的值,而是小于当前值,故永远不能产生下溢,满信号也是如此.最常用的解决方法是用格雷码计数器,格雷码在每个时钟只有一位变换可以极大的减少在同步计数时错误的发生.3 格雷码计数器设计格雷码计数器的方法有很多,这里介绍二种简单直接的方法.下面详细介绍两种方法.3.1 格雷码计数器中的问题为了更好的理解把n-bit计数器转换成(n-1)-bit计数器时出现的问题,先考虑一下一个双重4-bit和3-bit格雷码计数器的例子如图3.图3 4-bit格雷码计数器示例及转换成3-bit格雷码时出现的问题在4-bit计数器中除了MSB位其余位关于中间对称,我们把2nd MSB位反相后,上半部分与下半部分的LSBs便相等.但是经过反相操作后整体便不是格雷码了,例如15(1100)到0(0000)的转变过程有两个bits变化,在下面的第一种格雷码计数器中会有解决方法.3.2 第一种格雷码计数器图4是第一种计数器的框图并是双重格雷码计数器中两个bits同时跳变的解决方法.其中假设输出寄存器的值是格雷码(ptr),此格雷码被输出到格雷码到二进制的转换器中,然后通过一个有条件递增的加法器并输出下一个格雷码值(gnext),连接到输出寄存器的输入端,如框图上半部分所示.(n-1)-bit格雷码简单地通过n-bit格雷码的2个MSBs的异或操作产生,(n-2)个LSBs不变.图4 第一种格雷码计数器示意图及其如何避免了两位同时跳变问题3.3 第二种格雷码计数器此种风格的格雷计数器(如图5所示)用了两组寄存器避免了把格雷码转换成二进制数的步骤.而且第二组寄存器也可以直接用来寻址FIFO存储器.n-bit格雷码指针仍然需要同步到不同的时钟域中.二进制指针可以更容易的通过计算产生“几乎满”和“几乎空”信号.因此在本论文的设计中用此种风格的格雷码计数器.图5 第二种格雷码计数器工作示意图4 总体设计及“空”和“满”信号的产生总体设计如图6所示,本设计方案共有四个模块,双口RAM模块,读控制模块,写控制模块,格雷码同步模块.写控制模块主要是当写使能信号有效且写满信号无效时产生写地址并实行地址递增功能,读控制模块实现相似功能,双口RAM模块用来使缓冲数据其读写动作可同时进行.4.1 “空”和“满”信号的产生“空”信号的产生比较简单,只需同步到读时钟域的写地址格雷码与n-bit的读指针的格雷码完全相等即可代码如下图6 异步FIFO总体设计框图及其信号说明但是,“满”信号的产生就没那么容易,简单地用n-bit格雷码作比较判断“满”信号是不可靠的.因为格雷码除了MSB位外是对称的如图3所示.在图3中假如写指针和读指针都指向地址7,此时写指针递增一次后,写指针指向地址8,读指针和写指针相比较,除了MSB位不同外其余各位均相等,满信号此时有效,但这是不符合实际情况的,错误的.这也是为什么在图4中应用双重n-bit格雷码计数器的一个原因.正确判断满信号的条件是:读写指针的n-bit格雷码的前两个MSBs都不相等,其余的写指针和同步读针相等.代码如下4.2 不同时钟速度因为异步FIFO被两个不同的时钟控制,很明显两个时钟运行在不同的速度下.当把较快的时钟同步到较慢的时钟时,会有一些计数值被跳过.当被同步的格雷码递增两次只被取样一次时也不会出现亚稳态问题,因为亚稳态出现在同步时钟上升沿附近有多位同时跳变时,而在两个同步时钟沿之间有格雷码跳变两次,第一次跳变距离同步时钟条边沿较远,只有第二次跳变在同步时钟沿附近,故不会产生亚稳态.当较快的格雷码计数器在较慢时钟沿之间递增多于一次,不会出现已经溢出却没有检测到的现象,因为同步到写时钟域的读指针滞后于当前的读指针,而写指针只会小于或等于同步读指针,故不会出现溢出.5 设计仿真及总结本设计采用Xilinx公司Spartan3A系列的XC3S1400A,封装时PG484,速度是-4,仿真器是ISE Simulator(VHDL/Verilog),硬件描述语言是Verilog,开发工具是ISE.最后对电路进行时序分析,结果为该FIFO运行速度可达到90.63MHz.wclk、rclk时钟周期分别为:75MHz、80MHz.先向FIFO中写入18个数据,当第16个数据被读入后wfull立即被置位如下图7.图7 写满仿真结果同时向FIFO中写入和读出数据,由于wptr要经过两个读周期才能同步到读时钟域,故在waddr递增后的第二个rclk的上升沿rempty才清零如下图8所示.本文对异步FIFO的结构和重要时序问题给予了详细的阐述,并得到了可靠的仿真结果.在高速数据采集系统中,采用高性能FPGA作为数据预处理和高速异步FIFO 作为数据采集缓存的应用都十分广泛.把FIFO集成在FPGA中简化了电路设计的复杂程度,增加了电路的集成化程度和可靠性,是未来高速数据采集系统的重要发展方向.图8 同时写入读出时的仿真结果参考文献【相关文献】[1] Clifford E.Cummings,Synthesis and Scrip ting Techniques for De signing Multi-Asynchronous Clock Designs[A].SNUG-2001,2001(3):2-8.[2]吴自信,张嗣忠.异步FIFO结构及FPGA设计[J].单片机及嵌入式系统应用,2000,22(3):1.[3]赵雅兴.FPGA原理、设计与应用[M].天津:天津大学出版社,1999.[4]夏宇闻.数字系统设计-Verilog实现[M].北京:高等教育出版社,2006.[5]王金明.Verilog HDL程序设计教程[M].北京:人民邮电出版社,2004.。
异步fifo原理
异步fifo原理异步FIFO原理解析什么是异步FIFO异步FIFO是一种用于数据接收和发送的电子元件,它按照先入先出(FIFO)的原则处理数据。
它被广泛应用于数字电子系统中的数据缓冲、通信和存储等领域。
异步FIFO的原理异步信号与同步信号的区别1.同步信号:数据的传输采用同一个时钟信号驱动,数据的采样和传输是在时钟的上升沿或下降沿进行的。
2.异步信号:数据的传输不依赖于单一的时钟信号,发出数据的一方和接收数据的一方的时钟信号不一定完全一致。
异步FIFO的工作原理异步FIFO是由两个独立的存储器组成,一个作为数据的写入端,另一个作为数据的读取端。
它们通过一系列的控制信号来实现数据的缓冲和传输。
1.当数据写入FIFO时,写指针会自动递增,将数据写入写指针所指向的位置。
2.当数据读取FIFO时,读指针会自动递增,读取指针所指向的数据,并将其传递给外部。
异步FIFO的数据同步由于不同的时钟信号可能有不同的频率和相位,所以在数据传输过程中,可能会出现时钟抖动或者抖动,导致数据读取错误。
因此,为了保证数据的可靠传输,异步FIFO使用了数据同步机制。
1.FIFO的写指针和读指针都需要采用相关的同步电路,使其与本地时钟信号同步。
2.读指针必须等待写指针来自写入端的下一个时钟周期,并且读指针的启动信号必须与读指针同一时钟周期内变化。
异步FIFO的关键问题异步FIFO在使用过程中,需要注意一些关键问题,以确保数据的正确传输。
数据宽度不兼容在异步FIFO中,写入端和读取端的数据宽度不一定相同。
为了解决这个问题,需要使用数据宽度转换电路,将数据进行格式转换。
读写速度不匹配在数据写入和读取的过程中,写入端和读取端的速度可能不一致。
为了解决这个问题,一种常见的解决方案是使用FIFO深度控制电路,来控制数据的写入和读取速度。
异步FIFO的应用场景异步FIFO主要用于数据缓冲、数据通信以及存储系统等领域。
它在数字电子系统中起到了缓冲数据、数据传输和数据存储的重要作用。
高速异步FIFO的设计和实现
万方数据路中,这一信号最终会朝着0和1两个稳态转换,变成稳定的信号。
这一变换所需的时间取决于寄存器的结构和参数,通常在一个时钟周期内可以完成这一从亚稳态到稳态的转换。
所以,在设计中普遍采用两级寄存器串接的同步器来对信号进行同步,如图1所示。
图1解决亚稳态的同步器电路2.2毛刺单根信号的同步采用图1所示的同步电路即可消除亚稳态问题。
然而,对多位总线信号的同步,除了亚稳态外,还有一个重要的问题就是毛刺现象。
如果需要同步的总线的多位同时发生变化,由于在实际电路中各位的延时不可能完全一致,因此中间就可能会产生毛刺现象。
而用另一个频率相位完全不同的时钟采样的时候就有可能采样到毛刺信号,造成错误的同步。
例如,FIFO的读写指针是一个二进制计数器,当它从l计数到2时,位0从1变成0,位l从0变成1。
如果位0从1变成0的延时比位1从0变1要大,就会在1和2中间多出一个毛刺3,而如果直接用图l的同步电路同步,就有可能错误地在另一个时钟域得到一个3的结果。
对于FIFO的设计来说,这样的同步错误是致命的,会造成空满判断的失误。
解决这一问题就是需要采用无毛刺的电路结构,无毛刺电路要求信号同步前必须被寄存器锁存,并且每次只有一位发生变化。
例如,文献[2]中设计的FIFO就采用格雷码来避免这一问题。
3高速异步FIFO结构3.1基本结构本文设计的高速异步FIFO结构如图2所示,主要包括数据通路reg—file和控制模块fifo—eft两个部分。
reg—file模块是FIFO的存储器部分;fifo_eft模块负责FIFO的读写控制,如读写指针的产生和空满信号的产生。
图2高速异步FWO结构框图本设计的外部端口如表l所示。
3.2reg__file模块设计FIFO的存储器部分可以采用双端口SRAM或者用DFF寄存器搭建存储部分。
由于本设计为32×32的FIFC,存储器容量不大,采用双端口SRAM由于powerring等因素,面积会比用寄存器搭建要大,速度也不容易达86到500MHz的高速。
4.异步FIFO的设计
利用异步FIFO在跨时钟域中降低亚稳态发生概率在数字电路设计中,时钟是整个电路最重要、最特殊的信号,系统内大部分器件的操作都是在时钟的跳变沿上进行,如果时序不满足要求,就可能造成逻辑状态出错甚至整个系统设计的失败。
随着SOC技术的不断发展,数字系统设计的复杂度也在日益增加,经常需要跨时钟域的数据传输,通信技术等异步设计才能实现特定的功能需求。
本文设计的异步FIFO就是为了解决将数据从一个时钟域同步的读/写到另一个时钟域,并且能很好的避免亚稳态的发生。
1.异步系统任意的两个系统如果满足以下条件之一,如图1-2所示,就可称其为异步的:(1)工作在不同的时钟频率上;(2)工作在相同频率上,但相位不同图1-2 异步系统时钟当两个不同时钟域的系统进行数据传输,由于接口处是异步的,就可能会违反建立时间和保持时间规则导致亚稳态以及不可靠的数据传输,因此处理起来较同步逻辑复杂困难。
在同步系统中,输入信号必须总是满足寄存器时序要求,所以亚稳态不会发生。
亚稳态问题通常发生在当一个信号在无关的线路中或异步时钟域中传输。
在所有的异步系统中,亚稳态是不可避免的。
1.1亚稳态所有的数字器件寄存器都定义了一个信号时序要求,满足了这个要求寄存器才可以正确地在输入端获取(capture)数据在输出端产生数据。
为了确保数据的可靠与正确性,在数据传输过程中必须满足寄存器的建立时间和保持时间,如图1-1,即输入数据在时钟沿之前必须稳定一段时间(寄存器建立时间Tsu)并且在时钟沿之后稳定一段时间(寄存器保持时间Th),然后寄存器输出经过一个特定的时钟到输出延时(clock to output ,Tco)后有效。
图1-1 建立时间与保持时间如果一个数据信号在翻转中违反了一个寄存器的建立和保持时间的要求,寄存器的输出可能就会出现亚稳态。
在亚稳态中,寄存器的输出值在高和低之间徘徊一段时间,这就意味着输出翻转到一个确定的高或低的延时会超过固定的时钟到输出延时。
一个异步FIFO的设计示例
一、异步FIFO 技术规范1. 总体描述1.1. 功能定义异步FIFO ( First In First Out)指的是在两个相互独立的时钟域下, 数据从一个时钟域写入FIFO 而另一个时钟域又从这个FIFO 中将数据读出。
本设计用8*256的RAM 实现异步FIFO 。
具体功能:1. 写使能有效,且FIFO 不为满时,在写时钟的上升沿向FIFO 中写入数据。
2. 读使能有效,且FIFO 不为空时,在读时钟的上升沿从FIFO 中读出数据。
3. 当FIFO 写满时产生满信号,当FIFO 读空时产生空信号。
1.2. 应用范围异步FIFO 是用来作为缓冲的存储器, 它能对数据进行快速、顺序的存储和发送, 主要用来解决不同速率器件间的速率匹配问题。
2. 引脚描述8*256异步FIFO rst r_clkr_en data_in[7:0]full empty w_clkw_endata_out[7:0]图12.1. 引脚功能描述 信号名输入/输出 功能描述r_clk输入 读数据时钟信号 w_clk 输入 写数据时钟信号data_in[7:0] 输入8位的输入数据r_en 输入读使能,高电平有效,在FIFO非空时,clk上升沿读入数据;w_en 输入写使能,高电平有效,在FIFO非满时,clk上升沿写入数据;rst 输入异步清零,低电平有效,低电平时读地址,写地址,计数器都清零。
empty 输出空信号,高电平有效,当FIFO读空时其值为1full 输出满信号,高电平有效,当FIFO写满时其值为1 data_out[7:0] 输出8位的输出数据2.2.引脚时序描述当写满时full由低变高,当读空时empty由低变高。
只要不为满full就为低,不为空empty就为低。
3.顶层模块划分。
异步FIFO
使用FIFO同步源自不同时钟域的数据是在数字IC设计中经常使用的方法,设计功能正确的FUFO会遇到很多问题,探讨了两种不同的异步FIFO的设计思路。
两种思路都能够实现功能正确的PIFO。
本文所研究的FIFO,从硬件的观点来看,就是一块数据内存。
它有两个端口,一个用来写数据,就是将数据存入FIFO;另一个用来读数据,也就是将数据从FIFO当中取出。
与FIFO操作相关的有两个指针,写指针指向要写的内存部分,读指针指向要读的内存部分。
FIFO控制器通过外部的读写信号控制这两个指针移动,并由此产生FIFO空信号或满信号。
对于异步FIFO而言,数据是由某一个时钟域的控制信号写入FIFO,而由另一个时钟域的控制信号将数据读出FIFO。
也就是说,读写指针的变化动作是由不同的时钟产生的。
因此,对FIFO空或满的判断是跨时钟域的。
如何根据异步的指针信号对FIFO的满状态或空状态进行正确的判断是本文研究的重点。
此外,设计过程中的一些细节问题也将在文中涉及到。
1 指针以及满空信号的产生为了更好地说明问题,先探讨一下同步FIFO指针移动以及满空信号的产生过程。
对于同步FIFO,读写指针都指向一个内存的初始位置,每进行一次读写操作,相应的指针就递增一次,指向下一个内存位置。
当指针移动到了内存的最后一个位置时,它又重新跳回初始位置。
在FIFO非满或非空的情况下,这个过程将随着读写控制信号的变化一直进行下去。
如果FIFO处于空的状态,下一个读动作将会导致向下溢出(underflow),一个无效的数据被读人;同样,对于一个满了的FIFO,进行写动作将会导致向上溢出(overflow),一个有用的数据被新写入的数据覆盖。
这两种情况都属于误动作,因此需要设置满和空两个信号,对满信号置位表示FIFO处于满状态,对满信号复位表示FIFO非满,还有空间可以写入数据;对空信号置位表示FIFO处于空状态,对空信号复位表示FIFO非空,还有有效的数据可以读出。
基于FPGA的异步FIFO设计方法详解
基于FPGA的异步FIFO设计方法详解在现代电路设计中,一个系统往往包含了多个时钟,如何在异步时钟间传递数据成为一个很重要的问题,而使用异步FIFO可以有效地解决这个问题。
异步FIFO是一种在电子系统中得到广泛应用的器件,文中介绍了一种基于FPGA的异步FIFO设计方法。
使用这种方法可以设计出高速、高可靠的异步FIFO。
在现场可编程逻辑芯片的设计过程中不同模块之间的数据接口尤其是不同时钟系统的各个模块之间的数据接口是系统设计的一个关键用异步FIFO模块来实现接口,接口双方都在自己时钟的同步下进行工作它们之间不需要互相握手只需要跟接口FIFO模块进行交互即可即向接口FIFO模块中写入数据或从FIFO模块中读出数据。
用这样一个缓冲FIFO模块实现FPGA内部不同时钟系统之间的数据接口使设计变得非常简单和容易所用的FIFO 接口是XILINX公司提供的IP核。
经过充分测试和优化,系统运行稳定占用的FPGA内部资源也非常少。
1 FIFO 类型FIFO先进先出队列是一种在电子系统得到广泛应用的器件通常用于数据的缓存和用于容纳异步信号的频率或相位的差异FIFO的实现通常是利用双口RAM 和读写地址产生模块来实现的图1显示出了FIFO 的内部结构。
根据读写操作的同步/异步标志方案的同步/异步第一个写操作以及复位功能的不同FIFO 存储器可分为4 大类:(1)异步FIFO。
通常只有两个控制信号读使能(RE )与写使能(WE)信号标志信号有全空标志(EF)全满标志(FF)可选半满标志(HF)几乎全满标志(AF)几乎全空标志(AE)这些标志并不与任何时钟或事件同步但是反映读写指针的即时对照。
(2)选通式FIFO。
与异步FIFO存储器相似选通FIFO通常使用读写选通UNCK和LDCK 信号以及输出使能OE信号这类FIFO 通常提供半满标志(HF)可选几乎满标志(AF)几乎空标志(AE)全空标志(EF)和全满标志(FF)这些标志虽然反映读写指针但不与任何时钟或事件同步。
任意深度的异步FIFO设计
在异 步 FF IO存 储 器 中 , 写指 针要 被 同步 到对方 的时钟 域 以产 生 空/ 读/ 满信 号 . 由于 二进 制 数 据 每 次
翻转 的不确定性及亚稳态的影响 , 不能将多位二进制数据直接同步到另一时钟域 中. 最常见的方法是先将 数据转化成 Ga 码再同步. r y Ga 码是一种错误最小化编码 , r y ]其缺点是 G a 码指针只能用于实现大小为 2的幂次的 FF r y IO存储
mo tFI s FO s d sg e t a o e,t i e u r s t e d ph o mo y i wa e i n d wi Gr y c d h h s r q ie h e t fme r s 2 Ge e al n rl y,t e h
Ke o d : I O ;me a tb l y y c r n z ;G a o e yw r s F F tsa i t ;s n h o ie i ry c d
随着集成 电路设计规模 的不断扩大 , 使裸片尺寸越来越大 , 这容易造成时钟偏差. 一些新 的方法 , 如整
体异步局部同步( A S 结构正在替代通 常的同步方法 _ , G L) 1 它不需要整体采用单一时钟 , j 因而避免 了时钟
Ab ta t As n h o o s F F s a g n r lwa o c mmu i ae b t e i ee t co k d ma n . As s c : y c rn u I O i e ea r y t o n c t ewe n d f r n l c o i s f
企 肥 学 院 学 报 ( 然科学版) 自
2 1 年 8月 第 2 卷 第 3期 01 1
FIFO同步、异步以及Verilog代码实现
FIFO同步、异步以及Verilog代码实现FIFO 很重要,之前参加的各类电⼦公司的逻辑设计的笔试⼏乎都会考到。
FIFO是英⽂First In First Out 的缩写,是⼀种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使⽤起来⾮常简单,但缺点就是只能顺序写⼊数据,顺序的读出数据, 其数据地址由内部读写指针⾃动加1完成,不能像普通存储器那样可以由地址线决定读取或写⼊某个指定的地址。
FIFO⼀般⽤于不同时钟域之间的数据传输,⽐如FIFO的⼀端是AD数据采集, 另⼀端是计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,⽽PCI总线的速度为33MHz,总线宽度32bit,其最⼤传输速率为 1056Mbps,在两个不同的时钟域间就可以采⽤FIFO来作为数据缓冲。
另外对于不同宽度的数据接⼝也可以⽤FIFO,例如单⽚机位8位数据输出,⽽ DSP可能是16位数据输⼊,在单⽚机与DSP连接时就可以使⽤FIFO来达到数据匹配的⽬的。
FIFO的分类根均FIFO⼯作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。
同步FIFO是指读时钟和写时钟为同⼀个时钟。
在时钟沿来临时同时发⽣读写操作。
异步FIFO是指读写时钟不⼀致,读写时钟是互相独⽴的。
FIFO设计的难点 FIFO设计的难点在于怎样判断FIFO的空/满状态。
为了保证数据正确的写⼊或读出,⽽不发⽣益处或读空的状态出现,必须保证FIFO在满的情况下,不 能进⾏写操作。
在空的状态下不能进⾏读操作。
怎样判断FIFO的满/空就成了FIFO设计的核⼼问题。
.........................................................................................................................................同步FIFO的Verilog代码之⼀在modlesim中验证过。
异步FIFO的verilog代码实现(包含将满和将空逻辑)
异步FIFO的verilog代码实现(包含将满和将空逻辑)异步FIFO的verilog代码实现(包含将满和将空逻辑)代码参考来源:1. Clifford E. Cummings, "Simulation and Synthesis Techniques for Asynchronous FIFO Design".2.⽬录异步FIFO简介使⽤场景:在有⼤量的数据需要进⾏跨时钟域传输,并且对数据传输速度要求⽐较⾼的场合。
⼀个异步 FIFO ⼀般由如下部分组成:1. Memory, 作为数据的存储器;2.写逻辑部分,主要负责产⽣写信号和地址;3.读逻辑部分,主要负责产⽣读信号和地址;4.地址⽐较部分,主要负责产⽣ FIFO 空、满的标志。
跟普通的FIFO相⽐,异步FIFO实际上多了读写地址的跨时钟域同步的逻辑,以及两个时钟域中读写信号的⽐较逻辑。
异步FIFO关键技术1 -- 读写信号跨时钟域同步⾸先,FIFO的关键是需要判断读空和写满,⽽这两个信号的产⽣依赖读地址和写地址。
在异步FIFO中,读和写是分在两个时钟域中的,在写时钟域,需要得到读地址的信息进⽽判断是否写满(写指针是否追上读指针),同理,在读时钟域,也需要写地址的信息。
我们知道跨时钟域的单⽐特数据⼀般可以⽤双寄存器法进⾏同步,但读写地址通常都是多⽐特的信号,此时如何进⾏同步呢?当然,多⽐特的同步肯定可以通过增加握⼿信号来解决,但实际上对于数值上连续的信号,可以采⽤格雷码进⾏多⽐特到单⽐特的传输。
格雷码再次不做介绍,具体原理可以参考:有了格雷码,就可以将读写地址同步到各⾃的时钟域了。
异步FIFO关键技术2 -- 读写地址的⽐较跟普通fifo⼀样,异步fifo也是通过⽐较读写地址是否相同来判断当前fifo是否空满。
区别在于,异步FIFO因为使⽤了格雷码对地址进⾏编码传输。
⽐如读信号通过格雷码编码后同步到写时钟域,此时需要只需要写信号对应的格雷码和读信号格雷码是否相同(有效位相同)。
最经典的FIFO原理
最经典的FIFO原理FIFO (First In, First Out)原理是一种常用的数据结构和算法。
它是指先进入的数据先出来的一种处理顺序。
下面将详细介绍FIFO原理的定义、实现方式、应用场景和一些具体示例,以及它的优点和缺点。
一、FIFO原理定义FIFO原理指的是按照数据进入的顺序,先进入的数据会在后面进入的数据之前被处理或者被取出。
这种处理数据的方式类似于一个队列,数据从队列的一端进入,从另一端出去。
在FIFO原理中,数据进入队列的这一端被称为“队尾”,数据出去的那一端被称为“队首”。
当新的数据进入队列时,它会排在队尾,而当数据被处理或者被取出时,它会从队首开始。
FIFO原理在计算机科学中有广泛的应用,如操作系统中的作业调度、缓存替换策略、网络通信等。
二、FIFO原理实现方式FIFO原理可以通过多种方式来实现。
下面介绍两种常见的实现方式。
1.数组实现使用数组作为底层数据结构来实现FIFO原理的队列。
当新的数据进入队列时,将其添加到数组的末尾;而当数据被取出或者被处理时,将数组的第一个元素移除。
需要注意的是,在数组实现的FIFO队列中,当队列的空间已满时,无法再添加新的数据;当队列为空时,无法再从队列中取出数据。
2.链表实现使用链表作为底层数据结构来实现FIFO原理的队列。
链表中的每个节点包含一个数据元素和一个指向下一个节点的指针。
当新的数据进入队列时,将其添加到链表的末尾;而当数据被取出或者被处理时,将链表的第一个节点移除。
链表实现的FIFO队列可以动态扩展和收缩,因为每个节点只需要存储指向下一个节点的指针,而不需要预先分配一定大小的存储空间。
三、FIFO原理的应用场景FIFO原理在计算机科学中有广泛的应用场景。
下面介绍几个常见的应用场景。
1.操作系统中的作业调度操作系统中的作业调度采用FIFO原理,根据作业进入系统的顺序来安排处理。
当多个作业同时进入操作系统时,根据进入顺序,它们会被添加到作业队列中,然后按照FIFO原理,从队首开始处理。
异步FIFO设计
,异步FIFO设计文档一、概述在大规模ASIC或FPGA设计中,多时钟系统往往是不可避免的,这样就产生了不同时钟域数据传输的问题,其中一个比较好的解决方案就是使用异步FIFO 来作不同时钟域数据传输的缓冲区,这们既可以使相异时钟域数据传输的时序要求变得宽松,也提高了它们之间的传输效率。
此文内容就是阐述异步FIFO的设计。
二、设计原理结构框图Fig. 2.1.1如上图所示的同步模块synchronize to write clk,其作用是把读时钟域的读指针rd_ptr采集到写时钟(wr_clk)域,然后和写指针wr_ptr进行比较从而产生或撤消写满标志位wr_full;类似地,同步模块synchronize to read clk 的作用是把写时钟域的写指针wr_ptr采集到读时钟域,然后和读指针rd_ptr 进行比较从而产生或撤消读空标志位rd_empty。
~另外还有写指针wr_ptr和写满标志位wr_full产生模块,读指针rd_ptr 和读空标志位rd_empty产生模块,以及双端口存储RAM模块。
二进制计数器存在的问题异步FIFO读写指针需要在数学上的操作和比较才能产生准确的空满标志位,但由于读写指针属于不同的时钟域及读写时钟相位关系的不确定性,同步模块采集另一时钟域的指针时,此指针有可能正处在跳变的过程中,如图Fig.2.2.1所示,那么采集到的值很有可能是不期望的值,当然,不期望的错误结果也会随之发生。
Fig. 2.2.1上图中,rd_ptr2sync 3和4以及4和5之间的中间态是由于到各寄存器的时钟rd_clk存在偏差而引起的。
二进制的递增操作,在大多数情况下都会有两位或者两以上的bit位在同一个递增操作内发生变化,但由于实际电路中会存在时钟偏差和不同的路径延时,二进制计数器在自增时会不可避免地产生错误的中间结果,如图Fig.2.2.2。
Fig.2.2.2…上图是Fig.2.2.1的电路原型以及局部波形的放大。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
异步FIFO的实现方式实验目的本次实验介绍一种异步FIFO的实现方式。
使用FIFO存储器可以在两个不同时钟系统之间快速而方便的传输数据。
另外,在网络接口,图像处理等方面异步FIFO存储器也得到了广泛的应用。
因此,异步FIFO存储器具有较大的研究和应用价值。
异步FIFO的介绍和整体结构异步FIFO(First In First Out)存储器是指向FIFO缓冲器中写入数据的时钟域和从FIFO缓冲器中读取数据的时钟域是不同的,这两个时钟之间没有必然的因果关系。
异步FIFO是一种先进先出的电路,使用在异步时钟域数据接口的部分,用来存储、缓冲在两个异步时钟之间的数据传输。
在异步电路中,由于时钟之间周期和相位完全独立,所以数据的丢失概率不为零。
如何设计一个高可靠性、高速的异步FIFO存储器便成为一个难点。
异步FIFO的一般结构如图1所示,都是由一个读时钟域电路、一个写时钟域电路和一个双端口的RAM来构成的。
异步FIFO与同步FIFO所做的工作是相同的,都是在写信号有效时写数据到RAM中,在读信号有效时把数据从RAM中读出,所以对于中间部分的RAM 设计是比较简单的。
另外,读电路和写电路单独实现起来也是比较容易的,只需要按照同步FIFO的工作情况,如果没有写满或读空的状态时每写一个数据就把写地址加1,每读一个数据就把读地址减1。
设计难点在于两个时钟域的交叠部分:满、空状态的产生,这也是设计的重点。
图1 异步FIFO结构针对这个问题,先从对亚稳态的处理开始介绍亚稳态的处理一个触发器进入亚稳态时,既无法预测该单元的输出电平,也无法预测何时输出才能稳定在某个正确的电平上。
在这个稳定期间,触发器输出一些中间级电平,或者可能处于振荡状态、并且这种无用的输出电平可以沿信号通道上的各个触发器级联式传播下去。
亚稳态发生的原因是由于在同步系统中,如果触发器的建立时间或保持时间不满足,就可能产生亚稳态,此时触发器输出端Q在亚稳态是指触发器无法在某个规定时间段内达到一个可确认的状态,逻辑误判有可能通过电路的特殊设计减轻危害(如本设计中将使用的Gray码计数器),而亚稳态的传播则扩大了故障面,难以处理。
在数字集成电路中寄存器要满足建立时间和保持时间。
建立时间是在时钟翻转之前数据输入必须有效的时间,保持时间是在时钟沿之后数据输出必须仍然有效的时间。
当一个信号被寄存器锁存时,如果信号和时钟之间不满足这个要求,Q的值是不确定的,并且在未知的时刻会固定到高电平或低电平。
此时寄存器进入了亚稳态(Metastability)。
解决这一问题的最简单方法是使用同步器,使得在另一个时钟域采样时信号足够稳定。
同步器的设计本身就是一个比较麻烦的问题,本次设计中也不深入讨论一些细节性的问题,直接采用两级采样的同步器,避免了使用一级同步器仍可能出现亚稳态的情况。
每个这样的同步器都具有一个等于时钟周期的等待时间。
这种同步器可以把一些亚稳态的值同步为确定值,但并不一定是正确值,同时有一些亚稳态也还是无法稳定成确切值的,这种情况称为同步出错。
由于同步出错的随机性,很难对它们进行跟踪。
如果想进一步降低亚稳态出现的概率、可以再増加同步器的级数,但是太多的同步器会使系统的性能下降,所以系统中不会用太多的同步器,一般使用两个同步器已经足够。
空满状态的判断之所以在前面介绍了亚稳态的问题,是因为这是判断满状态或空状态无法回避的一个问题。
因为读电路在读控制时维持一个地址指针,写电路在写控制时维持一个地址指针,简单来说,这两个地址指针直接一比较,就能得到空满的判断结果,但是实际操作起来非常麻烦。
例如对于满状态来说,这是写入电路所关心的状态,因为满状态下不能继续写入数据,但是空状态对于写电路没有影响。
如果写入电路要判断当前FIFO是否为满,就需要把写电路自身维持的写指针和读电路维持的读指针做比较,这个读指针就需要送入写电路中,此时就发生了穿过时钟域的问题,也就是说,读指针要从读时钟域同步到写时钟域,然后参与判断,此时就需要前面介绍的同步器。
同样,对于空状态来说,这是读出电路所关心的状态,也是由读电路来维持的,因为空状态下再读数就会得到错误的数据,但是满状态下读数是没有影响的。
如果读电路要判断当前FIFO是否为空,就需要把写时钟域中的写指针取到读时钟域来,和读时钟域的读指针进行比较得出是否是空状态,同样跨越了时钟域。
在跨时钟域系统中希望出现错误的概率越低越好,此时格雷码无疑是最好的一个选择。
格雷码属于可靠性编码,是一种误差最小化的编码,它大大减少了由一个状态到下一个状态时电路混淆。
由这种编码相邻的两个码组之间只有一位不同,和其他编码同时改变2位和多位的情况相比更为可靠。
表1所示是格雷码与二进制码的对应关系。
表1 格雷码与二进制码转换真值表由前面的介绍可知通过同步器之后信号稳定的值可能是1也可能是0,可能与输入的值相同也可能与输入的值不同。
如果对于二进制码,这显然是灾难性的。
例如从十进制的7变到8,二进制码是从0111变为1000,把0111送入同步器之后,由于4位都要变化,所以4位都可能会出现亚稳态,从而在同步器的输出端就会出现各种可能性,这样即使数据稳定下来,对整个电路的作用也很小。
而如果采用格雷码,是从0100变为1100,只是最高位发生了改变,也就只有这一位可能会出现亚稳态的情况。
这样经过同步器处理之后,输出端可能得到的值只有两种0100或1100,其中1100是正确的数值,如果得到这个输出自然是最好,但即使是0100的输出,也只是和原来的值相同,可以认为没有变化,这也不会对电路造成负面的影响。
相比二进制代码那种变化后什么值都有可能的情况,格雷码显然是一种更易于接受的编码方式。
格雷码虽然在跨时钟域方面效果比较好,但在本身计数方面是不足的,也就是说还需要把格雷码转换成二进制码来计数,4位的格雷码转二进制码的代码部分如下:bin[0]=gray[3]^gray[2]^ gray[1]^ gray[0];bin[1]=gray[3]^gray[2]^ gray[1];bin[2]=gray[3]^gray[2];bin[2]=gray[3];也可以用for循环完成:module gray[2](bin,gray);parameter size=4;output [size-1:0] bin;input [size-1:0] gray;reg [size-1:0] bin;integer i;always @(gray)for(i=0;i,size;i=i=i+1);bin[i]=^(gray>>1);endmodule计数之后还要变回格雷码,转换的方法与上述方式类似。
这样使用格雷码作为指针就可以降低亚稳态带来的影响。
接下来要解决的是空满判断的问题,常用的判断方法是附加位比较法。
附加位比较法是给每个指针增加一个附加位,对于二进制指针而言,将存储空间的最后一个存储单元写入数据后,地址将变为零,即地址指针低n-1位清零并向最高位(MSB)也就是附加位进位。
读指针也是如此工作。
如果两个指针的最高位(MSBs)不同而其余位相同,就说明写指针比读指针多循环了一次,标志FIFO存储器处于满状态。
如果包括最高位在内的两个指针完全相同,则说明写指针和读指针经历了相同次数的循环,也就是说FIFO存储器处于空状态。
这样读指针和写指针就变成了一个n位指针,其中低n-1位是用来存放FIFO 存储器的地址,可以用来对2n-1个存储单元寻址,而最高位则用来辨别当两个指针的地址相等时是满状态还是空状态。
对二进制指针来说,用这种方式来区分满状态与空状态是可行的。
但是,格雷码指针却不能直接使用这种方式,原因有两个。
举个4位格雷码的例子,格雷码计数器的低3位用于存放存储地址,第四位是附加位,这个FIFO存储器的存储容量为8。
正确的操作应当是,当写(或读)完一个循环时,地址应该重新开始计数,附加位应该翻转。
然而格雷码指针却并非如此,地址由7到8格雷码由0-100到1-100),指针的附加位改变,但是地址位(低n-1位)却没有重新开始计数,这是由于格雷码是一种镜像码造成的。
第二个原因是这种格雷码不能直接产生满状态标志。
如果两个格雷码指针都是Gray-7,这时的FIFO存储器为空状态,在进行一次写操作后写指针将加1,格雷码第4位将变为1而低3位不变,这时的读指针和写指针的最高位将不同而低位相同。
如果这样的话,FIFO存储器满标志将置位,这显然是错误的,因而需要对这个4位的格雷码进行修改。
想要的结果是:一个n位的(即包括附加位)格雷码计数器用在异步时钟域间传递数据,但是又希望它的低n-1位计数器也是格雷码类型的。
这样低n-1位就能单独形成一个循环,而不是一种反射码。
所以,此时需要的是一个既能产生n位的格雷码序列又能产生n-1位的格雷码序列的计数器。
分别实现一个n位的格雷码计数器和一个n-1位的格雷码计数器自是非常简单:用一个计数器来实现一个n位的格雷码计数器,并将这个计数器的次高位进行修改而低位保持不变以实现一个n-1位的格雷码计数器,这也不是一件很难的事情。
这种既能产生n位格雷码又能产生n-1位格雷码的计数器被称为"两重格雷码计数器。
下面以3位和4位格雷码来说明空满状态的判断标准。
3位格雷码表示的就是地址空间,可以有8个存储空间。
由于写入和读出并不是按照从000开始的,而是可以以任意一个位置开始,比如存放数据可以按照十进制地址5、6、7、0、1、2、3、4的地址顺序来存放,读出数据也同理,这样为了表示循环,就增加了1位变为4位格雷码。
首先说明空状态的判断标准,空状态表示读指针和写指针重合,此时无论是看3位格雷码还是4位格雷码都应该是完全相同,比如写指针指向1010,读指针也必然指向1010,这样判断空状态就只需要判断两个指针是否相同,相同时即为空,不同时即为不空。
然后解释满状态的判断标准。
满状态判断比较复杂。
假设一次写入数据是从十进制地址6开始,连续写入8个数据。
到14,这时存满8个数据,应产生满状态输出,这两个地址形式如下:如果是二进制地址,判断的方法已经介绍过了。
而格雷码地址的前两位是不同的,但后面的两位是相同的。
如果扩展成更多位的格雷码,满状态下依然是这种情况,即前两位不同,后面位均相同。
这样判断满状态首先要保证除去前两位之后的剩余部分是相同的。
然后对于本例来说,需要保证前两部分是01和10,如果地址是以01开头,则满时一定是10;如果以10开头,满时一定是01。
判断的方法可以有很多种,这里采用先取前两位的异或值,保证相等,此时只可能是0,1的组合,然后再判断首位不同,这样就只能是01和10这两种情况。
经过这三个条件的判断,就能就保证此时为写满状态。