官方论坛
官方淘宝
官方博客
微信公众号
点击联系吴工 点击联系周老师

2.4至简设计规范--明德扬科教(mdy-edu.com)

发布时间:2021-08-22   作者:admin 浏览量:
第二篇 FPGA至简设计原理

本文的文档编号:001500000080

需要看对应的视频,请点击视频编号:001500000089

1、本视频详细讲解了如何正确的看懂 信号波形


  第四章 FPGA至简设计法规范


第1节 波形图规则

    至简设计法曾在D触发器的相关知识讲解中,详细的描述了如何看FPGA信号的波形。针对波形的规则,只需记住一点:时钟上升沿看信号,看到的是信号变化前的值。这是什么意思呢?就是说在每一个时钟上升沿查看信号时,如果信号的值发生了改变,那么此时的信号值为信号改变前的值。还没有理解或者非常感兴趣的朋友,可以查找对应章节仔细学习相关内容。

    下面来举例说明一下,观察2.4-1中第4个时钟上升沿相应的信号变化可以看到在第4个时钟上升沿,信号a和信号c发生了改变。信号a1变为0,信号c0变为1,此时的信号值应该看变化前的值,因此在第4个时钟上升沿信号a的值为1,信号c的值为0。再来观察第5个时钟的上升沿,可以看出信号b和信号c发生了改变。同样的,此时信号值为变化前的值,即信号b的值为1,信号c的值也为1
                              

2.4-1波形图规则示例1

再来看2.4-2,在第5个时钟上升沿处观察信号dout和信号cnt的值。根据规则可知信号要取变化之前的值,即信号dout取值为1,同样的道理,信号cnt的取值同样为1,并不是2
2.4-2波形图规则示例2

    以上就是观察波形的规则,只要记住在不确定的信号处均选择前面的信号,就一定不会出错。当然,该方法的使用前提是所有信号都是同步信号且波形是理想的波形,不然一切都是空谈。该方法的具体原理解释可以参考学习至简设计法D触发器中波形查看的相关内容。

第2节 计数器规范

    计数器设计是FPGA设计的核心,计数器架构是FPGA设计最常用的架构之一,也是至简设计法的核心部分。计数器架构并不难,只要认真学习这部分内容,相信广大初学者也能掌握FPGA设计的精髓。本书在这里也会提供通过一些项目练习来进行巩固学习。

本章主要介绍至简设计法的计数器规则。

    下面是至简设计法的计数器模板样式,其包括三段:计数器的always语句,加1条件的定义以及结束条件的定义。

1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
always  @(posedge  clk or negedge rst_n)begin
  
     if(rst_n==1'b0)begin
  
cnt<= 0;
  
    end
  
    else if(加1条件) begin
  
        if(结束条件)
  
cnt<= 0;
  
        else
  
cnt<= cnt + 1;
  
    end
  
end
  
assign 加1条件 = ;
  
assign 结束条件 = 加1条件&&cnt==(计数个数)-1;

  
计数器规则1:计数器逐一考虑三要素,初值、加1条件和结束值;
  
  • 任何计数器都有三个要素:初值、加1条件和结束值。
  • 初值:计数器的默认值或者开始计数的值。
  • 加1条件:计数器执行加1的条件。
  • 结束值:计数器计数周期的最后一个值。
  • 设计计数器,要逐一考虑这三个要素,一般是先考虑初值、再考虑加1条件,最后再考虑结束值。


  
计数器规则2:计数初值必须为0
  
  • 计数器的默认值和计数器的初始值一定要为0,这是至简设计法规范的统一要求。众所周知,一般编程语言计数都是从0开始的,0计第1个数,1计第2个数,以此类推。至简设计法也参考这种做法,计数器从0开始进行计数。
  • 所有计数器都统一从0开始计数有助于同学们阅读理解、方便使用,如此一来,同学们不需要从头看具体代码就能清楚这个数值的含义。


  
计数器规则3:只有在加1条件有效时,才能表示计数器的计数值。
  
假定加1条件为add_cnt,计数器当前值为cnt,则
  • add_cnt&&cnt==x-1表示计数器计数到x个。
  • cnt==x-1不能表示计数器计数到x个。
计数器是从0开始计数的,因此计数器的默认值即初始值是0。那么当计数器的值为0时要如何区分这是开始计数的第1个值,还是并未计数的默认值呢?
这种情况下可以通过加1条件来进行区分。当加1条件无效时,计数器值为0表示未开始计数,此时的0为默认值;当加1条件有效时,计数器值为0表示计的第1个数。同理,当cnt==x-1,不能表示计数到x;只有当cnt==x-1且加1条件有效时,才表示计数到x。
因此,当add_cnt&&cnt==5-1时,表示计数到5个。而当add_cnt==0&&cnt==5-1时,不能表示计数到5个。

  
计数器规则4:结束条件必须同时满足加1条件,且结束值必须是x-1的形式;
  

计数器的结束条件必须同时满足加1条件。假定add_cnt为加1条件,cnt为当前计数器值,如果要计5个数,那么结束值应该是4,但是结束条件并不是cnt==4,而是add_cnt&&cnt==4。因为根据规则3可知cnt==4不能表示计数到5个,只有add_cnt&&cnt==4时,才表示计数到5个。
为了更好地阅读代码,至简设计法规定结束值必须是x-1的形式。即add_cnt&&cnt==4要写成add_cnt&&cnt==5-1。这里的“5”表示计数数量,“-1”则是固定格式。有了这个约定后计数的边界直观清晰。至简设计法多年的项目实践发现:无论多么有经验的工程师,对于边界值总会要多花一些心思来考虑。因此,至简设计法索性就制定了这个规则使得工程师不需要再考虑边界条件。

  
计数器规则5:当取某个数时,assign形式必须为:(加1条件)&&cnt==计数值-1);
  
