doc

两种异步FIFO的设计及verilog源代码

  • 1星
  • 日期: 2018-07-31
  • 大小: 53.5KB
  • 所需积分:1分
  • 下载次数:1
  • favicon收藏
  • rep举报
  • 分享
  • free评论

两种异步FIFO的设计及verilog源代码

文档内容节选

异步FIFO及verilog原码1 异步FIFO及verilog原码    这几天看了Clifford E Cummings的两篇大作Simulation and Synthesis Techniques for Asynchronous FIFO Designand Simulation and Synthesis Techniques for Asynchronous FIFO Design with Asynchronous Pointer Comparisons颇有感想,真可谓经典之作,不可错过       1什么是FIFO FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线 ,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地 址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某 个指定的地址   2什么情况下用FIFO FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端是AD数据采集,另一端是计 算机的PCI总线,假设其AD采集的速......

异步FIFO及verilog原码_1 异步FIFO及verilog原码    这几天看了Clifford E. Cummings的两篇大作《Simulation and Synthesis Techniques for Asynchronous FIFO Design》and 《Simulation and Synthesis Techniques for Asynchronous FIFO Design with Asynchronous Pointer Comparisons》颇有感想,真可谓经典之作,不可错过。       1.什么是FIFO? FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线 ,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地 址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某 个指定的地址。   2.什么情况下用FIFO? FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端是AD数据采集,另一端是计 算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32 bit,其最大传输速率为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设计的核心问题。由于同步FIF O几乎很少用到,这里只描述异步FIFO的空/满标志产生问题。在用到触发器的设计中, 不可避免的会遇到亚稳态的问题(关于亚稳态这里不作介绍,可查看相关资料)。 在涉及到触发器的电路中,亚稳态无法彻底消除,只能想办法将其发生的概率将到最低 。其中的一个方法就是使用格雷码。格雷码在相邻的两个码元之间只由一位变换(二进制 码在很多情况下是很多码元在同时变化)。这就会避免计数器与时钟同步的时候发生亚稳 态现象。但是格雷码有个缺点就是只能定义2^n的深度,而不能像二进制码那样随意的定 义FIFO的深度,因为格雷码必须循环一个2^n,否则就不能保证两个相邻码元之间相差一 位的条件,因此也就不是真正的各雷码了。 第二就是使用冗余的触发器,假设一个触发器发生亚稳态的概率为P,那么两个及联的触 发器发生亚稳态的概率就为P的平方。但这回导致延时的增加。亚稳态的发生会使得FIF O出现错误,读/写时钟采样的地址指针会与真实的值之间不同,这就导致写入或读出的 地址错误。由于考虑延时的作用,空/满标志的产生并不一定出现在FIFO真的空/满时才 出现。可能FIFO还未空/满时就出现了空/满标志。这并没有什么不好,只要保证FIFO不 出现overflow or underflow 就OK了。   很多关于FIFO的文章其实讨论的都是空/满标志的不同算法问题。   第一个算法:Clifford E. Cummings的文章中提到的STYLE #1,构造一个指针宽度为N+1,深度为2^N字节的FIFO(为便方比较将格雷码指针转换为 二进制指针)。当指针的二进制码中最高位不一致而其它N位都相等时,FIFO为满(在C lifford E. Cummings的文章中以格雷码表示是前两位均不相同,而后两位LSB相同为满,这与换成二 进制表示的MSB不同其他相同为满是一样的)。当指针完全相等时,FIFO为空。    这种方法思路非常明了,为了比较不同时钟产生的指针,需要把不同时钟域的信号同步 到本时钟域中来,而使用Gray码的目的就是使这个异步同步化的过程发生亚稳态的机率 最小,而为什么要构造一个N+1的指针,Clifford E. Cummings也阐述的很明白,有兴趣的读者可以看下作者原文是怎么论述的,Clifford E. Cummings的这篇文章有Rev1.1 \ Rev1.2两个版本,两者在比较Gray码指针时的方法略有不同,个Rev1.2版更为精简。 第二种算法:Clifford E. Cummings的文章中提到的STYLE #2。它将FIFO地址分成了4部分,每部分分别用高两位的MSB 00 、01、 11、 10决定FIFO是否为going full 或going empty (即将满或空)。如果写指针的高两位MSB小于读指针的高两位MSB则FIFO为“几乎满”,若 写指针的高两位MSB大于读指针的高两位MSB则FIFO为“几乎空”。 它是利用将地址空间分成4个象限(也就是四个等大小的区域),然后观察两个指针 的相对位置,如果写指针落后读指针一个象限(25%的距离,呵呵),则证明很可能要写 满,反之则很可能要读空,这个时候分别设置两个标志位dirset和dirrst,然后在地址 完全相等的情况下,如果dirset有效就是写满,如果dirrst有效就是读空。 这种方法对深度为2^N字节的FIFO只需N位的指针即可,处理的速度也较第一种方法快 。 异步FIFO及verilog原码_续 两篇文章的原码 //----------------------STYLE #1-------------------------- module fifo1(rdata, wfull, rempty, wdata, winc, wclk, wrst_n,rinc, rclk, rrst_n);       parameter DSIZE = 8;       parameter ASIZE = 4;       output [DSIZE-1:0] rdata;       output wfull;       output rempty;       input [DSIZE-1:0] wdata;       input winc, wclk, wrst_n;       input rinc, rclk, rrst_n;      reg wfull,rempty;   reg [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr;   reg [ASIZE:0] rbin, wbin;   reg [DSIZE-1:0] mem[0:(1<>1) ^ rbinnext; // 二进制码转换成为格雷码,经典 //--------------------------------------------------------------- // FIFO empty when the next rptr == synchronized wptr or on reset //---------------------------------------------------------------   assign rempty_val = (rgraynext == rq2_wptr);   always @(posedge rclk or negedge rrst_n)     begin       if (!rrst_n) rempty <= 1'b1;       else rempty <= rempty_val;     end //---------------wfull产生与waddr产生------------------------------ // GRAYSTYLE2 pointer    always @(posedge wclk or negedge wrst_n)    if (!wrst_n) {wbin, wptr} <= 0;    else {wbin, wptr} <= {wbinnext, wgraynext}; // Memory write-address pointer (okay to use binary to address memory)    assign waddr = wbin[ASIZE-1:0];    assign wbinnext = wbin + (winc & ~wfull);    assign wgraynext = (wbinnext>>1) ^ wbinnext; //------------------------------------------------------------------ // Simplified version of the three necessary full-tests: // assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) && // (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) && // (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0])); //------------------------------------------------------------------    assign wfull_val = (wgraynext=={~wq2_rptr[ASIZE:ASIZE-1],                        wq2_rptr[ASIZE-2:0]});     always @(posedge wclk or negedge wrst_n)      if (!wrst_n) wfull <= 1'b0;      else wfull <= wfull_val; endmodule //---------------------STYLE #2------------------------- module fifo2 (rdata, wfull, rempty, wdata,winc, wclk, wrst_n, rinc, rclk, rrst_n);       parameter DSIZE = 8;       parameter ASIZE = 4;   output [DSIZE-1:0] rdata;   output wfull;   output rempty;   input [DSIZE-1:0] wdata;   input winc, wclk, wrst_n;   input rinc, rclk, rrst_n;  wire [ASIZE-1:0] wptr, rptr;  wire [ASIZE-1:0] waddr, raddr;    async_cmp #(ASIZE) async_cmp(.aempty_n(aempty_n),                               .afull_n(afull_n),             .wptr(wptr), .rptr(rptr),             .wrst_n(wrst_n));       fifomem2 #(DSIZE, ASIZE) fifomem2(.rdata(rdata),                                     .wdata(wdata),                                       .waddr(wptr),               .raddr(rptr),                                       .wclken(winc),                .wclk(wclk));     rptr_empty2 #(ASIZE) rptr_empty2(.rempty(rempty),                                   .rptr(rptr),                                     .aempty_n(aempty_n),              .rinc(rinc),                                     .rclk(rclk),              .rrst_n(rrst_n));    wptr_full2 #(ASIZE) wptr_full2(.wfull(wfull),                                .wptr(wptr),                                 .afull_n(afull_n),             .winc(winc),                                  .wclk(wclk),             .wrst_n(wrst_n)); endmodule  module fifomem2 (rdata, wdata, waddr, raddr, wclken, wclk);     parameter DATASIZE = 8; // Memory data word width   parameter ADDRSIZE = 4; // Number of memory address bits   parameter DEPTH = 1<>1) ^ rbnext; // binary-to-gray conversion   always @(posedge rclk or negedge aempty_n)    if (!aempty_n) {rempty,rempty2} <= 2'b11;    else {rempty,rempty2} <= {rempty2,~aempty_n}; endmodule module wptr_full2 (wfull, wptr, afull_n, winc, wclk, wrst_n);   parameter ADDRSIZE = 4;   output wfull;   output [ADDRSIZE-1:0] wptr;   input afull_n;   input winc, wclk, wrst_n;   reg [ADDRSIZE-1:0] wptr, wbin;   reg wfull, wfull2;   wire [ADDRSIZE-1:0] wgnext, wbnext; //--------------------------------------------------------------- // GRAYSTYLE2 pointer //--------------------------------------------------------------- always @(posedge wclk or negedge wrst_n)   if (!wrst_n) begin    wbin <= 0;    wptr <= 0;    end   else begin    wbin <= wbnext;    wptr <= wgnext;    end //--------------------------------------------------------------- // increment the binary count if not full //---------------------------------------------------------------   assign wbnext = !wfull ? wbin + winc : wbin;   assign wgnext = (wbnext>>1) ^ wbnext; // binary-to-gray conversion   always @(posedge wclk or negedge wrst_n or negedge afull_n)    if (!wrst_n ) {wfull,wfull2} <= 2'b00;    else if (!afull_n) {wfull,wfull2} <= 2'b11;    else {wfull,wfull2} <= {wfull2,~afull_n}; endmodule   细心的读者会发现,第一种写法(本人做的修改)把所有信号写在同一个module里,而 第二种写法则分了很多模块。哪种写法更好呢?有兴趣的可以想一想,事实上,第二种 写法是推荐的写法:原因如下:     异步的多时钟设计应按以下几个原则进行设计: 1,尽可能的将多时钟的逻辑电路(非同步器)分割为多个单时钟的模块,这样有利于静 态时序分析工具来进行时序验证。 2,同步器的实现应使得所有输入来自同一个时钟域,而使用另一个时钟域的异步时钟信 号采样数据。 3,面向时钟信号的命名方式可以帮助我们确定那些在不同异步时钟域间需要处理的信号 。 4,当存在多个跨时钟域的控制信号时,我们必须特别注意这些信号,保证这些控制信号 到达新的时钟域仍然能够保持正确的顺序。
更多简介内容

