作者:桂。

时间:2018-05-13  05:51:13

链接:http://www.cnblogs.com/xingshansi/p/9030879.html


前言

主要梳理FIFO的特性,fifo类似一个人的肚子,饿了就吃(write),吃完一段时间后就拉(read),,吃饱就满了(full),拉完就空了(empty)。

内容多参考他人,待消化吸收后重新完善。

参考:https://blog.csdn.net/houqi02/article/details/51683635

一、FIFO

  1.什么是FIFO?
  FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
  2.什么情况下用FIFO?
  FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端时AD数据采集,另一端时计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为1056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。另外对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。
  3.FIFO的一些重要参数
  FIFO的宽度:也就是英文资料里常看到的THE WIDTH,它只的是FIFO一次读写操作的数据位,就像MCU有8位和16位,ARM 32位等等,FIFO的宽度在单片成品IC中是固定的,也有可选择的,如果用FPGA自己实现一个FIFO,其数据位,也就是宽度是可以自己定义的。
  FIFO的深度:THE DEEPTH,它指的是FIFO可以存储多少个N位的数据(如果宽度为N)。如一个8位的FIFO,若深度为8,它可以存储8个8位的数据,深度为12 ,就可以存储12个8位的数据,FIFO的深度可大可小,个人认为FIFO深度的计算并无一个固定的公式。在FIFO实际工作中,其数据的满/空标志可以控制数据的继续写入或读出。在一个具体的应用中也不可能由一些参数算数精确的所需FIFO深度为多少,这在写速度大于读速度的理想状态下是可行的,但在实际中用到的FIFO深度往往要大于计算值。一般来说根据电路的具体情况,在兼顾系统性能和FIFO成本的情况下估算一个大概的宽度和深度就可以了。而对于写速度慢于读速度的应用,FIFO的深度要根据读出的数据结构和读出数据的由那些具体的要求来确定。
  满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。
  空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
  读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
  写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。
  读指针:指向下一个读出地址。读完后自动加1。
  写指针:指向下一个要写入的地址的,写完自动加1。
  读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。
  4.FIFO的分类
  根均FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。
  5.FIFO设计的难点
  FIFO设计的难点在于怎样判断FIFO的空/满状态。为了保证数据正确的写入或读出,而不发生益处或读空的状态出现,必须保证FIFO在满的情况下,不能进行写操作。在空的状态下不能进行读操作。怎样判断FIFO的满/空就成了FIFO设计的核心问题。由于同步FIFO几乎很少用到,这里只描述异步FIFO的空/满标志产生问题。
  在用到触发器的设计中,不可避免的会遇到亚稳态的问题(关于亚稳态这里不作介绍,可查看相关资料)。在涉及到触发器的电路中,亚稳态无法彻底消除,只能想办法将其发生的概率将到最低。其中的一个方法就是使用格雷码。格雷码在相邻的两个码元之间只由一位变换(二进制码在很多情况下是很多码元在同时变化)。这就会避免计数器与时钟同步的时候发生亚稳态现象。但是格雷码有个缺点就是只能定义2^n的深度,而不能像二进制码那样随意的定义FIFO的深度,因为格雷码必须循环一个2^n,否则就不能保证两个相邻码元之间相差一位的条件,因此也就不是真正的各雷码了。第二就是使用冗余的触发器,假设一个触发器发生亚稳态的概率为P,那么两个及联的触发器发生亚稳态的概率就为P的平方。但这回导致延时的增加。亚稳态的发生会使得FIFO出现错误,读/写时钟采样的地址指针会与真实的值之间不同,这就导致写入或读出的地址错误。由于考虑延时的作用,空/满标志的产生并不一定出现在FIFO真的空/满时才出现。可能FIFO还未空/满时就出现了空/满标志。这并没有什么不好,只要保证FIFO不出现overflow or underflow 就OK了。
  很多关于FIFO的文章其实讨论的都是空/满标志的不同算法问题。
  在Vijay A. Nebhrajani的《异步FIFO结构》一文中,作者提出了两个关于FIFO空/满标志的算法。
  第一个算法:构造一个指针宽度为N+1,深度为2^N字节的FIFO(为便方比较将格雷码指针转换为二进制指针)。当指针的二进制码中最高位不一致而其它N位都相等时,FIFO为满(在Clifford E. Cummings的文章中以格雷码表示是前两位均不相同,而后两位LSB相同为满,这与换成二进制表示的MSB不同其他相同为满是一样的)。当指针完全相等时,FIFO为空。这也许不容易看出,举个例子说明一下:一个深度为8字节的FIFO怎样工作(使用已转换为二进制的指针)。FIFO_WIDTH=8,FIFO_DEPTH= 2^N = 8,N = 3,指针宽度为N+1=4。起初rd_ptr_bin和wr_ptr_bin均为“0000”。此时FIFO中写入8个字节的数据。wr_ptr_bin =“1000”,rd_ptr_bin=“0000”。当然,这就是满条件。现在,假设执行了8次的读操作,使得rd_ptr_bin =“1000”,这就是空条件。另外的8次写操作将使wr_ptr_bin 等于“0000”,但rd_ptr_bin 仍然等于“1000”,因此FIFO为满条件。
  显然起始指针无需为“0000”。假设它为“0100”,并且FIFO为空,那么8个字节会使wr_ptr_bin =“1100”,, rd_ptr_bin 仍然为“0100”。这又说明FIFO为满。
  在Vijay A. Nebhrajani的这篇《异步FIFO结构》文章中说明了怎样运用格雷码来设置空满的条件,但没有说清为什么深度为8的FIFO其读写指针要用3+1位的格雷码来实现,而3+1位的格雷码可以表示16位的深度,而真实的FIFO只有8位,这是怎么回事?而这个问题在Clifford E. Cummings的文章中得以解释。三位格雷码可表示8位的深度,若在加一位最为MSB,则这一位加其他三位组成的格雷码并不代表新的地址,也就是说格雷码的0100表示表示7,而1100仍然表示7,只不过格雷码在经过一个以0位MSB的循环后进入一个以1为MSB的循环,然后又进入一个以0位MSB的循环,其他的三位码仍然是格雷码,但这就带来一个问题,在0100的循环完成后,进入1000,他们之间有两位发生了变换,而不是1位,所以增加一位MSB的做法使得该码在两处:0100~1000,1100~0000有两位码元发生变化,故该码以不是真正的格雷码。增加的MSB是为了实现空满标志的计算。Vijay A. Nebhrajani的文章用格雷码转二进制,再转格雷码的情况下提出空满条件,仅过两次转换,而Clifford E. Cummings的文章中直接在格雷码条件下得出空满条件。其实二者是一样的,只是实现方式不同罢了。
  第二种算法:Clifford E. Cummings的文章中提到的STYLE #2。它将FIFO地址分成了4部分,每部分分别用高两位的MSB 00 、01、 11、 10决定FIFO是否为going full 或going empty (即将满或空)。如果写指针的高两位MSB小于读指针的高两位MSB则FIFO为“几乎满”,
  若写指针的高两位MSB大于读指针的高两位MSB则FIFO为“几乎空”。
  在Vijay A. Nebhrajani的《异步FIFO结构》第三部分的文章中也提到了一种方法,那就是方向标志与门限。设定了FIFO容量的75%作为上限,设定FIFO容量的25%为下限。当方向标志超过门限便输出满/空标志,这与Clifford E. Cummings的文章中提到的STYLE #2可谓是异曲同工。他们都属于保守的空满判断。其实这时输出空满标志FIFO并不一定真的空/满。
  说到此,我们已经清楚地看到,FIFO设计最关键的就是产生空/满标志的算法的不同产生了不同的FIFO。但无论是精确的空满还是保守的空满都是为了保证FIFO工作的可靠。