当要从计数器取某个数时,例如要取计数器第5个数,很容易就写成cnt==5-1,这一写法是不正确的。正确的写法是(加1条件)&&(cnt==计数值-1),如add_cnt&&cnt==5-1。原因可以参考计数器规则3的说明。

  
计数器规则6:计数结束后,计数器的值必须恢复默认值0
  
每轮计数器周期结束后,计数器必须变回0,这是为了使计数器能够循环重复计数。

  
计数器规则7:若需要限定范围,推荐使用“>=”“<”两种符号;
  
边界值的设计通常都要花费一些心思,而且容易出错。为此,至简设计法规范约定,如果需要限定范围时,推荐使用“>=”和“<”两种符号。例如要取前8个数,那么就取cnt>=0&&cnt<8。注意,一定是“大于等于”和“小于”符号,而不能使用“大于”、“小于等于”符号。
该规则参考编程里的for循环语句。假如要循环8次,for循环的条件通常会写成“i=0;i<8;i++”,0为开始值,8为循环个数。当然,也可以写成“i=0;i<=7;i++”,但这些数字的意义就变得令人费解了,虽然知道7是从8-1得来的,但此时“-1”就显得画蛇添足,在设计中不必多此一举。

  
计数器规则8:设计步骤是,先写计数器的always段,条件用名字代替;然后用assign写出加1条件;最后用assign写出结束条件。
  
