基本原理:

      1.读写指针的工作原理

  写指针:总是指向下一个将要被写入的单元,复位时,指向第1个单元(编号为0)。

  读指针:总是指向当前要被读出的数据,复位时,指向第1个单元(编号为0).

     2.FIFO的“空”/“满”检测

  FIFO设计的关键:产生可靠的FIFO读写指针和生成FIFO“空”/“满”状态标志。

  当读写指针相等时,表明FIFO为空,这种情况发生在复位操作时,或者当读指针读出FIFO中最后一个字后,追赶上了写指针时,如下图所示:

当读写指针再次相等时,表明FIFO为满,这种情况发生在,当写指针转了一圈,折回来(wrapped around)又追上了读指针,如下图:

为了区分到底是满状态还是空状态,可以采用以下方法:

  方法1:在指针中添加一个额外的位(extra bit),当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零。对读指针也进行同样的操作。此时,对于深度为2n的FIFO,需要的读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000~1000、1001~1111,MSB作为折回标志位,而低3位作为地址指针。

  • 如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。
  • 如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空;

      3.  二进制FIFO指针的考虑

  将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测。

使用gray码解决了一个问题,但同时也带来另一个问题,即在格雷码域如何判断空与满。

  对于“空”的判断依然依据二者完全相等(包括MSB);

  而对于“满”的判断,如下图,由于gray码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,除了MSB,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在gray码上判断为满必须同时满足以下3条:

  • wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次。
  • wptr与rptr的次高位不相等,如上图位置7和位置15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。
  • 剩下的其余位完全相等。

    5.总体实现

以上内容参考http://www.cnblogs.com/BitArt/archive/2013/04/10/3010073.html,非原创。

源码在原来的基础上进行改编,如下:

 module Asyn_FIFO(data_out, full, empty, data_in, wen, wclk, wrst,ren, rclk, rrst);
parameter datasize = ;
parameter addrsize = ; input [datasize-:]data_in;
input wen,ren,wclk,rclk,wrst,rrst;
output [datasize-:]data_out;
output empty,full; reg empty,full;
wire [datasize-:]data_out; wire [addrsize-:]raddr,waddr; //
wire [addrsize:]rbinnext,wbinnext,rptrnext,wptrnext;
wire empty_val,full_val;
reg [addrsize:]rbin,wbin,rptr,wptr,rptr1,rptr2,wptr1,wptr2;
reg [addrsize-:]memory[:(addrsize<<)-]; //双口RAM
assign data_out=memory[raddr];
always @(posedge wclk)
begin if(wen&&!full) memory[waddr]<=data_in;end //同步wptr指针
always @(posedge rclk or negedge rrst)
begin if(!rrst) {rptr2,rptr1}<=;
else {rptr2,rptr1}<={rptr1,wptr};
end //同步rptr指针
always @(posedge wclk or negedge wrst)
begin if(!wrst) {wptr2,wptr1}<=;
else {wptr2,wptr1}<={wptr1,rptr};
end //产生raddr信号和empty信号
always @(posedge rclk or negedge rrst)
begin if(!rrst) {rbin,rptr}<=;
else {rbin,rptr}<={rbinnext,rptrnext};
end
assign raddr=rbin[addrsize-:];
assign rbinnext=rbin+(ren&&~empty);
assign rptrnext=(rbinnext>>)^rbinnext; //生成raddr
assign empty_val=(rptrnext==rptr2);
always @(posedge rclk or negedge rrst)
begin if(!rrst) empty<=;
else empty<=empty_val;
end //产生waddr信号和full信号
always @(posedge wclk or negedge wrst)
begin if(!wrst) {wbin,wptr}<=;
else {wbin,wptr}<={wbinnext,wptrnext};
end
assign waddr=wbin[addrsize-:];
assign wbinnext=wbin+(wen&&~full);
assign wptrnext=(wbinnext>>)^wbinnext; //生成waddr
assign full_val=(wptrnext=={~wptr2[addrsize:addrsize-],wptr2[addrsize-:]});
always @(posedge wclk or negedge wrst)
begin if(!rrst) full<=;
else full<=full_val;
end
endmodule

