转自http://ninghechuan.com

异步FIFO有两个异步时钟,一个端口写入数据,一个端口读出数据。通常被用于数据的跨时钟域的传输。

同步FIFO的设计。一个时钟控制一个计数器,计数器增加(只写不读),计数器减少(只读不写),计数器保持(不写不读)。计数器为0时,FIFO空,计数器为你定义的最大值,FIFO为满。貌似较容易设计。

很遗憾的是,异步FIFO并不能用这样的思想,因为异步FIFO有两个时钟,并没有办法控制一个计数器读写操作。只能分开读写计数器,通过比较读写指针的值来判断空满状态。

异步FIFO的读写指针

复位时,读写指针都为0。

写指针总是指向下一个要被写入的单元。复位时,写指针为0,所以指定的就是要被写入的0单元,当进行一次写操作,指针会自动加1,指向下一个要被写入的单元。

同样的,读指针总是指向当前要读的单元。复位时,读指针为0。当复位释放,这个时候如果有读使能读数据,是无效的,因为FIFO是空的。只有当写入数据后,FIFO空信号(empty)拉低时,才能读出有效的数据。

FIFO空满标志判断

当读指针和写指针相等的时候,可以认为FIFO空,认为是读指针追上了写指针,FIFO被读空了。当写指针追上读指针时,写数据比读数据快,并且写了一圈又写满了读空的一段,读写指针又相等。这样怎么能判断到底是FIFO满还是FIFO空呢?

通过读写指针位宽都多1bit的方法解决这个问题。读写指针最高位不会表示FIFO的地址深度,仅用来判断FIFO空满标志。即用N位标志读写指针的位宽,剩下的N-1 bit 表示FIFO读写深度。可以得出:

空标志:读指针等于写指针。

满标志:读指针和写指针的最高位不同,其余位相等。

if(waddr == raddr) -> empty
if({~waddr[N-1], waddr[N-2:0]} == raddr) -> full

FIFO的二进制读写指针考虑

异步FIFO的读写指针是在两个异步时钟下分别进行计数的,要判断空满标志就需要将两个指针进行比较,肯定需要将两个信号同步到一个时钟域下进行比较。这个过程是容易出现问题的,因为通常情况下的二进制计数器,可能是多个位同时变化的,例如从7-8(0111-1000)。同一个时钟沿同步多个信号可能会产生亚稳态。

采用Gray码(格雷码)可以解决这个问题,因为Gray码计数值增加,每次只变化一位。所以将一个地址指针转化为Gray后,再同步到另一个时钟域,进行比较得出空满信号。

二进制转换Gray码

assign  graydata = (bindata >> 1) ^ bindata;

FIFO设计框图

从上图可以看到最中间是这个FIFO的缓存部分用一个双口RAM可以实现。

左边的模块来产生FIFO的写指针和FIFO满标志,右边的模块来产生FIFO的读指针和FIFO空标志。

本设计中的FIFO 满标志在写时钟域下产生,这样在FIFO写满后能立即检测到并产生full标志。所以需要将读指针同步到写时钟域下进行比较。

FIFO空标志在读时钟域下产生,这样FIFO写空后能立即检测到并产生empty标志,所以需要将写指针同步到读时钟域下进行比较。

框图最下面有两个同步模块,便是实现读写指针的同步操作。

空满标志判断问题

前面说过判断空满标志的方法

空标志:读指针等于写指针。

assign	empty_val = (rd_cnt == wr_cnt_r);

always @(posedge rclk or negedge rst_n)begin
    if(!rst_n)
        fifo_empty <= 0;
    else
        fifo_empty <= empty_val;
end

满标志:读指针和写指针的最高位不同,其余位相等。

这种方法在二进制计数器下是完全没有问题的,但在格雷码表示下判断满标志就有问题了。如上图,四位格雷码,7(0_100)和8(1_100)的低三位是完全一样的,如果读地址为0_100,读地址为1_100,这个时候按照上文的说法,应该是FIFO写满了,但是真的是这样吗?这就是问题所在。

解决方法就是在判断FIFO满标志时,不仅判断最高位不同,次高位也应该不同,其余为相等,这个时候FIFO处于满状态。

根据四位格雷码可以推论出如上结论。

//assign full_val = ((wr_cnt[ADDR_SIZE] != rd_cnt_r[ADDR_SIZE]) && // (wr_cnt[ADDR_SIZE-1] != rd_cnt_r[ADDR_SIZE-1]) && // (wr_cnt[ADDR_SIZE-2:0] == rd_cnt_r[ADDR_SIZE-2:0])); //上一行代码可简化为 assign 	full_val = (wr_cnt == {~rd_cnt_r[ADDR_SIZE: ADDR_SIZE-1], rd_cnt_r[ADDR_SIZE-2:0]});

always @(posedge wclk or negedge rst_n)begin
    if(!rst_n)
        fifo_full <= 0;
    else
        fifo_full <= full_val;
end

解决了空满标志的这个棘手的问题,FIFO其余部分设计就可以随即设计,当然本设计仅为初学者学习,了解FIFO的基本原理。本文学习自Reference的这个paper,欢迎讨论交流。