Vijay A. Nebhrajani的这篇《异步FIFO结构》.PDF  

Clifford E. Cummings的文章 .PDF

、仿真

//==========================================
// Function : Asynchronous FIFO (w/ 2 asynchronous clocks).
//=========================================

`timescale 1ns/1psmodule aFifo#(parameter    DATA_WIDTH    = 8,ADDRESS_WIDTH = 4,FIFO_DEPTH    = (1 << ADDRESS_WIDTH))//Reading port(output reg  [DATA_WIDTH-1:0]        Data_out, output reg                          Empty_out,input wire                          ReadEn_in,input wire                          RClk,        //Writing port.     input wire  [DATA_WIDTH-1:0]        Data_in,  output reg                          Full_out,input wire                          WriteEn_in,input wire                          WClk,input wire                          Clear_in);/////Internal connections & variables//
    reg   [DATA_WIDTH-1:0]              Mem [FIFO_DEPTH-1:0];wire  [ADDRESS_WIDTH-1:0]           pNextWordToWrite, pNextWordToRead;wire                                EqualAddresses;wire                                NextWriteAddressEn, NextReadAddressEn;wire                                Set_Status, Rst_Status;reg                                 Status;wire                                PresetFull, PresetEmpty;//Code///
    //Data ports logic://(Uses a dual-port RAM).//'Data_out' logic:always @ (posedge RClk)if (ReadEn_in & !Empty_out)Data_out <= Mem[pNextWordToRead];//'Data_in' logic:always @ (posedge WClk)if (WriteEn_in & !Full_out)Mem[pNextWordToWrite] <= Data_in;//Fifo addresses support logic: //'Next Addresses' enable logic:assign NextWriteAddressEn = WriteEn_in & ~Full_out;assign NextReadAddressEn  = ReadEn_in  & ~Empty_out;//Addreses (Gray counters) logic:
    GrayCounter GrayCounter_pWr(.GrayCount_out(pNextWordToWrite),.Enable_in(NextWriteAddressEn),.Clear_in(Clear_in),.Clk(WClk));GrayCounter GrayCounter_pRd(.GrayCount_out(pNextWordToRead),.Enable_in(NextReadAddressEn),.Clear_in(Clear_in),.Clk(RClk));//'EqualAddresses' logic:assign EqualAddresses = (pNextWordToWrite == pNextWordToRead);//'Quadrant selectors' logic:assign Set_Status = (pNextWordToWrite[ADDRESS_WIDTH-2] ~^ pNextWordToRead[ADDRESS_WIDTH-1]) &(pNextWordToWrite[ADDRESS_WIDTH-1] ^  pNextWordToRead[ADDRESS_WIDTH-2]);assign Rst_Status = (pNextWordToWrite[ADDRESS_WIDTH-2] ^  pNextWordToRead[ADDRESS_WIDTH-1]) &(pNextWordToWrite[ADDRESS_WIDTH-1] ~^ pNextWordToRead[ADDRESS_WIDTH-2]);//'Status' latch logic:always @ (Set_Status, Rst_Status, Clear_in) //D Latch w/ Asynchronous Clear & Preset.if (Rst_Status | Clear_in)Status = 0;  //Going 'Empty'.else if (Set_Status)Status = 1;  //Going 'Full'.//'Full_out' logic for the writing port:assign PresetFull = Status & EqualAddresses;  //'Full' Fifo.always @ (posedge WClk, posedge PresetFull) //D Flip-Flop w/ Asynchronous Preset.if (PresetFull)Full_out <= 1;elseFull_out <= 0;//'Empty_out' logic for the reading port:assign PresetEmpty = ~Status & EqualAddresses;  //'Empty' Fifo.always @ (posedge RClk, posedge PresetEmpty)  //D Flip-Flop w/ Asynchronous Preset.if (PresetEmpty)Empty_out <= 1;elseEmpty_out <= 0;endmodule

空、满的核心思想是(空、满标志位的判定,结合了Gray code的特性,理论出自:Clifford E. Cummings的文章 .PDF,具体理论依据,待梳理。

    //'Quadrant selectors' logic:assign Set_Status = (pNextWordToWrite[ADDRESS_WIDTH-2] ~^ pNextWordToRead[ADDRESS_WIDTH-1]) &(pNextWordToWrite[ADDRESS_WIDTH-1] ^  pNextWordToRead[ADDRESS_WIDTH-2]);assign Rst_Status = (pNextWordToWrite[ADDRESS_WIDTH-2] ^  pNextWordToRead[ADDRESS_WIDTH-1]) &(pNextWordToWrite[ADDRESS_WIDTH-1] ~^ pNextWordToRead[ADDRESS_WIDTH-2]);

  这里仅仅是判定空、满标志位,理论上:

即可满足。且在此之前,已有:assign EqualAddresses = (pNextWordToWrite == pNextWordToRead);

上述的判定显得冗余?对应示意图:

基础007_FIFO原理相关推荐

  1. 画像的基础、原理、方法论(模型)和应用

    用户画像(User Profile)的本质是用户需求描述,一种刻画用户需求的模型. 用户画像在推荐系统.广告系统.商业分析.数据分析.用户增长.用户研究.产品设计.数据化运营.精准营销.量化风控等领域 ...

  2. linux系统基础与应用,Linux操作系统:基础、原理与应用

    <Linux操作系统:基础.原理与应用> 第1部分基础篇 第1章操作系统概述/3 1.1认识操作系统3 1.1.1操作系统的概念3 1.1.2操作系统的功能4 1.2操作系统的发展与现状5 ...

  3. Java基础-hashMap原理剖析

    Java基础-hashMap原理剖析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一.什么是哈希(Hash) 答:Hash就是散列,即把对象打散.举个例子,有100000条数 ...

  4. java原理教程,java基础之运行原理(一),java基础运行原理

    java基础之运行原理(一),java基础运行原理 java的核心配置:JDK JDK主要包括三个部分 1.Jre:java的运行环境 2.Java的工具:java的编译器(java.c.exe). ...

  5. Redis基础及原理详解

    Redis基础及原理详解 前言:以下是最近学习redis的一些笔记总结,文中如有不当的地方欢迎批评指正,重在记录与学习,笔芯~~ Nosql概述 演进历史 单机mysql Memcached(缓存)+ ...

  6. 用户增长的基础、原理和方法论

    用户增长(User Growth,UG)是指用户相关指标的增长. 用户增长的前提是你的产品是满足需求的,且与市场是匹配的,但到达用户存在阻碍.所以用户增长的主要工作就是要减少阻碍,降低交易成本(比如认 ...

  7. 机器学习,深度学习基础算法原理详解(图的搜索、交叉验证、PAC框架、VC-维(持续更新))

    机器学习,深度学习基础算法原理详解(图的搜索.交叉验证.PAC框架.VC-维.支持向量机.核方法(持续更新)) 机器学习,深度学习基础算法原理详解(数据结构部分(持续更新)) 文章目录 1. 图的搜索 ...

  8. 小白入门STM32(2)---控制SG90舵机---基础工作原理详解

    文章目录 序言 一.基础理论 1.1 舵机控制原理--PWM 习题 1.2 定时器 1.2.1 基础定时器 时钟装置 循环计数器 1.2.2 比较定时器 习题 二.实战上手 2.1 设置定时器和单片机 ...

  9. 计算机的编译原理pdf,计算机编程基础--编译原理.pdf

    第一章 引论(1) 1.1 什么叫编译程序 编译程序:是指这样的程序,它能够把某种 语言的程序转换成另一种语言的程序, 而后者与前者在逻辑上是等价的.如果 源语言是诸如FORTRAN.Pascal.C ...

最新文章

  1. 如何给a标签绑定ajax事件
  2. 三部排序|2013年蓝桥杯B组题解析第六题-fishers
  3. Asp.net使用代码修改配置文件的节点值
  4. Python-5-字符串方法
  5. java完整版记事本_求java记事本完整版
  6. 忘掉Java并发,先听完这个故事...
  7. 诛仙服务器显示横线,诛仙手游聊天颜色字体代码发送带颜色的字
  8. gdb 10.2的安装
  9. 11年潜心研究产品 全屋智能品牌Aqara终于要开发布会了
  10. ebook_7种开放式eBook格式指南
  11. 索尼机器狗Aibo将在美国开售,智能撒娇是最甜的 |每只性格都不同
  12. 阻塞非阻塞、同步异步
  13. linux下开源电子设计软件
  14. 浅谈摄某网绕过图片水印查看下载无水印图片
  15. SpringBoot 系列教程(九十二):Spring Boot全局设置Jackson时间处理
  16. java h5实现视频播放_Springboot项目使用html5的video标签完成视频播放功能
  17. 华为服务器故障灯不开机_华为手机开不了机指示灯亮怎么办?
  18. 2022下半年软考什么时候开始报名?
  19. 案例分享 | CEVA 使用 TensorFlow Lite 在边缘设备部署语音识别引擎及前端
  20. 微服务--应对每秒上万并发下的参数优化实战(实战经验)

热门文章

  1. matlab计算不同时间步长,Matlab ODE求解器中的时间步长计算
  2. 部署“极客猿导航geek-navigation遇到的问题”——作者没说但你就会遇到(1)
  3. 目标检测mAP计算详解
  4. 无人机开源项目_8个开源无人机项目
  5. zabbix5.0 High swap space usage ( less than 50% free)解决步骤。相关小知识:linux系统mem和swap的关系
  6. 有关字节型转换为浮点型
  7. 适用于WordPress的10个最佳白标签品牌插件
  8. 【Doris Weekly FAQ】2021.07.05~2021.07.18
  9. ff开发者必备插件列表
  10. 人工智能领域的会议和期刊