异步FIFO是一种先进先出电路,用在需要实时数据接口的部分,用来存储、缓冲在两个异步时钟之间的数据传输。异步FIFO与同步FIFO最大的不同在于异步FIFO读写时钟不同,通常异步FIFO用来做数据的时钟域转换,FIFO设计中难度最大的地方在FIFO的空满标识的产生,对同步FIFO来说,由于读写指针的增加时钟频率相同,因此读写指针可以直接进行比较产生出空满标志,而异步FIFO某由于读写两端时钟频率不同,读写指针需要进行时钟域转换后才能进行比较,也就是读时钟域的读地址要先转到写时钟域,然后与写时钟域的写地址进行比较,而实际这种比较时存在一定风险的。

异步FIFO设计一般的结构有:双口存储器、读地址产生逻辑、写地址产生逻辑、空/满标志产生逻辑四部分构成。图1是一种常用的异步FIFO设计方案,其中,读地址(rptr)和空标志(rempty)由读时钟

(rclk)产生,而写地址(wptr)和满标志(wfull)由写时钟(wclk)产生。把写地址与读地址相互比较以产生空/满标志。由于读写地址的变化由不同的时钟产生,所以对FIFO空或满的判断是跨时钟域的。如何避免异步传输带来的亚稳态以及正确地产生空/满标志是设计异步FIFO的难点。

图1

在设计时,需要弄清楚以下几个方面:

1.首先确定输入输出接口,异步FIFO在一个时钟域中进行写数据操作,而在另一个时钟域中进行读数据操作,所以在写数据模块,需要有写数据wdata,写时钟wclk,写复位wrst_n,写请求wreq,写满标志wfull;在读数据模块,需要有读数据rdata,读时钟rclk,读复位rrst_n,读请求rreq,读空标志rempty。其中rdata,rempty,wfull为输出信号,其余为输入信号。

其FIFO用来存储16*8数据(数据宽为8,数据深度为16)的顶层模块如下:

//异步FIFO缓存16*8数据,即数据宽度为8,深度为 16//

module

yibufifo(rdata,rempty,rrep,rclk,rrst_n,wdata,wfull,wrep,wclk,wrst_n);

input wclk,wrep,wrst_n;

input rclk,rrep,rrst_n;

input[7:0]wdata;

output[7:0]rdata;

output rempty,wfull;

wire wclk,wrep,wrst_n;

wire rclk,rrep,rrst_n;

wire [7:0]wdata;

wire [7:0]rdata;

wire [3:0]wptr,rptr;

wire [3:0]waddr,raddr;

wire aempty_n,afull_n;

ram i1(.wdata(wdata),//读写存储模块

.rdata(rdata),

.waddr(wptr),//地址与指针同步

.raddr(rptr),//

.wrep(wrep),

.wclk(wclk));

async_cmp i2(.aempty_n(aempty_n),//异步比较读写指针产生异步空满标志

.afull_n(afull_n),

.wptr(wptr),

.rptr(rptr),

.wrst_n(wrst_n));

rptr_empty2

i3(.rempty(rempty),//根据rclk产生读指针rptr和空标志rempty .rptr(rptr),

.aempty_n(aempty_n),

.rrep(rrep),

.rclk(rclk),

.rrst_n(rrst_n));

wptr_full2 i4(.wfull(wfull),//根据wclk产生写指针wptr和满标志wfull

.wptr(wptr),

.afull_n(afull_n),

.wrep(wrep),

.wclk(wclk),

.wrst_n(wrst_n));

endmodule

顶层模块图:

其中

2.1

读写地址产生逻辑(本设计中读写地址与读写指针同步)

读写地址线一般有多位,如果在不同的时钟域内直接同步二进制码的地址指针,则有可能产生亚稳态。例如,读指针从011变化到100时,所有位都要变化,读指针的每一位在读时钟的作用下,跳变不一致,即产生毛刺。如果写时钟恰好在读指针的变化时刻采样,得到的采样信号可能是000~111中的任何一个,从而导致空/满信号判断错误。由实践可知,同步多个异步输入信号出现亚稳态的概率远远大于同步一个异步信号的概率[3]。解决这一问题的有效方法是采用格雷码。格雷码的主要特点是相邻的两个编码之间只有一位变化。图2是格雷码产生的逻辑框图。在读使能或写使能信号有效、并且空/满标志无效的情况下,读写指针开始累加,进行FIFO读或写操作。二进制码与格雷码的转换是一个“异或”运算:gnext=(bnext>>1)^bnext。格雷码gnext