代码博主自己尝试着写了一个,仿真了下修改了很多问题,但肯定有bug还没解决。

我放在Github上了,处于学习的学生朋友可以一起讨论。

https://github.com/NingHeChuan/Silicon_Peasant

Reference

Simulation and Synthesis Techniques for Asynchronous FIFO Design——Clifford E. Cummings, Sunburst Design, Inc.

Verilog设计异步FIFO的更多相关文章

  1. 异步fifo的设计

    本文首先对异步 FIFO 设计的重点难点进行分析 最后给出详细代码 一.FIFO简单讲解 FIFO的本质是RAM, 先进先出 重要参数:fifo深度(简单来说就是需要存多少个数据)           ...

  2. 异步fifo的Verilog实现

     一.分析 由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题,如何解决? 跨时钟域的问题:由于读指针是属于读时钟域的,写指针是属于写时钟域的,而异步FIFO ...

  3. 基于FPGA的异步FIFO设计

    今天要介绍的异步FIFO,可以有不同的读写时钟,即不同的时钟域.由于异步FIFO没有外部地址端口,因此内部采用读写指针并顺序读写,即先写进FIFO的数据先读取(简称先进先出).这里的读写指针是异步的, ...

  4. 异步fifo的设计(FPGA)

    本文首先对异步 FIFO 设计的重点难点进行分析 最后给出详细代码 一.FIFO简单讲解 FIFO的本质是RAM, 先进先出 重要参数:fifo深度(简单来说就是需要存多少个数据)           ...

  5. 异步FIFO总结+Verilog实现

    异步FIFO简介 异步FIFO(First In First Out)可以很好解决多比特数据跨时钟域的数据传输与同步问题.异步FIFO的作用就像一个蓄水池,用于调节上下游水量. FIFO FIFO是一 ...

  6. 怎么用Verilog语言描述同步FIFO和异步FIFO

    感谢 知乎龚大佬 打杂大佬 网上几个nice的博客(忘了是哪个了....) 前言 虽然FIFO都有IP可以使用,但理解原理还是自己写一个来得透彻. 什么是FIFO? Fist in first out ...

  7. 异步FIFO空满设计延迟问题

    由于设计的时候读写指针用了至少两级寄存器同步,同步会消耗至少两个时钟周期,势必会使得判断空或满有所延迟,这会不会导致设计出错呢? 异步FIFO通过比较读写指针进行满空判断,但是读写指针属于不同的时钟域 ...

  8. 异步FIFO及verilog原码

    这几天看了Clifford E. Cummings的两篇大作<Simulation and Synthesis Techniques for Asynchronous FIFO Design&g ...

  9. 异步FIFO的verilog实现与简单验证(调试成功)

    最近在写一个异步FIFO的时候,从网上找了许多资料,文章都写的相当不错,只是附在后面的代码都多多少少有些小错误. 于是自己写了一个调试成功的代码,放上来供大家参考. 非原创 原理参考下面: 原文 ht ...

随机推荐

  1. (网页)备注在HTML页面的放置的小技巧(title属性)

    其实很简单,就是title这个属性:(字符多余的剪切,title显示完整的字符) 下面是代码: <ul> <li title="江南style.江南style.江南styl ...

  2. MongoDB的基本操作:服务端启动,客户端连接,CRUD操作

    本文内容: MongoDB的介绍 MongoDB服务端的启动 MongoDB客户端连接 SQL与MongoDB相关概念解释 什么是BSON 数据库操作 集合操作 文档操作 测试环境:win10 软件版 ...

  3. 常见问题--post发送参数使用httpservletrequest读取为空

    1)springcloud项目中使用request.getparameter读取参数为空 原因:使用restcontroller导致,之前为controller.而通过requestbody注解封装为 ...

  4. 关于Natively Compiled Stored Procedures的优化

    Interpreted Transact-SQL stored procedures are compiled at first execution, in contrast to natively ...

  5. Vue延迟点击

    从点击屏幕上的元素到触发元素的 click 事件,移动浏览器会有大约 300 毫秒的等待时间 fastclick清除点击延迟,让程序更灵敏 1.导出fastclick import Vue from ...

  6. Linux 查看对外开放端口

    备忘命令: netstat -anpt | grep 514 # 查看 rsyslog tcp 端口是否开放 保持更新,转载请注明出处.

  7. Alpha版本 - 用户反馈

    Alpha版本 - 用户反馈 使用情况 (前天发出了内测apk给身边的人小范围使用,到目前共有31名用户使用过产品) 新增用户数: 用户事件数: Bug反馈 登录/注册出现"无响应" ...

  8. ubuntu服务器配置

    首先设置Ubuntu更新源 https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/ sudo cp /etc/apt/sources.list /etc/a ...

  9. Appium1.9.1 部署及结果检验

    1.官网下载最新的 appium 2.点击 Download Appium 3.选择适用于自己操作系统的版本,我的是 windows版本,就选择如下红圈起的 4.点击安装,一直点 下一步 直到提示安装 ...

  10. Python--详解Python中re.sub

    给出定义: re.sub(pattern, repl, string, count=0, flags=0) Return the string obtained by replacing the le ...