1.  异步FIFO的概念
异步FIFO为读取与写入采用不同的时钟,使用异步FIFO用于在不同的时钟域传输数据,主要用于跨时钟域传输多bit数据。

2.  异步FIFO的设计难点
同步异步信号,避免亚稳态数据的危害
设计合适的FIFO指针,判断FIFO满或者空状态。3.  同步FIFO的指针
同步FIFO有一个计数器用于计数存储的数目和读取的数目。当FIFO只有写操作没有读操作计数值增加,当FIFO只有读操作没有写操作的时候计数值减小,当没有读写操作或者同时在进行读写操作的时候计数值保持不变。当计数器的计数值达到FIFO的总长度的时候FIFO满,当计数值为0的时候那么FIFO空。
但是在异步FIFO设计中无法使用一个计数器来统计FIFO的数据的个数,因为两个异步的时钟需要去控制同一个计数器。因此在设计异步FIFO时候需要比较FIFO的读写指针位置。4.  异步FIFO的指针
异步FIFO的写指针总是指向下一个要被写入的地址,当复位或者清空时候读写指针都指向FIFO缓冲区的0地址。同样的读指针总是指向当前FIFO中要被读出的数据所在的地址,当清空或者复位是指针指向0,当发生一次读操作时读指针所指的地址的数据被取出,然后指针地址增加。
FIFO空的标志发生时是当读的指针和写的指针相等时。当读写指针复位到0的时候如清空FIFO等操作的时候,或者是当读的指针赶上了写指针。
FIFO满的标志也是当读指针和写指针相等的时候。当写指针已经环绕一周,然后追上读指针的时候。因此就存在一个问题当读写指针相等的时候如何判断是读空还是写满。
为了区分是读空还是写满,一种设计的方式是给读写指针添加一个额外的位。当写指针增加了以后超过了FIFO的存储空间的最后的地址,这时候指针自加就会使得额外添加的最高位翻转。同样的读指针也会进行相同的操作。因此当两个最高位是不同的时候就可以判断是写指针已经环绕追上了读指针,那么FIFO是处于写满状态,如果最高位是相同的那么是读指针追赶上了写指针,FIFO处于读空状态。


图1 添加MSB用于区分写满与读空5.  读写指针计数器设计
对于一个二进制计数器,当他的计数值从一个时钟域同步到另外一个时钟域的时候是危险的,因为可能存在n-bits数据同时变化的情况,如7计数到8对应的二进制是0111计数到1000,那么对应的所有的位均发生变化。
一种通用的解决FIFO计数器的问题的方法是使用格雷码进行计数,格雷码对于相邻的两个计数值只允许一个位发生变化。因此就解决了欲在同一个时钟边沿同步多个bits的问题。6.  格雷码计数器问题引入
考虑4位和3位的格雷码计数器如图 2。通过对二进制码的分析可以得出对于4位格雷码上半部分与下半部分是最高位反向其余位关于中点镜像。为了将4位的格雷码转化为3位的格雷码,同时使得最高位为附加位,用于区分写满与读空。我们希望4位格雷码的低3位重复第一部分的低3位,而不是关于中点的镜像。如果直接将下半部分的低3位格雷码编码改为上半部分的低3位一样的编码那么就不是真格雷码应为从7到8以及15到0时候会出现两bits发生变化。而真格雷码应该是在相邻的两个计数之间只有一个位发生变化。
图2 四位格雷码7.  格雷码计数器设计
格雷码计数器是不存在奇数长度的,因此设计出来的额FIFO的深度就是  。 二进制计数器咋每次自加都会检测是否为满或者空状态,从而保证不会出现溢出或者下溢。
在图 3所示的格雷码计数器中二进制计数器的低(n-1)位可以直接作为FIFO存储单元的地址指针,将二进制数转化为格雷码传输给另外一个时钟域。
图 3格雷码计数器8.  格雷码转二进制与二进制转格雷码
二进制B[n:0]转化为格雷码G[n:0]
G[n] = B[n]                       //保留最高位作为格雷码的最高位

G[n-1:0] = B[n-1:0]^B[n:1]  //次高位格雷码为二进制码的高位与次高位相异或其余类似

格雷码G[n:0]转化为二进制B[n:0]
B[n] = G[n]                        //保留最高位作为二进制码的最高位

