文章目录

  • 1.异步FIFO设计难点
  • 2.空满标志
  • 3.格雷码的使用
  • 4.数据同步
  • 5.异步FIFO代码
  • 6.异步FIFO的测试点
  • 7.FIFO的深度如何计算

异步FIFO,读写应用不同的时钟,它有两个主要作用,一个是实现数据在不同时钟域进行传递,另一个作用是实现不同数据宽度的数据接口。
同步FIFO和异步FIFO的最主要的不同就体现在空满标志产生的方式上,由此引出两者一些不同的参数。

1.异步FIFO设计难点

异步FIFO的设计难点在于空满标志符的产生,由于异步FIFO的读写是用不同的时钟来控制的,所以不能用计数器的方法来产生空满标志符。

2.空满标志

我们知道FIFO的状态是满还是空,他们的相同的判断条件都是w_addr=r_addr,但到底是空还是满我们还不能确定。
我们设定一个指针r_pointer_bin,w_pointer_bin,宽度为[FIFO_addr_size:0],也就是说比传统的地址多一位,我们就用这多出来的一位做空满判断

如果是满状态的话,也就是说w_pointer_bin比r_pointer_bin多走了一圈,反应在数值上就是w_pointer_bin和r_point_bin的最高位不相同
如果是空状态的话,也就是说w_pointer_bin和r_pointer_bin的路径相同,反应在数值上就是w_pointer_bin和r_pointer_bin的每一位相等
FIFO_addr_size=2;FIFO_data_size=3;

3.格雷码的使用

将一个时钟域上的指针r_pointer_bin/w_point_bin同步到另一个时钟域,如果数据用二进制的方法进行同步的话就会出现多位数据同时跳变的问题。比如3’b011到3’b100即3到4跳变会引起多位数据的改变,这样会大大增加出错的概率。格雷码相邻数据只有一位跳变,这样就大大降低了数据出错的概率。
格雷码只有满足2n 个数,才可以形成循环,否则会导致相邻位不止一位发生变化。这也就是使用格雷码作为读写指针时,FIFO的深度必须为2n 。有的时候宁愿浪费一点空间,也要将深度设为2n
也就是说,深度为2^n 的异步FIFO,读写指针的宽度应该为(n+1)位。

  • 空标志:读写指针所有位均相同
  • 满标志:读写指针最高位不同,次高位不同,其他位相同

4.数据同步

因为满状态以后数据就不能进行写入,空状态以后数据就不能进行读出。由此,我们在write模块进行满状态的判断,在read模块进行空状态的判断
首先我们要明白,读写指针受不同的时钟控制,假如你把写指针同步到读指针时钟域中去判断满,行不行?不行,假如加入此时你判断了为满(最高位和次高位不同,其他位相同),控制FIFO不要再写了。但你注意了,此时写指针在经过两级触发器同步到读时钟域的过程中,写指针它在写时钟域中还进行了至少两次的写操作(一般写时钟更快),这就造成了FIFO的溢出。
所以需要做:

  • 满标志:将读指针同步到写时钟域
  • 空标志:将写指针同步到读时钟域
    为了避免亚稳态,选择两级D触发器相串联构成同步模块,来传递指针信号,在用于数据同步的这两拍里面有可能再进行读操作,所以用于比较时的读地址一定小于或等于当前的读地址,就算此刻产生full信号,其实FIFO有可能还没有满。这也就为设计留了一些设计的余量。同理,就算有empty信号的产生,FIFO有可能还有数据。这种留余量的设计在实际的工程项目中是很常见的。

5.异步FIFO代码

