• FPGA基础学习(11) -- FIFO设计(style#2)


    在上一篇FIFO设计(stlye#1)中总结了论文《Simulation and Synthesis Techniques for Asynchronous FIFO Design》提出的FIFO设计的第一种方法,本篇博客总结第二种方法,源自论文《Simulation and Synthesis Techniques for Asynchronous FIFO Design with Asynchronous Pointer Comparisons》。

    style#1提出了一种增加补位的格雷码作为指针标识,来判断FIFO是满还是空的方法。 这种方法起源于想要解决“不知道读指针敢上了写指针(空)还是写指针绕了一圈赶上了读指针(满)”的问题。实际上,为了分清空还是满,最重要的就是找准指针的来向。所以style#2就是用读、写指针的最高两位划分成4个象限,来识别读写指针的相对方向,从而正确的判断空满。

    1. 空满判断

    如下两图所示,分别示意了“即将满”和“即将空”,注意“即将”两字。以指针的最高两位00、01、11、10,分别表示第一、第二、第三和第四象限,在判断空满之前遵循以下两个原则:

    • 写指针落后于读指针一个象限,表示即将满;
    • 读指针落后于写指针一个象限,表示即将空;

    说“即将”是表示指针追赶的方向,先有方向,当两指针相等之后,才会产生真正的空或满信号。

    在确定了象限关系之后,会生成dirset_n和dirrst两个信号,用于产生指示指针追赶方向的direction信号,从而确定空满信号,如下图所示。

    如下图,为style#2 FIFO的整体结构框图。

    2. 分析

    实际上style#2理解起来比style#1更简单,但是由于指针是进行的异步比较,并且有一些关键的组合电路,所以论文讨论时序、关键路径以及组合电路的各信号跳变上用了不少篇幅。

    如上图所示,是产生full 和empty的电路图,其中曲线是代码async_cmp.v对应的原理图,后面两个两拍寄存器在相应的代码模块中。

    2.1 工作原理

    1. 论文中说“aempty_n在rclk的上升沿有效,在wclk的上升沿失效”,这句好什么意思呢?因为是组合电路,所以要结合前级的时序电路和代码来分析。

    先看代码:

    module async_cmp #(parameter   ADDRSIZE = 4)
    (
        aempty_n, 
        afull_n, 
        wptr, 
        rptr, 
        wrst_n
    );
        
        parameter   N = ADDRSIZE-1;
        
        output  aempty_n, afull_n;
        input   [N:0]   wptr, rptr;
        input   wrst_n;
        
        reg     direction;
        wire    high = 1'b1;
        wire    dirset_n = ~( (wptr[N]^rptr[N-1]) & ~(wptr[N-1]^rptr[N]));  // wptr在rptr后一个象限,快要满了
        wire    dirclr_n = ~((~(wptr[N]^rptr[N-1]) & (wptr[N-1]^rptr[N])) | ~wrst_n);   // wptr在rptr前一个象限,快要空了
        
     /*    always @(posedge high or negedge dirset_n or negedge dirclr_n)
            if (!dirclr_n) 
                direction <= 1'b0;
            else if (!dirset_n) 
                direction <= 1'b1;
            else 
                direction <= high; */
                
        always @(negedge dirset_n or negedge dirclr_n)
        if (!dirclr_n) direction <= 1'b0;
        else direction <= 1'b1;
        
        assign  aempty_n = ~((wptr == rptr) && !direction);
        assign  afull_n = ~((wptr == rptr) && direction);
        
    endmodule
    

    aempty_n表示FIFO空的使能信号,FIFO既然要为空,那么肯定是读指针“追上”写指针,那什么时候追上呢,肯定是在rclk驱动的读指针在rclk的上升沿出变化的值等于wptr,当然前提是要满足direction = 0的条件。

    同理,什么时候空失效呢?肯定是写指针又继续抢先一步,写指针的变化是有wclk的上升沿触发的。

    那么又有问题?aempty_n跟空信号有关,空信号又是控制读操作的,它必须和读时钟保存紧密的联系,但是aempty_n的失效却跟wclk有关,所以后面两拍rclk驱动寄存器实现了空信号与rclk的同步。注意:aempty_n同时连接寄存器的D端和set端

    同理可以分析afull_n。

    只要结合指针的在各自时钟驱动下的变化,再结合象限指示信号dirset_n和dirclr_n,以及direction信号就可以理解各信号的变化。论文中也现象的对各信号的变化展开了分析。

    1. 有关复位

    从电路图可以看出,复位只直接复位full信号,通过使读写指针相同(都置0),从而间接的使empty信号拉高,从而正确表征FIFO复位后为空。

    2.2 时序及关键路径

    1. 如上面象限比较的电路所示,因为两指针是异步是异步时钟驱动,如果多位输入或多或少不同步的变化,可能导致输出有毛刺,但是采用格雷码编码则可以避免这个问题。

    2. 如下图表示出的有关正确产生empty和full的关键信号。

    3. 问题及解答

    同样这篇论文中,作者对几个关心的问题做了分析和解答,这也是深入理解style#2 FIFO的途径。

    前面分析过aempty_n信号与rempty以及读时钟的基本关系,aempty_n作为两级同步寄存器的输入端和置位端,在rclk的驱动下,产生rempty信号。那么,之前我们又说过aempty_n在rclk的上升沿有效,在wclk的上升沿失效,因为rclk和wclk是异步时钟,在极端情况下,aempty_n刚刚有效(拉低),又迅速失效(拉高),形成一个毛刺(译为反向很短的脉冲,与竞争冒险产生的毛刺区分开),会不会出问题?作者给出了4个场景来说明这个。

    1. 毛刺没有被第一级同步寄存器捕获,故rempty没有产生。这不会导致问题。PS:对这个问题我是这么理解的,既然wclk上升沿迅速到来,并且读写指针不相等,那说明立马又写入了一个数据,这时候实际的FIFO不为空,并且下一个读操作还没到来,所以不会出现读空异常的情形;
    2. 毛刺置位了第一级寄存器,但是没有被第二级寄存器捕获,这种情形不可能出现。最终empty会在rclk的驱动下出现在第二级寄存器的输出端,所以也不会出问题。(我不是很能理解);
    3. 毛刺只置位了第二级寄存器,丢了第一级寄存器,这几乎不可能,只要关键路径的时序满足了设计要求,那么可以在output输出empty,至少会持续一个rclk周期,知道下一次第一级寄存器输出为0,从而失效empty,所以这也不是问题;
    4. 最有可能的情况是毛刺被两级寄存器都捕获,并因为两级同步的关系,被有效了2个rclk周期(但是要避免亚稳态,下面会讨论),所以这也不是问题。

    针对上面四种场景,作者进一步说明的其中的一些时序考虑,如下:

    aempty_n的毛刺不会对同步寄存器有影响,因为它本身就是靠rclk驱动的(与同步寄存器属于同时钟域),就算有毛刺,也只能是在rclk上升沿之后产生,并且不会持续到下一个rclk到来。

    一个问题:假设写时钟的上升沿与读时钟的上升沿几乎在一起,并失效了aempty_n,导致第一级寄存器出现亚稳态,这会导致什么情况?

    移除第二级寄存器的置位信号会违背第二级寄存器的恢复时间,会不会导致第二级寄存器出现亚稳态?作者认为不会,如果置位信号使第二级寄存器输出为高了,那么它的输入端也必为高(置位和输入均与aempty_n有关),所以它不会因为恢复时间而导致输出状态的不确定,即亚稳态(这一点实际上理解不是很深,只能略有感性体会)。

    最后一个问题:一个毛刺,它失效于wclk的上升沿,与此同时,它失效时刻与第二级寄存器的rclk上升沿很接近,会不会导致第二级寄存器出现亚稳态?

    答案是不会,前提是aempty_n的关键路径满足时序要求。因为aempty_n拉低到稳定状态,肯定只在rclk的第一个上升沿和第二个上升沿之间,所以这个毛刺必然在第二个上升沿之前到来。PS:言外之意就是第二个寄存器不会产生亚稳态。

    同样可以这样分析full信号。

    4. 仿真

    本论文也给出了完整的源码,借用上一篇的测试程序,可以通过仿真图来理解上面分析的几个信号的关系。

  • 相关阅读:
    display:block;inline;inline-block大总结
    img图片inline-block总结
    定时器
    获取样式
    UmiJS
    vue 点击当前路由重新加载该路由
    Support for the experimental syntax 'decorators-legacy' isn't currently enab -- 装饰器@
    js 改变匹配到的字符串的颜色
    with
    页面从输入 URL 到页面加载显示完成
  • 原文地址:https://www.cnblogs.com/rouwawa/p/12436041.html
Copyright © 2020-2023  润新知