至简设计法规定计数器代码包括三段。
第一段,写出计数器的always段。
模板如下所示:
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
always  @(posedge clk or negedge  rst_n)begin
  
    if(rst_n==1'b0)begin
  
cnt<= 0;
  
    end
  
    else if(加1条件) begin
  
        if(结束条件)
  
cnt<= 0;
  
        else
  
cnt<= cnt + 1;
  
    end
  
end

同学们有没有发现上述模板的特点?这个模板只需要填两项内容:加1条件和结束条件。假定加1条件为add_cnt,结束条件为end_cnt,则代码变成:
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
always  @(posedge clk or negedge  rst_n)begin
  
    if(rst_n==1'b0)begin
  
cnt<= 0;
  
    end
  
    else if(add_cnt) begin
  
        if(end_cnt)
  
cnt<= 0;
  
        else
  
cnt<= cnt + 1;
  
    end
  
end

至此就完成了该always的设计,是不是很简单?只要确定好条件命名,就完成了这段设计代码。

第二段,用assign写出加1条件。

在此阶段,只需要确认好计数器的加1条件。假设计数器的加1条件为a=2,则代码为:
1
assign  add_cnt= a==2;

第三段,用assign写出结束条件。

在此阶段只需要确认好计数器的结束值。参考计数器规则5的要求,结束条件的形式一定是:(加1条件)&&cnt==计数值-1)。假设计数器的要计数10个,则代码为:
1
assign  end_cnt=  add_cnt&&cnt==10-1;

至此就完成了计数器代码的设计。回顾一下,这段代码特点就是:每次只考虑一件事,按照这一要求可以很容易地完成代码设计。

  
计数器规则9:加1条件必须与计数器严格对齐,其他信号一律与计数器对齐。
  
在设计中虽然对计数器进行编码,但一般计数器并不是最终目的,最终目的是各种输出信号。设计计数器是为了方便产生这些输出信号(包括中间信号),并且能够从计数器获取变化条件。例如信号dout在计数到6时拉高,则其变1条件是:add_cnt&&cnt==6-1。
假设有两个信号:dout0在计数到6时拉高,dout1在计数到7时拉高。一种设计方法是dout0的变1条件是add_cnt&&cnt==6-1,dout1的变1条件设定为dout0==1,这样dout1就是间接与计数器对齐。至简设计法不建议采用这种方法,在设计中建议信号一律与计数器对齐,dout1的变1条件应该改为:add_cnt&&cnt==7-1。

  
计数器规则10:命名必须符合规范,比如:add_cnt表示加1条件;end_cnt表示结束条件。
  
如无特别说明计数器的命名都要符合规范,加1条件的前缀为“add_”,结束条件的前缀为“end_”

  
计数器规则11:减1计数器暂时不用。
  
减1计数器在项目中应用也较为广泛。但至简设计法建议在学习阶段暂时不用减1计数器,进入公司或者已经在做项目的情况下根据公司具体要求而定。
以上就是至简设计法的计数器规则。计数看似简单,但要用好却并非易事。至简设计法强调,真正掌握计数器的使用需要多实践,至简设计法也会为提供大量的实践项目进行练习,从而让同学们掌握、搞透计数器的设计。


第3节 状态机规范

    状态机是数字电路设计中的一个非常重要组成部分,也是贯穿于整个设计始终的最基本设计思想和设计方法。在现代数字系统设计中状态机的设计对系统的高速性能、高可靠性、高稳定性都具有决定性的作用。熟练掌握状态机的设计后在数字电路的设计中必能达到事半功倍的效果。

前一节中介绍了计数器的规范。其实计数器本质上也可以认为是一个状态机,只不过计数器是用数字来区分不同状态而已。

那么在设计中什么时候使用计数器,什么时候会使用状态机呢?

如果是顺序处理或是简单的流程控制,例如其步骤是0->1->2->3->0,这个时候用计数器实现是最便捷的。但是在复杂的流程控制场合,例如其步骤是0->1->5->2->4,其跳转顺序是乱序的时候,就应该利用状态机来设计。
规范的状态机代码可以极大地提高设计效率,在减少状态出错可能的同时缩短调试时间,从而设计出稳健的系统。
至简设计法从项目实践和培训经验出发,总结出一套科学的、适用于状态机设计的方法,也称之为状态机架构八步法。

状态机架构八步法具有如下优点:
  •   通用的设计方法,无论是简单还是复杂的状态机均能按照此法进行设计;
  •   步骤清晰易懂,每步只考虑一个问题,易于掌握和使用;
  •   状态机代码严谨规范,不容易出错;
  •   设计出的状态机结构简单且稳健。


  
状态机规则1:使用四段式写法。
  
四段式不是指四段always代码,而是指四段程序。另外需要注意四段式的状态机并非一成不变,而是会根据输出信号的个数进行调整。四段式的写法可参照至简设计法GVIM特色指令Ztj产生的状态机模板。

第一段,同步时序的always模块,格式化描述次态迁移到现态寄存器。
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
always@(posedge clk or negedge rst_n)begin
  
     if(!rst_n)begin
  
state_c<= IDLE;
  
     end
  
     else begin
  
state_c<= state_n;
  
     end
  
end

第二段,组合逻辑的always模块,描述状态转移判断条件。注意,转移条件用信号来表示,信号名要按至简设计法规则来命名。
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
always@(*)begin
  
    case(state_c)
  
IDLE:begin
  
            if(idle2s1_start)begin
  
state_n = S1;
  
            end
  
            else begin
  
state_n = state_c;
  
            end
  
        end
  
        S1:begin
  
            if(s12s2_start)begin
  
state_n = S2;
  
            end
  
            else begin
  
state_n = state_c;
  
            end
  
        end
  
        S2:begin
  
            if(s22idl)begin
  
state_n = IDLE;
  
            end
  
            else begin
  
state_n = state_c;
  
            end
  
        end
  
default:begin
  
state_n = IDLE;
  
        end
  
endcase
  
end
  
  
assign idle2s1_start =  state_c==IDLE && ;
  
assign  s12s2_start  =state_c==S1   && ;
  
assign  s22idl_start  =state_c==S2   && ;

第三段,用assign定义转移条件。注意,条件一定要加上现态。
1
  
2
  
3
assign idle2s1_start = state_c==IDLE  && ;
  
assign s12s2_start  =state_c==S1   && ;
  
assign s22idl_start  =state_c==S2   && ;

第四段,设计输出信号。至简设计法规范要求一段always代码设计一个信号,因此有多少个输出信号就有多少段always代码。
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
always  @(posedge clk or negedge rst_n)begin
  
     if(!rst_n)begin
  
        out1 <=1'b0   
  
     end
  
     else if(state_c==S1)begin
  
        out1 <= 1'b1;
  
     end
  
     else begin
  
        out1 <= 1'b0;
  
     end
  
end


  
状态机规则2:四段式状态机第一段写法不变。
  

设计状态机时所有四段式状态机模板的第一段除了名字外的代码都可以直接用,不需要进行改动。

  
状态机规则3:第二段的状态转移条件用信号来表示。
  

设计状态机时,至简设计法要求四段式状态机的第二段中用信号名来表示转移条件,而无须直接写出具体的转移条件。
用信号名表示的好处是后续修改时只需改动信号的名字,并且方便根据状态机的命名修改对应的跳转条件。

  
状态机规则4:用assign将状态转移条件写成XX2XX_start的形式。
  

状态机规则3要求转移条件用信号名来表示,这样一来设计师就要编写很多信号名称,这也是设计师工作中的一大困扰。因此至简设计法制定此规则:将状态转移的条件信号用xx2xx_start的形式表示。

例如有三个状态IDLE、READ、WRITE,若从IDLE跳转到READ状态,其跳转条件可以命名为:idle2read_start;若从IDLE跳转到WRITE,其跳转条件可以命名为:idle2write_start。
这个命名方式既能够解决命名的困扰,又能直接从信号名看出信号的作用。至简设计法提出并主张所有信号都用对应意义的字母来命名,达到“见名知义”的效果。后续章节中还会提及至简设计法关于信号命名的规范,需要多加注意。

  
状态机规则5:assign定义状态转移条件信号时,必须加上当前状态。
  

状态机的第二段代码中使用信号名来表示转移条件,在代码后则需用assign对相应信号进行定义。注意,定义这个转移条件信号时必须加上当前状态,以避免因两个不同状态由同一种变化条件发生转移而导致错误。
例如:
1
  
2
  
3
assign idle2s1_start = state_c==IDLE  && XX;
  
assign s12s2_start  =state_c==S1   && XX;
  
assign s22idl_start  =state_c==S2   && XX;

  
状态机规则6:状态不变时使用state_n = state_c。
  

至简设计法项目和培训实践统计发现:编写状态机代码时有很大一部分错误是复制粘贴过程出错造成的,很多同学会出现复制其他状态的代码时忘记修改状态的错误。

此外,也有一部分同学写第二段状态机时,容易把状态保持不变写与state_n= state_n。这个写法是错误的,因为组合逻辑只有锁存器才能有保持电路,而数字电路中通常不希望出现锁存器。
为此,至简设计法规定,其四段式状态机的第二段,状态不变时使用state_n= state-_c。如下所示,可以自行对比。这样写不但可以减少出错的可能,还可以减少调试的时间。

1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
IDLE:begin
  
   if(idle2s1_start)begin
  
state_n = S1;
  
   end
  
   else begin
  
state_n = state_c;
  
   end
  
end
IDLE:begin
  
   if(idle2s1_start)begin
  
state_n = S1;
  
   end
  
   else begin
  
state_n = IDLE;
  
   end
  
end

第4节 接口规范

    在确定模块划分后需要明确模块的端口以及模块间的数据交互。至简设计法在实际项目经验中总结得出了一般模块端口的信号规范。完成项目模块划分后,可以在确定端口及数据流向时参考使用。

                                       表2.4- 1 端口信号规范
  
信号
  
说明
  
clk
  
模块工作时钟
  
rst_n
  
系统复位信号,低电平有效
  
en
  
en有两种用法:
  
1.使能命令信号,类似于vld,其值为1时表示一个命令有效;
  
2. 使能状态指示,其值为1时表示处于使能状态。
  
vld
  
数据有效标志指示信号,表示当前的data数据有效。注意,vld不仅表示了数据有效,而且还表示了其有效次数。时钟收到多少个vld=1,就表示有多少个数据有效
  
data
  
数据总线。输入一般名称为din,输出一般名称为dout。类似的信号还有addr,len等
  
err
  
整个报文错误指示,在eop=1且vld=1有效时才有效
  
sop
  
报文起始指示信号,用于表示有效报文数据的第一个数据,当vld=1时此信号有效
  
eop
  
报文结束指示信号,用于表示有效报文数据的最后一个数据,当vld=1时此信号有效
  
rdy
  
模块准备好信号,用于模块之间控制数据发送速度
  
例如模块A发数据给模块B,则
  
rdy信号由模块B产生,连到模块A(该信号对于B是输出信号,对于A是输入信号);
  
B要确保rdy产生正确,当此信号为1时,B一定能接收数据;
  
A要确保仅在rdy=1时才发送数据。



第5节 FIFO规范

FIFOFirst Input First Output),即先入先出队列。在计算机中先入先出队列是一种传统的按序执行方法,先完成并引退先进入的指令,随后跟着执行第二条指令(这些指令是指计算机在响应用户操作的程序代码,对用户而言是透明的)。