经寄存器输出格雷码指针ptr。这种方法采用了两组寄存器,虽然面积较大,但是有助于提高系统的工作频率。

图2

always @

(posedge rclk or negedge rrst_n)

begin

if(!rrst_n)

begin

rbin<=0;

rptr<=0;

end

else

begin

rbin<=rbnext;

rptr<=rgnext;

end

end

assign rbnext=!rempty?rbin+rrep:rbin;

assign

rgnext=(rbnext>>1)^rbnext;//二进制码转换成格雷码

always@(posedge wclk or negedge

wrst_n)

begin

if(!wrst_n)

begin

wbin<=0;

wptr<=0;

end

else

begin

wbin<=wbnext;

wptr<=wgnext;

end

end

assign wbnext=!wfull?wbin+wrep:wbin;

assign

wgnext=(wbnext>>1)^wbnext;//二进制码转换成格雷码

2.2 空/满标志产生逻辑

正确地产生空/满标志是设计任何类型FIFO的关键点。空/满标志产生的原则是:写满而不溢出,能读空而不多读。传统的异步FIFO把读写地址信号同步后再进行同步比较以产生空满标志,由于读写地址的每一位都需要两级同步电路,大量使用寄存器必然要占用很大的面积。这种方法不适合设计大容量的FIFO。当读、写指针相等也就是指向同一个内存位置时,FIFO可能处于满或空两种状态,必须区分FIFO是处于空状态还是满状态。传统的做法是把读、写地址寄存器扩展一位,最高位设为状态位,其余低位作为地址位。当读写指针的地址位和状态位全部吻合时,FIFO处于空状态;当读写指针的地址位相同而状态位相反时,FIFO处于满状态。传统的异步FIFO工作频率低、面积大。下面将介绍一种产生空/满标志的新方法。

采用象限比较法,先确定当前读写状态是快接近满了,还是快要接近空了。取读指针rptr和写指针wptr的最高两位,按其次序分为4个象限,显然当写指针滞后一个象限,并且当写使能,即复位信号wrst_n为1时,FIFO快要满了,在程序中用close_full_n(dirset)表示,当写指针超前一个象限时,FIFO快要空了,在程序中用close_empty_n(dirrst)表示。如图3所示:

图3

图4

用一个寄存器direction来寄存当前是否接近满空的状态,快接近满了则令direction=1;快接近空了则令direction=0;由于空/满标志产生的原则为:写满而不溢出,能读空而不多读,所以在其它情况下令direction=1,这样保证满标志不会出错,不会在快满时误以为未满而继续向FIFO写数据造成有效数据被覆盖。最后再由读写指针是否相同和direction一起来判断当前状态是满afull_n还是空aempty_n。

整个满空标志位的判断过程都使用组合逻辑,这样虽然读写时钟不一样,但是在读写指针发生变化时可以马上判断当前满空状态,之后再在读写时钟下清除写满wfull和读空rempty标志位,写满wfull要同步到写时钟域,而读空rempty要同步到读时钟域。写满wfull在afull_n变低时有效为1,在afull_n变高后的下一个时钟清除为0。读空rempty在aempty_n变低时有效为1,在afull_n变高后的下一个时钟清除为0。

根据图4可得:

wire

close_full_n=~((wptr[n]^rptr[n-1]) &

~(wptr[n-1]^rptr[n]));

wire close_empty_n=~((~(wptr[n]^rptr[n-1]) &

(wptr[n-1]^rptr[n])) |~wrst);

always @(posedge high or negedge dirset or negedge dirrst)

if (!close_empty_n) direction

<= 1′b0;

else if (!close_full_n) direction

<= 1′b1;

else direction <= high;

assign aempty=~((wptr==rptr) &&

!direction);

assign afull=~((wptr==rptr) &&

direction);

always @(posedge rclk or negedge aempty)

if (!aempty) {rempty,rempty2}

<= 2′b11;

else {rempty,rempty2} <=

