当前位置:   article > 正文

异步fifo设计(1)---原理_异步fifo时序图

异步fifo时序图

作为跨时钟域数据传输的两大方式之一(握手协议和异步fifo),异步fifo在面试中也是高频的考点,因此这里专门做一帖的详细介绍。

异步fifo,其内部核心可看成是一块双端口的RAM存储器,

基于此存储器,接下来分析fifo的读写时序;

从图上可以看出,若要向地址0写入数据,则D0触发器的使能信号判断条件为组合逻辑(wen && waddr == 0),若满足,则将din写入到D0;注意,这里wdin、wen、waddr三个信号均是同步的,即一旦使能信号到来,则数据就写入对应地址触发器,尤其要注意,waddr是通过计数器来实现地址的增加的,wen一个脉冲结束,地址就会加1,具体时序如下

读端口的逻辑设计从图上也可以看出,当使能信号到达时,先经过地址触发器,经过RAM处理后,送出的rdata信号还要再经过一个触发器才会将数据送出,因此从使能信号拉高开始,一共经过了两个时钟周期才能将数据输出,因此,rdata_vld信号在ren信号两个周期后拉高,这是由器件本身决定的。

wdata即wdin为要写入的数据,ack在下一个时钟周期拉高代表写入成功,data为读的数据,经过两周期延迟后输出,第一周期负责处理地址读,第二周期负责送。

那么,异步fifo的结构了解清楚了,现在就出现了以下两个问题:

  1. 当写指针快于读指针时,导致写入的数据直接覆盖掉还没有读到的数据;

  1. 当读指针快于写指针时,导致多读出了一些还没写的错误的数据。

要解决这两个问题,就要研究异步fifo的空满标志位如何产生了,即full和empty信号。

首先思考,读写地址相等时,是空还是满

异步fifo空满水限(full limit & empty limit)的设计

写满的两种表现

设置fifo深度为16,假设当写入的数据≥14个后为写满,写地址在自加写,读地址也在自加读,当写地址减去读地址的差≥14时,则写满警告出现,这里就要分两种情况讨论,第一种是写地址>读地址,则直接大减小,第二种为写地址<读地址,则地址之差为waddr + 16 - raddr;如waddr = 6,raddr = 8,则diff addr = 6 + 16 - 8 = 14,则写满;当waddr = raddr时,写满和读空两种情况都有可能出现,因此才需要设计空满水限。

上面阐述了空满产生的条件,关键在于写写地址与读地址之间的差值是多少,而读写地址又是位于不同的时钟域下的,并且空满信号的产生也是在不同的时钟域下进行判断,这就涉及到如何地址相见,在哪个时钟域产生空满的问题。

首先来看异步fifo空信号的设计(将写地址waddr同步到读时钟域RCLK)产生的问题:

  1. fwclk > frclk时,waddr出现漏采问题;(待解决)

  1. fwclk < frclk时,waddr出现多采问题;(无需处理)

  1. 出现亚稳态,导致waddr同步出错问题;(格雷码处理)

下面结合时序图具体分析将写地址直接同步到读时钟域RCLK因亚稳态产生waddr出错的问题:

可以看出,由于出现了亚稳态,地址的两个字节都同时产生了不确定性,最终四种情况的地址都有可能产生。

解决方案:格雷码

格雷码的意义:

由于二进制的读写指针会出现多位同时跳变,直接由同步器会产生错误的中间值,从而产生错误的空满标志。

深度为16的二进制及格雷码Gray-Code码递变表

Gray-Code的设计

由于Gray-Code计数器每一次只改变一个bit,那么采样的结果只可能是计数器的前一个值或者是新的值。

局限性:计数深度必须是2的n次幂(为什么?)

Gray-Code码到二进制的转换

4bit的Gray-Code码到二进制的转换等式

B(i) = G(i); (i = N - 1)

B(i) = B(i + 1) XOR G(i); (0 <= i < N - 1)

对应的verilog代码:

module gray2bin (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 + 1)

bin[i] = ^(gray >> i);//右移取异或

endmodule

二进制到格雷码的转换

转换等式:

G(i) = B(i + 1) XOR B(i); (0 <= i < N - 1)

G(i) = B(i); (i = N - 1)

verilog代码:

module bin2gray (gray, bin);

parameter SIZE = 4;

output [SIZE - 1 : 0] gray;

input [SIZE - 1 : 0] bin;

assign gray = (bin >> 1) ^ bin;//将二进制bin右移后对应位置异或

endmodule

格雷码计数器的verilog设计:

module graycntr (gray, clk, inc, rst_n)

parameter SIZE = 4;

output [SIZE - 1 : 0] gray;

input clk, inc, rst_n;

reg [SIZE - 1 : 0] gnext, gray, bnext, bin;

interger i;

always @(posedge clk or negedge rst_n)

if (!rst_n)

gray <= 0;

else

gray <= gnext;

always @(posedge clk or negedge rst_n)

for (i = 0; i < SIZE; i = i + 1)

bin[i] = ^(gray >>i);

bnext = bin + inc;

gnext = (bnext >> 1) ^ bnext;

end

endmodule

将地址转换为格雷码后再同步到读时钟域的时序图如下:

首先,格雷码地址只会有一位产生变化,因此waddr[2:0]全程不改变,不会发生亚稳态,而只需要考虑waddr[3],而将waddr[3]同步到读时钟域两拍后,waddr只会产生[1000]和[0000]两种情况,而这两种情况均能得到正确的地址,因此解决了跨时钟域采错的问题。

电路图如下:

不同时钟域间信号传递必须是时序逻辑,不能是组合逻辑直接相连。

这里有一点要注意,在判断是否为空的情况下,亚稳态如果得到的是1000老地址,则用老写地址减去读地址,只会是更安全的情况,即老地址都没写读空,则新写的地址更不可能出现读空。同理,这里fwclk>frclk,有可能出现漏财的情况,但漏财也不会影响empty的判断。

根据以上对empty产生信号的分析,得到full和empty信号产生电路图结构如下:

empty在读时钟域判断,waddr同步到rclk将得到老的写地址,这会让empty的判断更安全可靠;同理,full在写时钟域判断,raddr同步到wclk将得到老的读地址,这会让full的判断更安全可靠。

以上就是关于异步fifo设计的主要内容,下一节再讨论异步fifo深度计算问题。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/1009814
推荐阅读
相关标签
  

闽ICP备14008679号