在数字电路设计中提到的FIFO实际是指FIFO存储器,其主要用于数据缓存和异步处理。当然FIFO存储器缓存数据也遵循先入先出的原则。由于微电子技术的飞速发展,新一代FIFO芯片容量越来越大,体积越来越小,价格越来越便宜。因其灵活、方便、高效的特性,FIFO芯片逐渐在高速数据采集、高速数据处理、高速数据传输以及多机处理系统中得到越来越广泛的应用。

FIFO本质是一个RAM,其与普通存储器的区别是没有外部读/写地址线,使用起来非常简单。但FIFO只能顺序的写入数据,再顺序的读出数据,其数据地址由内部读写指针自动加1完成,无法像普通存储器那样可以由地址线来对某个指定地址的数据进行读取或写入。

  
FIFO规则1:使用Show-ahead读模式。
  


FIFO读操作一般有两种使用模式:NormalShow-ahead模式。其中Normal模式是读使能有效后的下一拍读出相应数据,如下图所示。
2.4-3Normal模式时序图

Show-ahead模式是先进行数据输出,在读使能有效时对FIFO输出数据进行更新。即FIFO中的第一个数据输出在总线上,在读使能信号到来的下一拍直接输出第二个数据,如下图所示。
2.4-4Show-ahead模式时序图