推荐帖子

通信网络中的透传到底什么意思?
1、透传:指与传输网络的介质、调制解调方式、传输方式、传输协议无关的一种数据传送方式。 这就好比快递邮件,邮件中间有可能通过自行车、汽车、火车、飞机的多种组合运输方式到达您的手上,但您不用关心它们中间经历了哪些。 2、为什么要透传呢? 透传一般都是用来读取远程的串口数据。例如:网吧内每个上网者都要刷身份证才能上网,但身份证数据库不可能放在每个网吧内。所以就将读卡器的串口数据通过透传回传到
蓝先生 工控电子
LOTO课2:二极管实践 --- 桥式全波整流
实践用到的资源 4个整流二极管,500R的电阻(做负载),示波器,信号源 备注:阻值并不需要准确,这个电阻是作为负载使用的,阻值不能太大,太大的话会把电流限制到很小,可能让整流二极管截止,二极管焊接的时候注意极性。信号源要能产生正负2v以上频率50HZ的正弦交流信号 视频中使用OSC482S自带信号源模块产生正负2V的正弦波作为二极管桥式电路的输入,通
LOTO2018 移动便携
MSP430F149
本帖最后由 Jacktang 于 2020-5-9 23:04 编辑 基本信息 描述:16 位超低功耗微控制器、60kB 闪存、2KB RAM、12 位 ADC、2 USART、硬件乘法器 厂商:TEXAS INSTRUMENTS 器件类别: 微控制器 (MCU) 产品图片 MSP430 32kHz 晶体振荡器 (Rev. B) http://www.ti
Jacktang 【微控制器 MCU】
晒板子(Launchpad和Arduino)
本帖最后由 lcofjp 于 2020-5-21 23:07 编辑 今天收了俩快递,共五块板子。 买份凉皮肉夹馍庆祝一下,并且遇到流浪小喵。 什么是幸福?吃凉皮肉夹馍组合,喝着可乐(忘拍照了),玩着板子就是幸福:   点灯走起,来个hello world:   这块板子叫Grove Beginner Kit for Ardu
lcofjp DIY/开源硬件专区
【FAQ】RISC-V安全之地 |Microchip 安全解决方案系列研讨会 第4场
直播主题: RISC-V安全之地 |Microchip 安全解决方案系列研讨会 第4场   内容简介: MultiZone™ 安全性是 RISC-V 的首个 Linux® 安全之地。MultiZone 演示将展示如何保护混合关键系统的确定性行为,其中 Linux 和 实时系统在同一PolarFire®器件中。对于需要在不受信任的平台上进行可信工作负荷的安全关键型应用, Multi
EEWORLD社区 安防电子
【 ST NUCLEO-H743ZI测评】+ LIS25BA数据采集
本帖最后由 sylar^z 于 2020-5-24 00:36 编辑     这是在EE之前的活动中获得的ST骨振动传感器板子,可以采集说话时通过骨头震动传递的音频信号,不受环境中其他声源的影响。具体可以参看论坛的帖子(http://bbs.eeworld.com.cn/thread-1080360-1-1.html)。     在之前活动中,我分享过一篇基于NUCLEO-F7
sylar^z 【stm32/stm8】

评论

登录/注册

意见反馈

求资源

回顶部

datasheet推荐 换一换

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版 版权声明

北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved
$(function(){ var appid = $(".select li a").data("channel"); $(".select li a").click(function(){ var appid = $(this).data("channel"); $('.select dt').html($(this).html()); $('#channel').val(appid); }) })