B[n-1:0] = G[n-1:0]^B[n:1]  //次高位格雷码为二进制码的高位与次高位相异或其余类似

9.  FIFO实现
将地址指针转化为格雷码以后对于相邻的两个地址只有一个位数据发生变化,因此可以使用触发器来同步异步时钟的数据。  图4 FIFO结构框图10.满和空信号的生成

读空信号是在读时钟域生成的,从而保证能够实时的没有延迟的确定读空。当读空发生时是读指针追赶上写指针,两个指针值相同(包括扩展的最高位)。此时其格雷码也是相同的,因此设计相对简单。
在FIFO设计中写满信号是在写时钟域生成的,从而保证能够实时的没有延迟的确定写满。当写指针追赶上读指针的时候发生,此时两个指针的二进制计数器的低(n-1)位相同最高位不同。但是由于扩展了格雷码,而对于n位格雷码其(n-1)位是关于中间值镜像对称的。

图 5 有扩展位的格雷码编码
考虑图 5对于3位的格雷码地址添加一个附加位用于区分写满与读空成为4位的格雷码编码。当FIFO空时即读指针赶上写指针,此时两个格雷码完全相同(包括扩展位)。当FIFO写满时候需要考虑如下3个条件
1.  写指针的格雷码与同步到写时钟域的读指针格雷码的最高位不同
2.  写指针的格雷码与同步到写时钟域的读指针格雷码的次高位不相等
3.  写指针的格雷码与同步到写时钟域的读指针格雷码的其余位都相等11.不同的时钟速率同步的深入思考
当异步FIFO来同步两个不同的时钟域的时候,显然两个时钟的速度是不一样的,考虑当一个快的时钟域的信号同步到慢的时钟域的时候可能会存在计数值跳跃,因为在慢的时钟域的一个周期快的时钟域的计数值可能已经增加了多次了,因此就会导致如下的两个问题:
1.  在同步格雷码的时候如果格雷码的值增加了2个然而只采样了一次就会出现多个位的数据发生变化,这种情况下会导致多bit数据同步问题吗?
   答案是否定的。在同步多bit数据的时候当多个数据位在同步上升沿变化时会出现问题。但是对于快的时钟域的写指针的格雷码在一个时钟周期只改变一位,因此在慢的时钟域周围最多只会有一个位发生变化。
2.  在慢的时钟域一个周期里面快的时钟域的计数器可能已经增加了几个计数值了,那么会存在快的时钟域的已经从满状态增加到(满+1)的状态,而没能检测出满吗?
   答案是否定的,应为满状态是在写时钟域产生的,如果写的时钟比读取的时钟快,当写指针赶上从读时钟域同步过来的读指针后,满状态会马上置位,因此就不会出现溢出。
满与空状态能够准确的被置位,但是标志位清除有一定的延迟。
当我们在写时钟域产生FIFO满的状态,当写指针追赶上读指针的时候马上产生满标志,此时当读指针增长了以后FIFO就不再满了,但是写时钟域不能马上检测到读指针已经增加了,需要经过两个时钟周期,使得读指针的数据同步到写时钟域以后才能够清空满状态。这样能够保证FIFO不会溢出,相同的读FIFO也存在这样的问题。

Verilog源码:

/*异步fifo 参考文献  Simulation and SynthesisTechniques for Asynchronous FIFO Design*/

module async_fifo(

rst_n         ,

fifo_wr_clk   ,

fifo_wr_en,

r_fifo_full   ,

fifo_wr_data,

fifo_rd_clk   ,

fifo_rd_en,

fifo_rd_data,

r_fifo_empty

//     fifo_wr_err,

//     fifo_rd_err

);

input rst_n          ;

inputfifo_wr_en  ;

input  [15:0]fifo_wr_data;

inputfifo_rd_en  ;

inputfifo_rd_clk;

inputfifo_wr_clk;

output regr_fifo_full   ;

output[15:0]fifo_rd_data;

output regr_fifo_empty  ;

//     output regfifo_wr_err;

//     output regfifo_rd_err;

reg[9:0] rdaddress; //RAM地址为9位地址 扩展一位用于同步

reg[9:0] wraddress;

wire   [9:0]  gray_rdaddress;