至简设计法推荐使用Show-ahead模式,因为在这种模式下可以将读使能信号与读出数据当做有效信号和数据来使用,只要读使能有效则对应的数据就始终有效。

  
FIFO规则2:读写隔离规则。
  

     FIFO读写隔离规则是至简设计法经过长期的实践总结出来的经验规则。
读写隔离规则是指:FIFO的读、写控制是独立的,两者之间除了共用FIFO进行信息操作外,不能有任何信息传递。因此,既不能根据FIFO的读状态或读出的数据来决定写行为,也不能根据FIFO的写状态和写入的数据来决定读行为,如下图所示。
2.4-5读写隔离规则图
下面通过举例来帮助理解读写隔离规则。

假定需要设计一个模块将输入的报文保存到FIFO中,报文完整保存后再将其读出,并输给下游模块。那么如何确定何时才能保存完一个完整报文呢?可以知道收到din_eop时表示报文已经完整保存,那么能否可以使用din_eop作为读FIFO的开始条件呢?答案是不允许的。
如果以din_eop作为读开始的条件,如下图所示。先后输入一个6字节和3字节的报文,当收到第1个报文的din_eop时开始读FIFO数据并输出。由于输入数据量为6,则输出数据量也6,那么就要6个时钟来处理。然而在第2个报文的din_eop有效时,按照原理判断应该可以读取第2个报文并输出了,但是此时由于第1个报文还没有处理完,无法处理第2个报文,导致第2个报文被舍弃,数据出错。
2.4-6连续收到两个报文
可以看出不可以使用din_eop来作为读开始的条件,其根本的原因是:数据是要缓存后输出的,同样的,din_eop这个信号也需要缓存。