{rempty2,~aempty};

always @(posedge wclk or negedge afull)

if (!afull) {wfull,wfull2} <=

2′b11;

else {wfull,wfull2} <=

{wfull2,~afull };

2.3

保守的空/满标志

设计中FIFO空/满标志的设置是保守的,即FIFO空/满标志的置位是立即有效的,而其失效则是在一段时间之后。例如一旦读指针追上写指针,就会立即声明一个低电平有效的异步空信号aempty。此信号会立即把图6所示的set触发器置位,使触发器输出为1,即向外部输出同步的空信号rempty,并且保证了FIFO一旦为空,读指针就不增加,避免了FIFO的读溢出。当写地址增加时,表明FIFO已经非空,空标志aempty由低变高,此时

可以进行安全的读操作。aempty信号的失效与写时钟同步。空信号rempty是在读时钟域中同步aempty信号得到的。由于同步器使用了两个触发器,因此空信号rempty的失效要经过至少两个时钟周期的延迟。所以,空信号的声明是及时的,而空信号的失效是保守的。也就是说,虽然FIFO已经非空了,但是空信号rempty要经过几个周期的延迟才能变为无效。满信号也有类似的情况。

虽然空/满标志的设置是保守的,但这并不影响FIFO功能的正确性,经验证保守的空/满标志能够满足FIFO的设计要求。

具体的各个模块程序如下:

读写存储模块RAM:

//异步FIFO缓存16*8数据,即数据宽度为8,深度为 16//

module ram(wclk,wrep,wdata,waddr,raddr,rdata);

input wclk,wrep;//读时钟,读使能

input [7:0]wdata;//写数据8位

input[3:0]waddr,raddr;//读写地址

output[7:0]rdata;

reg[7:0]fifomem[0:3];

//du

assign rdata=fifomem[raddr];

//xie

always@(posedge wclk)

begin

if(wrep)

fifomem[waddr]<=wdata;

end

endmodule

ram模块图如下:

异步比较读写指针产生异步空满标志async_cmp模块

//异步FIFO缓存16*8数据,即数据宽度为8,深度为 16//

module

async_cmp(aempty_n,afull_n,wptr,rptr,wrst_n);//异步比较产生空满信号

//parameter addrsize=4;

//parameter N=addrsize-1;//地址位宽

input wrst_n;//写复位

input [3:0]wptr,rptr;//读写指针

output aempty_n,afull_n;//空满标志

reg direction;// 用一个寄存器direction来寄存当前是否接近满空的状态

wire close_full_direction_n; //快接近满了,低电平有效

wire close_empty_direction_n;//快接近空了,低电平有效

assign

close_full_direction_n=~((wptr[3]^rptr[3-1])&~(wptr[3-1]^rptr[3]));

assign

close_empty_direction_n=~((~(wptr[3]^rptr[3-1])&(wptr[3-1]^rptr[3]))|~wrst_n);

always@( negedge close_full_direction_n or negedge

close_empty_direction_n)//低电平有效,用来判断direction

begin

if(!close_full_direction_n)

direction<=1'b1; //快接近满了则令direction=1;

else

if(!close_empty_direction_n)

direction<=1'b0;//快接近空了则令direction=0;

else

direction<=1'b1;// //所以在其它情况下令direction=1

end

assign

aempty_n=~((wptr==rptr)&&!direction);//几乎空信号产生

assign afull_n=~((wptr==rptr)&&

direction);//几乎满信号产生

endmodule

async_cmp模块图如下:

根据rclk产生读指针rptr和空标志rempty ,rptr_empty2模块

//异步FIFO缓存16*8数据,即数据宽度为8,深度为 16//

module rptr_empty2(rempty,rptr,aempty_n,rrep,rclk,rrst_n);

input rrep,rclk,rrst_n;//读时钟,读使能,读复位

input aempty_n;//空标志

output[3:0]rptr;//读指针

output rempty;//读空标志

reg[3:0]rptr,rbin;//读指针,读地址二进制

reg rempty,rempty2;

wire[3:0]rgnext,rbnext;//读格雷码地址,读二进制地址

always@(posedge rclk or

negedge rrst_n)

begin

if(!rrst_n)

begin

rbin<=0;

rptr<=0;

end

else