Verilog学习笔记简单功能实现(八)...............异步FIFO的更多相关文章

  1. Verilog学习笔记简单功能实现(八)...............同步FIFO

    Part 1,功能定义: 用16*8 RAM实现一个同步先进先出(FIFO)队列设计.由写使能端控制该数据流的写入FIFO,并由读使能控制FIFO中数据的读出.写入和读出的操作(高电平有效)由时钟的上 ...

  2. Verilog学习笔记简单功能实现(二)...............全加器

    先以一位全加器为例:Xi.Yi代表两个加数,Cin是地位进位信号,Cout是向高位的进位信号.列表有:   Xi     Yi    Cin Sum Cout 0 0 0 0 0 0 0 1 1 0 ...

  3. Verilog学习笔记简单功能实现(六)...............计数分频电路

    在分频器电路中最重要的概念有两个:1)奇分频/偶分频:2)占空比. A)其中最简单的就是二分频电路,占空比为50%,其Verilog程序为 module half_clk(clr,clk_in,clk ...

  4. Verilog学习笔记简单功能实现(五)...............序列检测设计

    这里采用夏宇闻教授第十五章的序列检测为例来学习; 从以上的状态转换图可以写出状态机的程序: module seqdet(x,out,clk,rst); input x,clk,rst; output ...

  5. Verilog学习笔记简单功能实现(三)...............同步有限状态机

    在Verilog中可以采用多种方法来描述有限状态机最常见的方法就是用always和case语句.如下图所示的状态转移图就表示了一个简单的有限状态机: 图中:图表示了一个四状态的状态机,输入为A和Res ...

  6. Verilog学习笔记简单功能实现(一)...............D触发器

    module D_flop(data,clk,clr,q,qb); input data,clk,clr; output q,qb; wire a,b,c,d,e,f,ndata,nclk; nand ...

  7. Verilog学习笔记简单功能实现(四)...............译码器和编码器

    这里以简单的3-8译码器和8-3编码器为例: module decoder3_8(a,out); :]a; :]out; 'b1<<a;/*把最低位的1左移in位(根据in口输入的值)并赋 ...

  8. Verilog学习笔记简单功能实现(七)...............接口设计(并行输入串行输出)

    利用状态机实现比较复杂的接口设计: 这是一个将并行数据转换为串行输出的变换器,利用双向总线输出.这是由EEPROM读写器的缩减得到的,首先对I2C总线特征介绍: I2C总线(inter integra ...

  9. IIC驱动学习笔记,简单的TSC2007的IIC驱动编写,测试

    IIC驱动学习笔记,简单的TSC2007的IIC驱动编写,测试 目的不是为了编写TSC2007驱动,是为了学习IIC驱动的编写,读一下TSC2007的ADC数据进行练习,, Linux主机驱动和外设驱 ...

随机推荐

  1. salesforce 零基础学习(三十)工具篇:Debug Log小工具

    开发中查看log日志是必不可少的,salesforce自带的效果显示效果不佳,大概显示效果如下所示: chrome商城提供了apex debug log良好的插件,使debug log信息更好显示.假 ...

  2. java webservice 总结(学会读别人的webservice并且通过代理模式访问)

    公司做的系统之间的交互用到了webservice做交互,现在对webservice做一个总结. 1.配置已有的webservice webservice主要包括 xml/json:作为传输数据的格式 ...

  3. Java 7 中的Switch 谈 Java版本更新和反编译知识

    Java 7 中的Switch 谈 Java版本更新和反编译知识          学习编程,享受生活,大家好,我是追寻梦的飞飞.今天主要讲述的是Java7中的更新Switch实现内部原理和JAD反编 ...

  4. Android线程机制——AsyncTask

    对于Android为什么要使用多线程,因为从Android4.0之后,谷歌规定了网络操作不允许放在主线程中执行,由此就有了多线程的机制,有个JAVA学习经验的朋友一定知道多线程指的是什么,简单来讲就是 ...

  5. 微信开发 -- 搭建基于ngrok的微信本地调试环境

    第一步,安装ngrok客户端 (1)首先先到官网下载个客户端 http://natapp.cn/,选择适合的客户端类型,本人选择的是windows版 (2)下载后,解压,可以看到如下目录: 第二步,开 ...

  6. Razor基本语法

    前言: Razor引擎的核心是识别@符号及尖括号:    1.<...></...>    2.<.../>    [之所以说是"尖括号"而非& ...

  7. Sparse Filtering 学习笔记(三)目标函数的建立和求解

      Sparse Filtering 是一个用于提取特征的无监督学习算法,与通常特征学习算法试图建模训练数据的分布的做法不同,Sparse Filtering 直接对训练数据的特征分布进行分析,在所谓 ...

  8. 微信小程序中rpx与rem单位使用

    原作者: 小小小   来自: 授权地址 本文讲解rpx和rem应用于微信小程序,如果你还没有入门,建议先从下面看起: 微信小程序官方文档web app变革之remrpx单位官方文档rpx单位基础介绍 ...

  9. [git]merge和rebase的区别

    前言 我从用git就一直用rebase,但是新的公司需要用merge命令,我不是很明白,所以查了一些资料,总结了下面的内容,如果有什么不妥的地方,还望指正,我一定虚心学习. merge和rebase ...

  10. 使用php来访问操作sql server

    使用php来访问操作sql server 在此分成三步走: 第一部:查看配置,下载文件 首先查看自己的php和sql server版本 Php文件输入echo PHP_VERSION  运行脚本就可以 ...