module asy_fifo#(parameter  WIDTH=8,//FIFO的位宽parameter  DEEPTH=32,//FIFO的深度parameter  POINTER_WIDTH=5,//读写地址指针,指针向高位扩展一位parameter  ADDR_WIDTH=4//读写地址的位宽)(empty,full,r_data,w_clk,w_rstn,w_en,w_data,r_clk,r_rstn,r_en);output     empty,full; //FIFO生成的空满信号
output reg [WIDTH-1:0] r_data;//从FIFO中读出的数据
input      w_clk,w_rstn;//读时钟域时钟、读时钟域复位信号
input      w_en;//读操作使能信号
input      [WIDTH-1:0] w_data;//向FIFO中写入的数据
input      r_clk,r_rstn;//写时钟域时钟、写时钟域复位信号
input      r_en;//写操作使能信号//定义:FIFO的buffer
reg        [WIDTH-1:0] fifo_mem [0:DEEPTH-1];//定义:FIFO的读写指针
reg        [POINTER_WIDTH-1:0] w_pointer,r_pointer;//定义:FIFO内数据对应的存取地址
wire       [ADDR_WIDTH-1:0]w_addr,r_addr;//定义:转换为格雷码的指针
wire       [POINTER_WIDTH-1:0] w_gray_pointer;
wire       [POINTER_WIDTH-1:0] r_gray_pointer;//定义:指针经过两级触发器同步时的指针
reg        [POINTER_WIDTH-1:0] w_pointer_d1,w_pointer_d2;
reg        [POINTER_WIDTH-1:0] r_pointer_d1,r_pointer_d2;//===========写时钟域========
//写时钟域内,写数据进FIFO,并将写指针加1
assign  w_addr = w_pointer[POINTER_WIDTH-2:0];
always@(posedge w_clk or negedge w_rstn)beginif( w_en & (!full) ) beginfifo_mem[w_addr] <= w_data;  end
end//写指针计数器
always@(posedge w_clk or negedge w_rstn) beginif(!w_rstn) begin    w_pointer <= 0;endelse if(w_en & (!full)) beginw_pointer <= w_pointer + 1;  endelse beginw_pointer <= w_pointer; end
end
//==========================//===========读时钟域========
//读时钟域内,把FIFO内的数据取出,并将读指针加1
assign  r_addr = r_pointer[POINTER_WIDTH-2:0];
always@(posedge r_clk or negedge r_rstn)beginif(!r_rstn) beginr_data <= 'h0;endelse if( r_en & (!empty) ) beginr_data <= fifo_mem[r_addr] ;end
end//读指针计数器
always@(posedge r_clk or negedge r_rstn)beginif(!r_rstn) beginr_pointer <= 0;endelse if( r_en & (!empty) ) beginr_pointer <= r_pointer + 1 ;endelse beginr_pointer <= r_pointer;  end
end
//==========================//===========指针同步======
//将格雷码写指针同步到读时钟域//1.将写指针转换为格雷码的形式
assign w_gray_pointer = w_pointer^(w_pointer >> 1);//2.再将转换后的指针经过两级触发器同步
always@(posedge r_clk or negedge r_rstn) beginif(!r_rstn)begin{w_pointer_d1,w_pointer_d2} <= 0;endelse begin{w_pointer_d2,w_pointer_d1} <= {w_pointer_d1,w_gray_pointer};end
end//将格雷码读指针经过两级触发器同步到写时钟域//1.将读指针转换为格雷码的形式
assign r_gray_pointer = r_pointer^(r_pointer >> 1);//2.再将转换后的指针经过两级触发器同步
always@(posedge w_clk or negedge w_rstn) beginif(!w_rstn) begin{r_pointer_d1,r_pointer_d2} <= 0;endelse begin{r_pointer_d2,r_pointer_d1} <= {r_pointer_d1,r_gray_pointer};end
end
//==========================//判断空满
assign full = ((r_pointer_d2[POINTER_WIDTH-1] != w_gray_pointer[POINTER_WIDTH-1]) && //最高位不同(r_pointer_d2[POINTER_WIDTH-2] != w_gray_pointer[POINTER_WIDTH-2]) && //次高位不同(r_pointer_d2[POINTER_WIDTH-3:0] == w_gray_pointer[POINTER_WIDTH-3:0])//其他低位相同);
assign empty = (w_pointer_d2 == r_gray_pointer);endmodule

测试代码:

`timescale 1ns/10ps
module TB;parameter  WIDTH=8;wire       empty,full;
wire       [WIDTH-1:0] r_data;
reg        w_clk,w_rstn;
reg        w_en;
reg        [WIDTH-1:0] w_data;
reg        r_clk,r_rstn;
reg        r_en;asy_fifo dut(.empty(empty),.full(full),.r_data(r_data),.w_clk(w_clk),.w_rstn(w_rstn),.w_en(w_en),.w_data(w_data),.r_clk(r_clk),.r_rstn(r_rstn),.r_en(r_en));//产生写时钟,100MHzinitial begin w_clk <= 0;forever begin#5 w_clk <= !w_clk;endendinitial begin #10 w_rstn <= 0;repeat(10) @(posedge w_clk);#10 w_rstn <= 1;end //产生读时钟,50MHz  initial begin r_clk <= 0;forever begin#5 r_clk <= !r_clk;endendinitial begin #10 r_rstn <= 0;repeat(10) @(posedge w_clk);r_rstn <= 1;end initial begin
#10 w_en =  1'b1;w_data = #(0.01) $random;repeat(5) begin@(posedge w_clk);w_data = #(0.01) $random;    end@(posedge w_clk);w_en = 1'b0;w_data = #(0.01) $random;#20 r_en = #(0.01) 1'b1; repeat(5) begin@(posedge r_clk);end@(posedge r_clk);r_en = 1'b0;    #20 w_en = 1'b1;  repeat(20) begin@(posedge w_clk);  w_data = #(0.01) $random;end@(posedge w_clk); w_en =  1'b0;w_data = #(0.01) $random;r_en = #(0.01) 1'b1; repeat(20) begin@(posedge r_clk);end
#50  $finish();
endendmodule

6.异步FIFO的测试点

有两个一级测试点:
1.FIFO的基本功能;2.异步处理
1.FIFO的基本功能测试包括:

  • 检查端口时序
    1.检查数据是否在wclk的上升沿并且wr为高时被写入
    2.检查数据是否在rclk的上升沿且rd为高时读出
  • 数据一致性。先写后读,检查是否能按先入先出的顺序读出
  • 空满信号能不能正确生成。先连续的写,再连续的读,检查空满信号是否准确生成
  • 读写指针有没有做空满限制。当FIFO满时,外部有没有做保证写指针不会增加;当FIFO空时,读指针是否还在增加
  • 检查复位信号,各个寄存器和信号是否能被正常复位,复位释放后信号的初始值是否正常
  • 读写指针转换为格雷码的逻辑检查
    2.异步处理
  • 读写指针跨时钟域传输时,有没有做同步处理
  • FIFO的读写时钟频率差速的难受力。检查读快写慢、写慢读快一定周期后,FIFO是否还能保持稳定

7.FIFO的深度如何计算

设计一个同步FIFO,每100个时钟周期可以写80个数据,每10个周期可以读8个数据,FIFO的深度为多少?
首先我们要确定最极端的情况,也就是FIFO的Burst 会写了多少个数据,这种情况是,前100个时钟周期,数据在后80个周期内发生了连续的写操作,在后100个时钟周期内,数据在前80个周期写入。这就造成了,数据突发长度160

  • 数据突发长度(B)为:B=160
  • 写入B长度所需的时间:T = (1/fwr)*160
  • 从FIFO中读出一个数据所需的时间:t=(1/frd)10/8
  • 在T时间读走的数据量:T/t= 160* (frd/fwr)(8/10)
  • FIFO的深度:160 - 160* (frd/fwr)(8/10)
    因为是同步FIFO,所以frd/fwr = 1,代入得 深度为32。

由此我们可以推出FIFO的计算公式:
B-B*(frd/fwr)*(x/y)
B为突发长度;frd为读效率;fwt为写频率;x/y读出效率,即y个时钟周期有x个数据读出

参考:
https://blog.csdn.net/SummerXRT/article/details/117814863

异步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. 异步FIFO代码(包含almost_full以及almost_empty信号),测试代码,功能仿真结果

    更新一波代码以及测试,之前的输出没有用寄存器输出. 这次改进的代码加入了将满almost_full以及将空almost_empty信号 Verilog代码 module async_FIFO_01 # ...

  3. 异步FIFO设计:各个模块的作用及Verilog代码详解

    实现原理参考:异步FIFO---Verilog实现_alangaixiaoxiao的博客-CSDN博客_异步fifo 代码参考:IC基础(一):异步FIFO_MaoChuangAn的博客-CSDN博客 ...

  4. 面试——异步FIFO详解

    1.异步FIFO简介及其原理 FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序 ...

  5. 7 centos 时钟跟物理机同步_同步FIFO和异步FIFO

    1.定义 FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出 ...

  6. verilog异步复位jk触发器_以不变应万变的异步FIFO面试宝典(二)

    异步FIFO面试宝典(二) 上一期为童鞋们带来了FIFO工作的基本原理,本期将继续与各位童鞋探讨FIFO类面试相关问题.首先让我们回顾一下上一期的课后思考题: 如果读时钟域速度较快.写时钟域速度较慢( ...

  7. 同步fifo与异步fifo

    参考以下帖子: https://blog.csdn.net/hengzo/article/details/49683707 https://blog.csdn.net/Times_poem/artic ...

  8. 同步FIFO和异步FIFO的Verilog实现

    FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据, 其 ...

  9. 同步FIFO和异步FIFO

    1.定义 FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出 ...

最新文章

  1. DTCC:数据库安全重点在数据拷贝过程中
  2. Openstack 中的消息总线 AMQP
  3. C#语法之fixed 语句
  4. Drupal 引入JS文件的几种方式
  5. 字节跳动推“头条搜索”独立APP 安卓端已上线
  6. Python 3.5/3.6 windows 7 安装
  7. 电大计算机专业毕业自我鉴定,电大毕业生计算机专业自我鉴定
  8. checkbox选中与取消选择
  9. 白话理解傅里叶变换原理(时域频域)
  10. st7789 旋转_玩转 ESP32 + Arduino(二十八) TFT_eSPI库驱动ST7789
  11. android 简书饿了么,对接饿了么平台总结
  12. SEO不能不知道的首页关键词策略
  13. PLC通讯实现-C#实现三菱PLC通讯(三)
  14. HTML5视频与字幕使用的介绍
  15. 无线视频监控系统设计
  16. 10.2-控制单元CU的微程序设计
  17. html把图片做成导航条背景,DIV+CSS背景图片导航菜单的实现方法
  18. Scratch少儿编程教培系统源码下载
  19. PAT练习 小白鼠排队
  20. 选秀节目打分,分为专家评委和大众评委

热门文章

  1. 解决WINDOWS 7开机卡在正在启动WINDOWS的问题
  2. OutputStream用法
  3. 北大直博保送生论文抄袭后续!南开大学:留校察看一年
  4. 童话里都是骗人的,扒一扒那些悲惨的原配,富家女扶贫是什么下场
  5. powershell安装和使用--学习入门
  6. PowerShell: 在自定义代码中支持Tab键自动补全
  7. SpringCloud Gateway + nacos 报错 Service Unavailable
  8. eclipse优化设置介绍---谷营中西
  9. windows系统下(win10),使用IIS搭建自己的专属网站
  10. Android集成开发工具——Android Studio