先进先出缓存电路FIFO在大规模逻辑设计当中,得到普遍地使用。几乎每个芯片都会涉 及到它。也就是说每个大规模逻辑设计者都必须掌握该种电路的设计方法。但在实际应 用中,FIFO的类型又不尽相同。有的电路需要的是同步FIFO(即:读写时钟为同一个时 钟),有的需要异步FIFO(即:读写时钟的频率或相位不一样),有的电路对FIFO的速 度要求不高,有的则需要高速FIFO(比如工作频率在100MHz以上)。同时具体电路对FI FO的空满标志的产生也有一定的要求,有按一个深度进行读写的,也有连续读写一块的 (Burst read/write),有读写位宽一致的(256深×80bit <==> 256深×80bit,也有读 写位宽是倍数关系的(256深×80bit<==>1024深×20bit)。异步FIFO的读写地址转变为 格雷码再进行比较,产生空满标志,从而保证电路的可靠性。 XILINX的Coregen软件可以生成一些通用的同步和异步FIFO,如果它不能满足你的特定要 求,只好你自己动手了!不管是什么类型的FIFO,其关键点是产生读、写地址和空、满 标志。好的FIFO设计的基本要求是: 写满而不溢出; 读空又不多读。 同步FIFO的设计 同步FIFO的读写时钟为相同的一个,所以读写地址是同步的。通过判断FIFO中已经存在 多少个没有被读走的数据Cnt_fifo,来判断读空了,还是写满了。Cnt_fifo的产生:当 FIFO进行读但不写时,自增加1,当FIFO进行写但不读时,自减1,如果FIFO又读又写或 不读也不写,则该计数器不变。 满标志的产生:复位时,Full信号初始化为1,表示FIFO满;如果FIFO不读,并且Cnt_f ifo等于FIFO的深度Deepth_fifo时,或者Cnt_fifo等于(Deepth_fifo-1),并且正在写( 即写使能Write_enble有效)时,满标志应该置1;其余情况置为0。 空标志的产生:复位时,让Empty信号为1,表示FIFO空;当FIFO中的Cnt_fifo等于0或者 等于1并且正在读FIFO时,Empty就应置1,表示读空了;其余情况则不空。置为0。 几乎空Almost_empty和几乎满Almost_full标志的产生:在实际应用中为了便于正确产生 读写使能,避免多读和写溢出,经常使用几乎空和几乎满标志,来提前预告FIFO的状态 。要求FIFO还剩下可编程数量Cnt_empty的数据没读走时,就报告几乎空,但是仍允许读 走几个。或者写入FIFO的数据个数超过可编程数量Cnt_full的时候,就报告几乎满,但 仍允许写入几个数据。也就是说当Cnt_fifo>Cnt_full时,FIFO就要置Almost_full为1, 表示几乎空了。当Cnt_fifo<Cnt_empty时,FIFO就要置Almost_empty为1,表示几乎满了 。 读写FIFO的使能的产生:为了确保FIFO即不多读又不多写,采用了自我保护方式,即: 真正的写FIFO使能为外部的写使能和FIFO不满的组合; (assign Write_allow = Write_enable && ! Full ;) 真正的读FIFO使能为外部的读使能和非空的组合; (assign Read_allow = Read_enable && ! Empty ; )。 FIFO的读写地址产生比较简单,当读使能有效时,在时钟作用下,读地址加1;当写使能 有效时,写地址加1。 当FIFO深度较大时,同时FIFO的速度要求较高时,可以采用线性反馈移位计数器(LFSR )。它的速度非常快,但是要牺牲一个地址。 异步FIFO的设计 所谓异步是指读、写时钟是完全独立并且不一致的,或者不同频率,或者同频但不同相 。读地址和空标志是由读时钟产生的,而写地址和满标志则由写时钟产生,当要产生FI FO的空、满标志时,必须进行读写地址的比较时,问题就来临了。如果直接采样地址比 较的话,地址线一般有多位,写地址的每一位在写时钟作用下,跳变得不一致,即产生 毛刺,要过一小段时间才能稳定。在未稳定期内,刚好读时钟进行采样写地址,这时就 出现误判断,逻辑错误。同时采样读写地址相差N个来产生空满信号,时间上会多一些, 因为涉及加和减操作。 为避免地址跳变的不一致造成读写地址误判断,通常采用格雷码。此外,还要根据实际 情况的具体要求采用不同的解决办法,如: 1、加入一个高速时钟,使读写时钟频差在4倍以上; 2、在需要对FIFO包尾进行特殊处理,必须把包尾读出FIFO的情况下,可在异步FIFO后在 加上一个小同步FIFO; 3、还可以通过FIFO备份,读写操作在两个FIFO间按包切换等; 4、还可以强制读写指针在读完一个包和写完一个包时跳变加上一个恒值。 5、请参阅第1章“跨越异步时钟边界传输数据的解决方案”部分的内容。 格雷码的优点是相邻两值只有一位跳变,其他不变,这样地址变化的时间较短,极大提 高比较精度。 格雷码的时序 格雷码是不能进行加减产生空满标志的,那怎么办?采样延时一拍的方法。用读地址Rd _addr产生读地址的格雷码Rd_next_gray_addr,将Rd_next_gray_addr延一拍得到Rd_gr ay_addr,再将Rd_gray_addr延一拍得到Rd_last_gray_addr。你会发现在绝对时间上, Rd_next_gray_addr、Rd_gray_addr、Rd_last_gray_addr这个地址有先后关系,从大到 小排列,并且相差1。如图1所示。 写地址的格雷码的产生也类似。即: Wt_next_gray_addr、Wt_gray_addr、Wt_last_gr ay_addr。利用这6个格雷码进行比较,同时加上读写使能,就能等待空和满标志。 先说空标志Empty吧!当读写格雷码地址相等(Rd_gray_addr = = Wt_gray_addr)或者 FIFO内还剩下一个深度的字(Rd_next_gray_addr = = Wt_gray_addr),并且正在不空 的情况下执行读操作(Read_enable = = 1),这时Empty标志应该置为有效(高电平有 效)。 满标志Full:当写FIFO的格雷码地址等于上次读的格雷码地址时(Wt_gray_addr= = Rd _last_gray_addr),或者下次要写的格雷码地址等于上次读的格雷码地址(Wt_next_g ray_addr= = Rd_last_gray_addr),并且正在执行写操作。此时需要置Full标志有效。 如果要产生几乎空、几乎满标志时,可以多做几个格雷码的延时地址,利用这些读、写 格雷码地址距离远近关系就可以灵活的产生特定读写地址间距的几乎空或几乎满标志。 如果需要在大间距内时,产生几乎空满信号(比如读写地址相差10),那必须采用另外 一种方法:以几乎空为例。当(读地址-10)的格雷码等于写地址的格雷码时,几乎空 信号可以置位了。 读写地址的产生:如果外部写使能(Write_enable)来了,同时FIFO的不满的话,写地 址自增1;如果读使能(Read_enable)有效,同时FIFO不空的话,读地址自增1。在进行 地址的递增时判断FIFO的空满标志是为了自我保护,避免读写地址交错,产生错误逻辑 。 位宽变换FIFO 实际应用中,需要进行数据位宽的变换,比如输入1024×16bit的数据,输出256×64bi t的数据。或者颠倒过来。如图2所示。 FIFO的位宽的转换 在我们的FIFO中使用到了双端口RAM,它可以同时进行读和写操作。就以输入1024×16b it的数据,输出256×64bit数据的FIFO为例说明,其他情况一样。 显然我们需要一个256×64bit的双端口RAM。读地址(Wt_addr[7:0])比较好办,该地址 就是FIFO的深度。但是写地址(Rd_addr[9:0])就要分为两个部分,一个是与FIFO的深 度对应的地址(Rd_addr[9:2]),另一个是位宽方向的地址(Rd_addr[1:0])。因为4个 写地址才对应一个读地址。比较写地址和读地址的高8位就可以产生空、满标志(与前面 的FIFO类似)。 经常与包打交道时,包有包头,有包尾。当读到包尾时,不仅读地址的低2位要变,高8 位也要变,要跳跃到下一个包的包头。而包尾在4个地址中的位置,决定了读地址的跳变 方式。 按块操作的FIFO 实际应用中,有执行突发性(burst)的连续读、写N个深度的FIFO。也就是说对FIFO要 按照块操作。说白了也就是分为高低地址。高地址为块号,低地址为块内的地址。FIFO 的空满标志有读写的高位地址比较产生。 |
|
来自: zhangquanling > 《FPGA_混饭吃的》