wire   [9:0]  gray_wraddress;

/*同步寄存器*/

reg[9:0] sync_w2r_r1,sync_w2r_r2;

reg[9:0] sync_r2w_r1,sync_r2w_r2;

wirefifo_empty;

wirefifo_full;

/*二进制转化为格雷码计数器*/

assigngray_rdaddress = (rdaddress >>1) ^ rdaddress;//(({1'b0,rdaddress[9:1]}) ^rdaddress);

/*二进制转化为格雷码计数器*/

assigngray_wraddress = (({1'b0,wraddress[9:1]}) ^ wraddress);

assignfifo_empty = (gray_rdaddress == sync_w2r_r2);

assignfifo_full = (gray_wraddress == {~sync_r2w_r2[9:8],sync_r2w_r2[7:0]});

//

//     assignfifo_wr_err = (w_fifo_full && fifo_wr_en);

//     assignfifo_rd_err = (fifo_empty && fifo_rd_en);

ram  ram(

.data      (fifo_wr_data     ),

.rdaddress(rdaddress[8:0]),

.rdclock   (fifo_rd_clk  ),

.wraddress(wraddress[8:0]),

.wrclock   (fifo_wr_clk  ),

.wren      (fifo_wr_en   ),

.q         (fifo_rd_data)

);

/*在读时钟域同步FIFO空 sync_w2r_r2 为同步的写指针地址延迟两拍 非实际 写指针值 但是确保不会发生未写入数据就读取*/

always@(posedgefifo_rd_clk or negedge rst_n)

if(!rst_n)

r_fifo_empty<= 1'b1;

else

r_fifo_empty<= fifo_empty;

/*在写时钟域判断FIFO满 sync_r2w_r2 实际延迟两个节拍可能存在非满判断为满 但不会导致覆盖*/

always@(posedgefifo_wr_clk or negedge rst_n)

if(!rst_n)

r_fifo_full<= 1'b1;

else

r_fifo_full<= fifo_full;//格雷码判断追及问题

/*读数据地址生成*/

always@(posedgefifo_rd_clk or negedge rst_n)

if(!rst_n)

rdaddress<= 10'b0;

elseif(fifo_rd_en && ~fifo_empty)begin

rdaddress<= rdaddress + 1'b1;

end

/*写数据地址生成*/

always@(posedgefifo_wr_clk or negedge rst_n)

if(!rst_n)

wraddress<= 10'b0;

elseif(fifo_wr_en && ~r_fifo_full)begin

wraddress<= wraddress + 1'b1;

end

/*同步读地址到写时钟域*/

always@(posedgefifo_wr_clk or negedge rst_n)

if(!rst_n)begin

sync_r2w_r1<= 10'd0;

sync_r2w_r2<= 10'd0;

end elsebegin

sync_r2w_r1<= gray_rdaddress;

sync_r2w_r2<= sync_r2w_r1;

end

/*同步写地址到读时钟域, 同步以后 存在延迟两个节拍*/

always@(posedgefifo_rd_clk or negedge rst_n)

if(!rst_n)begin

sync_w2r_r1<= 10'd0;

sync_w2r_r2<= 10'd0;

end elsebegin

sync_w2r_r1<= gray_wraddress ;

sync_w2r_r2 <= sync_w2r_r1;

end

endmodule


转载自:

https://blog.csdn.net/u014070258/article/details/90052281

侵删。

74ls390设计任意进制计数器_异步FIFO:设计原理及Verliog源码相关推荐

  1. 74ls390设计任意进制计数器_利用数字频率合成技术设计高速任意波形发生器(上)...

    波形发生器为常用器件,正因如此,波形发生器具备较强现实意义.对于波形发生器,诸多朋友均存在一定兴趣.此外,小编在往期带来诸多波形发生器相关文章,热爱波形发生器的朋友可翻阅哦.本文中,小编对于波形发生器 ...

  2. 74ls390设计任意进制计数器,基于74LS192的任意进制计数器的设计

    基于74LS192的任意进制计数器的设计 [摘要]利用集成二.十进制计数器采用置数法.置零法设计任意进制计数器,分析设计方法,给出设计案例.以集成计数器74LS192为例,运用置零法和置数法设计八进制 ...

  3. 两片74161实现60进制_74LS161设计60进制计数器-数电课程设计

    计数器是一个用以实现计数功能的时序部件,它不仅可用来及脉冲数,还常用作数子系统的定时.分频和执行数字运算以及其它特定的逻辑功能. 计数器种类很多.按构成计数器中的各触发器是否使用一个时钟脉冲源来分,有 ...

  4. 使用74LS161设计任意进制计数器

    可预置的四位二进制同步计数器74LS161具有并行预置数据.清零.置数.计数和保持功能,并且有进位输出端,可以串接计数器使用.引脚排列如图7-1所示,功能表见7-2所示. 图7-1 74LS161引脚 ...

  5. verilog设置24进制计数器_任意进制计数器 || 反馈复位法 反馈置数法 || 超级重点 || 数电...

    任意进制计数器 || 反馈复位法 反馈置数法 || 超级重点 || 数电 前面介绍了4位二进制计数器和十进制计数器,但它们的计数长度.计数方式是固定的. 例如: 十进制计数器74160,其计数的模为1 ...

  6. 【verilog_8】: 设计60进制计数器,带异步复位、同步使能、同步装载、同步清零、同步置位

    1.设计60进制计数器,带异步复位.同步使能.同步装载.同步清零.同步置位 法一 author : Mr.Mao e-mail : 2458682080@qq.commodule cnt60x (in ...

  7. 设计60进制计数器,带异步复位、同步使能、同步装载、同步清零、同步置位

    设计60进制计数器,带异步复位.同步使能.同步装载.同步清零.同步置位 Design a modulus 60 counter, with asynchronous reset, synchronou ...

  8. 74161-可预置任意进制计数器(基于QuartusII实现)

    1. 使用74161设计一个可预置的任意进制计数器,使用QuartusII 完成创建工程.编辑电路图.编译,编辑波形文件仿真,记录波形并说明仿真结果,最后在FPGA上进行硬件测试. 原理:如图所示.预 ...

  9. 使用74LS160设计六进制计数器

    使用Mutisim12.0中的74LS160实现6进制计数器. 主要涉及到的内容: (1)任意进制计数器的转换 (2)实现逻辑器件的使用 (3)数码管使用 (4)显示译码器使用 (5)信号发生器XFG

最新文章

  1. 《深入理解Java虚拟机》笔记3
  2. Linux下的内存对齐函数
  3. 详细设计 存储分配_10k+点赞的 Spring Boot 后台管理系统竟然出了详细教程!爱了!...
  4. SQL Server Profiler (SQL跟踪器)的简单使用
  5. 新版kali安装beef-xss一大堆报错解决办法
  6. 使用 NetCoreBeauty 优化 .NET CORE 独立部署目录结构
  7. Java秒杀系统实战系列~RabbitMQ死信队列处理超时未支付的订单(转)
  8. 8位16进制频率计设计实验--VHDL
  9. 解决Linux下使用sqlplus不能使用上下键,退格键
  10. 开发基于大数据平台的搜索引擎
  11. Cplex20.1版本bin包Linux安装过程
  12. matlab 多维svm分类代码,SVM多分类(matlab)
  13. 网页中透明Flash的设置
  14. 顺式作用元件包括_顺式作用元件的结构组成
  15. 过程控制工程,离子膜烧碱一次盐水精制的膜过滤器压力控制
  16. python提醒事件_利用python实现短信和电话提醒功能的例子
  17. 广东某银行基于阿凡搭在信创环境下打造全行科技一体化服务平台
  18. appium Original error: Could not proxy command to the remote server. Original error: socket hang up
  19. halcon闭合轮廓线
  20. FTP主动模式和被动模式图解

热门文章

  1. 毕业,新的开始,撸起袖子加油干!
  2. Apriori算法通俗详解_fpgrowth_关联
  3. 超详细中文预训练模型ERNIE使用指南-源码
  4. 扩展LLVM:添加指令、内部函数、类型等
  5. YOLOV4知识点分析(一)
  6. 自动驾驶平台,阵营, 主要传感器与场景联系
  7. 自动驾驶的分级和行业现状
  8. 浅谈MySQL中utf8和utf8mb4的区别
  9. 员工信息管理系统java6_职工信息管理系统java源代码【可修改】.doc
  10. 欧拉定理 费马小定理