转自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. [iOS]深入理解GCD

    看到一篇很好的文章,本来想翻译的,但发现已经有人翻译了,遂简单整理了一下,方便阅读学习 新博客[wossoneri.com] 什么是GCD GCD(Grand Central Dispatch)是li ...

  2. SpringCloud+Feign环境下文件上传与form-data同时存在的解决办法

    最近项目转型使用SpringCloud框架下的微服务架构,各微服务之间使用Feign进行调用.期间,发现若被调用方法涉及到文件上传且仅存在单个文件时,一切正常,代码片段如下: @RequestMapp ...

  3. C#获取H5页面上传图片代码

    基于上一篇的H5压缩上传图片,由于图片是以二进制字符流blob的形式传过来的,所以应该想将其转成bytes类型再进行转换 public void ProcessRequest(HttpContext ...

  4. JS数组分组

    //1.找出数组中相同的元素 getRepeatNum(arr) { let obj = {}; for (let i = 0, len = arr.length; i < len; i++) ...

  5. 测试中Android与IOS分别关注的点

    主要从本身系统的不同点.系统造成的不同点.和注意的测试点做总结 1.自身不同点 研发商:Adroid是google公司做的手机系统,IOS是苹果公司做的手机系统 开源程度:Android是开源的,IO ...

  6. SQL Server 将一个表中字段的值复制到另一个表的字段中

    具体方法如下 一:update 表2 set (要插入的列名)= select 表1.某一列 from 表1 left jion 表2 on 表1和表2的关联 where ..... 二:update ...

  7. linux kernel 源码安装

    有时我们在安装系统后,发现没有安装当前系统的内核源码在/usr/src/kernels目录下,其实我们是少安装了一个rpm包: 当你配置好yum源后: yum install kernel-devel ...

  8. validator js验证器

    转自:https://github.com/jaywcjlove/validator.js 轻量级的JavaScript表单验证,字符串验证.没有依赖,支持UMD 导入js库 <script t ...

  9. Web服务并发I/O模型

    I/O模型: 阻塞型.非阻塞型.复用型.信号驱动型.异步 同步/异步: 关注消息通知机制 消息通知: 同步:等待对方返回消息 异步:被调用者通过状态.通知或回调机制通知调用者被调用者的运行状态 阻塞/ ...

  10. vsftpd不支持目录软链接的解决办法

    vsftpd本身不支持软连接,而在用FTP共享的时候又不想移动文件位置,便在网上找到了一个workaround: Linux内核从2..0开始支持把一部分文件系统挂载到文件系统中的其他位置,mount ...