基于这一原因提出用双FIFO架构的概念,如图2.4-7。感兴趣的同学可以对至简设计法中双FIFO架构的具体介绍进行学习。
2.4-7FIFO架构

  
FIFO规则3:读使能必须判断空状态,并且用组合逻辑产生。
  

rdreq必须由组合逻辑产生,其原因与empty有关。下面来说明rdreq和empty的关系,假设FIFO存有3个字节数据,现采用Show-ahead模式对其进行读操作,将所存的所有数据读出来。相应信号波形下图所示。
2.4-8信号波形图

从图中可以看出在a时刻FIFO已经为空,但由于电路存在一定延时,empty变为高电平需要经历一段时间。

如果用时序逻辑产生rdreq,如图中虚线所示。在a时刻empty0则表示FIFO中还有数据(但实际已经为空),因此rdreq还要保持一个时钟周期,在FIFO为空的情况下要再读取一个数据,读操作就会出错。如果用组合逻辑产生rdreq,如图中实线所示。当empty1时,rdreq马上拉低则不会出现读取空FIFO这样的错误。

  
FIFO规则4:处理报文时,把指示信号与数据一起存入FIFO。
  

通过一个例子来说明该规则。现要求设计一个模块,需先将输入报文存储到内部FIFO中,等待适当时机将报文数据原封不动地送给下游模块。注意,传送时需要同时输出报文数据、报文头和报文尾指示信号,时序如下图所示。
图2.4-9报文输出输入时序

假定输入的报文din8’h128’h348’h568’h788’h9a,其中8’h12是报文头数据,8’h9a是报文尾数据。则输出的报文dout同样应为8’h128’h348’h568’h788’h9a,且8’h12是报文头数据,8’h9a是报文尾数据。
根据一般思路,可以生成一个8位宽度的FIFO,然后将din数据保存到FIFO中。读出FIFO的数据赋给dout。但是怎么产生dout_sopdout_eop信号呢?

实际上FIFO不仅可以保存“数据”,也可以保存“指示信号”,因此可以将数据和对应的“指示信号值”一起写入FIFO。如要生成一个10位宽度的FIFO,保存到FIFO的数据应是{din,din_sop,din_eop},如下图所示。
图2.4-10 FIFO作为报文传输缓存

FIFO写入的第1个数据是10’b0001001010,即第1个数8’h12以及此时的din_sop(值为1)和din_eop(值为0)。第2个数据是10’b0011010000,即第2个数8’h34以及此时的din_sop(值为0)和din_eop(值为0)。依此类推,最后一个数是10’b1001101001,即8’h9a以及此时的din_sop(值为0)和din_eop(值为1)。

利用该方法写入数据很容易产生dout_sopdout_eop信号。如果FIFO读出的数据最低位为1则表示这是报文的最后一个数据,此时dout_eop1;如果其次低位为1则表示这是报文的第一个数据,此时dout_sop1
此种方式还可以判断报文的开始和结束,从而用于其他判断。

  
FIFO规则4:读写时钟不同时,必须用异步FIFO。
  

FIFO按时钟分可以分为同步FIFO和异步FIFO。
同步FIFO:指读时钟和写时钟都相同的FIFO。同步FIFO内部没有异步处理,因此结构简单,资源占用较少。
异步FIFO是指读时钟和写时钟可以不同的FIFO。异步FIFO内部有专门的异步处理电路,处理读、写信号的交互,因此异步FIFO结构复杂,占用资源较大。
   拓展阅读