begin

rbin<=rbnext;

rptr<=rgnext;

end

end

assign rbnext=!rempty?rbin+rrep:rbin;

assign

rgnext=(rbnext>>1)^rbnext;//二进制码转换成格雷码

always@(posedge rclk or

negedge aempty_n)//读空标志的产生。用格雷码表示

begin

if(!aempty_n)

{rempty,rempty2}<=2'b11;

else

{rempty,rempty2}<={rempty2,~aempty_n};

end

endmodule

rptr_empty2模块图:

根据wclk产生写指针wptr和满标志wfull,wptr_full2模块

//异步FIFO缓存16*8数据,即数据宽度为8,深度为 16//

module wptr_full2(wfull,wptr,afull_n,wrep,wclk,wrst_n);

input wrep,wclk,wrst_n;//写时钟,写使能,写复位

input afull_n;//满标志

output[3:0]wptr;//写指针

output wfull;//写满标志

reg[3:0]wptr,wbin;//写指针,写地址二进制

reg wfull,wfull2;

wire[3:0]wgnext,wbnext;//写格雷码地址,写二进制地址

always@(posedge wclk or

negedge wrst_n)

begin

if(!wrst_n)

begin

wbin<=0;

wptr<=0;

end

else

begin

wbin<=wbnext;

wptr<=wgnext;

end

end

assign wbnext=!wfull?wbin+wrep:wbin;

assign

wgnext=(wbnext>>1)^wbnext;//二进制码转换成格雷码

always@(posedge wclk or

negedge afull_n)//写满标志的产生。用格雷码表示

begin

if(!afull_n)

{wfull,wfull2}<=2'b11;

else

{wfull,wfull2}<={wfull2,~afull_n};

end

endmodule

wptr_full2模块图如下:

测试程序:

module yibufifo_tb;

//parameter DSIZE = 8;

//parameter ASIZE = 4;

wire [7:0] rdata;

wire wfull;

wire rempty;

reg [7:0] wdata;

reg wrep, wclk, wrst_n;

reg rrep, rclk, rrst_n;

initial begin

wclk=0;

rclk=0;

wrst_n=0;

rrst_n=0;

wrep=1;

rrep=0;

wdata=0;

#30;

wrst_n=1;

rrst_n=1;

#300;

wrep=0;

rrep=1;

end

always #5 wclk=!wclk;//10ns

always #10 rclk=!rclk;//20ns

always @(negedge wclk)

wdata<=wdata+1;

yibufifo i1 (

.rdata (rdata ),

.wfull (wfull ),

.rempty (rempty ),

.wdata (wdata ),

.wrep (wrep ),

.wclk (wclk ),

.wrst_n (wrst_n ),

.rrep (rrep ),

.rclk (rclk ),

.rrst_n (rrst_n )

); endmodule

在modelsim中的仿真结果如下:

fifo的rdata_异步FIFO设计与实现相关推荐

  1. (87)FPGA面试题-同步FIFO与异步FIFO区别?异步FIFO代码设计

    1.1 FPGA面试题-同步FIFO与异步FIFO区别?异步FIFO代码设计 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-同步FIFO与异步FIFO区 ...

  2. Verilog实现FIFO专题5-异步FIFO设计(异步FIFO工作方式、异步FIFO介绍、异步FIFO介绍)

    FIFO根据输入输出时钟是否一致,分为同步FIFO与异步FIFO.同步FIFO中,读写控制信号以及数据均处于同一时钟域,满足STA分析时一般不会出现亚稳态等不稳定情形:而对于异步FIFO,读写相关信号 ...

  3. 基于FPGA的目标颜色识别追踪三——FIFO(同/异步FIFO)、DDR3

    FIFO在数据处理过程中是十分重要的. 同步FIFO比较简单,面试过程中手撕代码可能会用到. module sFIFO #(parameter DATA_WIDTH = 8,ADDR_WIDTH = ...

  4. fifo的rdata_同步FIFO设计

    本文从微信公众号--数字IC小站,​转载,欢迎关注,微信公众号更新更多更快带选通信号的同步FIFO(重发)​mp.weixin.qq.com ​我们常见的同步FIFO一般都是固定位宽输入,固定位宽输出 ...

  5. 74ls390设计任意进制计数器_异步FIFO:设计原理及Verliog源码

    1.  异步FIFO的概念 异步FIFO为读取与写入采用不同的时钟,使用异步FIFO用于在不同的时钟域传输数据,主要用于跨时钟域传输多bit数据. 2.  异步FIFO的设计难点 同步异步信号,避免亚 ...

  6. FPGA逻辑设计回顾(6)多比特信号的CDC处理方式之异步FIFO

    文章目录 前言 异步FIFO的概念 异步FIFO为什么可以解决CDC问题? 异步FIFO的RTL实现 参考资料 前言 异步FIFO是处理多比特信号跨时钟域的最常用方法,简单来说,异步FIFO是双口RA ...

  7. 各种FIFO硬件设计(FIFO概念、异步、同步、非2次幂深度FIFO)

    文章目录 一.FIFO概述 二.FIFO分类 三.FIFO重要信号与参数 3.1 信号 3.2 参数 3.2.1 data_depth的确定 四.FIFO存储原理 五.同步FIFO 5.1 空满信号判 ...

  8. IC设计 — 同步FIFO和异步FIFO设计实现(一)

    文章目录 1. FIFO介绍 1.1 FIFO参数 1.2 full/empty 检测 1.3 同步FIFO和异步FIFO 2. FIFO设计 2.1 二进制和格雷码 2.2 同步FIFO 2.3 异 ...

  9. 异步FIFO的设计详解(格雷码计数+两级DFF同步)

    文章目录 一.异步FIFO介绍 1.1.空满判断 1.2.跨时钟域问题 1.3.格雷码转换 1.4.格雷码计数器 二.代码code 一.异步FIFO介绍   FIFO有同步和异步两种,同步即读写时钟相 ...

  10. FPGA基础知识极简教程(4)从FIFO设计讲起之异步FIFO篇

    博文目录 写在前面 正文 同步FIFO回顾 $clog2()系统函数使用 综合属性控制资源使用 异步FIFO设计 FIFO用途回顾 异步FIFO原理回顾 异步FIFO设计 异步FIFO仿真 参考资料 ...

最新文章

  1. linux双机脚本pkg如何生效,linux里命令pkg config工具的使用
  2. python手机版编程-可以使用手机编程实现python吗
  3. Windows 2008 R2 Powershell 3.0
  4. [BZOJ3832][Poi2014]Rally
  5. 求求你!不要在网上乱拷贝代码了!一段网上找的代码突然炸了,项目出现大BUG...
  6. bootstrapV4.6.0内间距、外间距(官方hack类css代码)-解读篇
  7. 成功编译Webkit-cairo
  8. html几个数据包,报文和数据包的区别
  9. 大学生计算机科学项目,计算机科学学院喜获2018年大学生创新创业项目多个立项...
  10. haversine根据经纬度算距离
  11. linux下远程桌面连接工具,linux远程连接windows工具(tsclient 远程桌面)
  12. 【pytorch】轻量级网络ShuffleNet_V2原理及完整实现,对照结构图手动编写
  13. (转)中国IT界名人
  14. 抱抱脸(hugging face)教程-中文翻译-任务总结
  15. 绝佳的3Dmax渲染技巧,这些精美的效果让人称赞不已!速看
  16. 春夏秋冬又一春之Redis持久化
  17. 阵列麦克风声音定位-代码python实现-二维与三维声音定位
  18. linux的操作系统相关
  19. ubuntu 建立光纤连接
  20. 【直播干货】了解电商直播间的灯光问题

热门文章

  1. check exception和uncheck exception
  2. 小和尚打水问题_操作系统进程同步问题解析(哲学家问题、生产消费问题、小和尚打水问题等大量例子)...
  3. ps修改社保照片 不大于20KB
  4. 易地推拓客分享:内容获客是最稳定的获客方式之一
  5. 《毁灭杀手》(kkrieger)
  6. C# 阿拉伯数字转换为中文数字/中文数字转换为阿拉伯数字
  7. KiCad快速修改PCB线宽
  8. java web,添加删除文本框
  9. Java——Arrays 类
  10. win10绿联usb转串口_win10 usb转串口驱动-win10 usb转串口sb转驱动下载 PL2303 最新版 - 河东下载站...