需要回答几个问题:

1.什么是异步FIFO,异步FIFO有什么功能?
跨时钟域的数据交换,防止亚稳态。

2.在产生写满与读空信号时需要进行跨时钟域如何做的,且如何能正确指示空满状态?
寄存器打两拍+格雷码。
格雷码的具体作用1
写读的地址是用二进制表示的,只是在将地址同步到对方的时钟域下得时候才会变成格雷码,因为格雷码相邻只有1位不同,即使在同步过程中同步错误,例如000->001,错误的结果仅仅为将原状态000同步过去,比如读同步到写,结果是在没满的时候会提前报写满,不会覆盖数据:<=满。读的情况一样。

3.异步FIFO的写满与读空信号如何利用格雷码正确产生?

格雷码的具体作用2
另一方面就是如何判断空满,假设fifo空间有8个,0-7,假设读地址是0000,当写地址为8时,实际写地址为1000,对应格雷码是1100,这时候是写满了,读地址的格雷码0000,写地址格雷码1100,二者对应高位与次高位不同,其余位相同,标志写满。
读空是二者格雷码完全相同,这个好理解:读是跟在写后面的,读得再快也是跟上了写,故而‘相同’。

总结:格雷码的唯一目的就是即使在亚稳态进行读写指针抽样,也能进行正确的空满状态指示。

原理框图:

异步FIFO的Verilog设计[2]:

module for_practice#(
parameter N = 8,WD = 3
)(
input w_clk,
input r_clk,
input arst,
input [N-1:0] i_dat,
input i_wren,
input i_rden,
output [N-1:0] o_dat,
output reg empty,
output reg full       );
reg[N-1:0]fifo_mem[2**WD-1:0];
wire [WD-1:0]wadd,radd;reg [WD:0] wbin,rbin,wgray,rgray;
wire[WD:0] wbin_next,rbin_next;
wire[WD:0] wgray_next,rgray_next;
/*******************************************************/
//产生写地址
assign wbin_next  = wbin + (i_wren & ~full );
assign wgray_next = (wbin_next>>1)^wbin_next;
assign wadd = wbin[WD-1:0];
always@(posedge w_clk or posedge arst)
beginif(arst)    {wbin,wgray} <= 0;else        {wbin,wgray} <= {wbin_next,wgray_next};
end
//将读格雷地址同步到写时钟域下,进行写满判断
reg [WD:0] rgray1,rgray2;
always@(posedge w_clk or posedge arst)
beginif(arst)    {rgray2,rgray1} <= 0;else        {rgray2,rgray1} <= {rgray1,rgray};
end
wire fullw;
assign fullw = {wgray_next == {~rgray2[WD:WD-1],rgray2[WD-2:0]}};
always@(posedge w_clk or posedge arst)if(arst)    full <= 0;else        full <= fullw;
//写入数据
always@(posedge w_clk)if(i_wren && !full)fifo_mem[wadd] <= i_dat ;/*******************************************************/
//产生读地址
assign rbin_next  = rbin + (i_rden & ~empty );
assign rgray_next = (rbin_next>>1)^rbin_next;
assign radd = rbin[WD-1:0];
always@(posedge r_clk or posedge arst)if(arst)    {rbin,rgray} <= 0;else        {rbin,rgray} <= {rbin_next,rgray_next};
//将写格雷地址同步到读时钟域下,进行读空判断
reg [WD:0] wgray1,wgray2;
always@(posedge r_clk or posedge arst)if(arst)    {wgray2,wgray1} <= 0;else        {wgray2,wgray1} <= {wgray1,wgray};
wire emptyr;
assign emptyr = {rgray_next == wgray2};
always@(posedge r_clk or posedge arst)if(arst)    empty <= 0;else        empty <= emptyr;
//读数据
assign o_dat = fifo_mem[radd];
/*******************************************************/endmodule 

同步FIFO的Verilog设计

思路就是将异步FIFO的跨时钟域的两拍寄存器与格雷码的部分去掉即可。

//读写地址
//当最高位相同,其余位相同认为是读空
//当最高位不同,其余位相同认为是写满
//同步fifo
module syn_fifo#(
parameter N = 8,WD = 3
)(
input clk,
input arst,
input [N-1:0] i_dat,
input i_wren,
input i_rden,
output [N-1:0] o_dat,
output reg empty,
output reg full
);
reg[N-1:0]fifo_mem[2**WD-1:0];//可以在复位时进行初始化为0
reg [WD:0] wbin,rbin;
wire [WD:0] wbin_next,rbin_next;wire [WD-1:0]wadd,radd;
wire fullw,emptyr;//产生写地址
assign wbin_next = wbin +(i_wren & ~full );
assign wadd = wbin[WD-1:0];
always@(posedge clk , posedge arst)
if(arst)    wbin <= 0;
else        wbin <= wbin_next;//写入数据
always@(posedge clk)
if(i_wren && !full)     fifo_mem[wadd] <= i_dat ;//产生读地址
assign rbin_next = rbin +(i_rden & ~empty );
assign radd = rbin[WD-1:0];
always@(posedge clk , posedge arst)
if(arst)    rbin <= 0;
else        rbin <= rbin_next;//读数据
assign o_dat = fifo_mem[radd]; //空满判断
assign fullw = (wbin_next == {~rbin[WD],rbin[WD-1:0]});//注意是wbin_next 与现在的 rbin比
assign emptyr = (wbin == rbin_next);                    //注意是rbin_next 与现在的 wbin比
always@(posedge clk , posedge arst)
if(arst)    { full,empty } <= 0;
else        { full,empty } <= { fullw,emptyr };
endmodule

参考资料

[1]异步fifo的设计(FPGA)

[2]异步FIFO的Verilog实现

跨时钟域信号处理(二)——异步fifo的Verilog实现(附同步fifo的实现)相关推荐

  1. FPGA跨时钟域信号处理之亚稳态问题

    FPGA跨时钟域信号处理之亚稳态问题学习笔记 跨时钟域会导致"亚稳态"的问题,信号的上升沿和下降沿并不是瞬间被拉高或拉低的,而是有一个倾斜变化的过程,如图中的tx信号的上升沿和下降 ...

  2. 数字IC笔面常考,跨时钟域神器。——异步FIFO(简介及手撕代码)

    异步FIFO 写在前面的话 异步FIFO相关知识点 FIFO简介 FIFO结构 应用场景(来源小梅哥 <FPGA 系统设计与验证实战指南> 章节4.4) 相关参数 异步FIFO 内部组成 ...

  3. 基于FPGA的跨时钟域信号处理——专用握手信号

    转自:http://bbs.ednchina.com/BLOG_ARTICLE_253787.HTM 在逻辑设计领域,只涉及单个时钟域的设计并不多.尤其对于一些复杂的应用,FPGA往往需要和多个时钟域 ...

  4. 跨时钟域信号处理——专用握手信号

    下图是一个基本的握手通信方式.所谓握手,意即通信双方使用了专用控制信号进行状态指示.这个控制信号既有发送域给接收域的,也有接收域给发送域的,有别于前面的单向控制信号检测方式 使用握手协议方式处理跨时钟 ...

  5. 跨时钟域信号处理---脉冲同步器详解

    在学习了原子哥的脉冲同步处理模块后,发现了诸多问题. 本文脉络:先对我哥的脉冲同步模块的代码进行一次测试,测试后发现问题,在对问题进行分析并提出解决方案. 这是一个典型的脉冲展宽同步器,实现的的功能是 ...

  6. 【FPGA】FIFO的Verilog设计之同步FIFO的设计

    这个同步FIFO的设计方法是调用异步读写双端口RAM来实现的. 关于异步读写双端口RAM的设计,前面博文已经讲到过了:[FPGA]双端口RAM的设计(异步读写) 此时使用双端口RAM来设计FIFO,可 ...

  7. 跨时钟域处理方法总结

    目录 跨时钟域处理 1. 异步时序定义 2. 亚稳态 3. 同步策略 方法一:双锁存器 方法二:握手信号(结绳法) 方法三:异步双口RAM+格雷码 跨时钟域处理 为了彻底理解跨时钟域问题,多方搜集资料 ...

  8. 【数字IC基础】跨时钟域(CDC,Clock Domain Crossing)

    文章目录 一.什么是跨时钟域? 二.跨时钟域传输的问题? 2.1 亚稳态(单bit:两级D触发器(双DFF)) 2.2 数据收敛(多bit亚稳态)(格雷码编码.握手协议.异步FIFO.DMUX) 2. ...

  9. 亚稳态及信号跨时钟域处理

    文章目录 一.亚稳态简介 二.亚稳态窗口 三.平均无故障时间(MTBF) 四.亚稳态产生场景 五.解决亚稳态的技术 5.1 单比特信号跨时钟域 5.1.1 多级同步器 5.1.2 另一种多级同步器 5 ...

最新文章

  1. 安卓的自定义的DemoApplication 出现的问题。
  2. HTTP 错误 404.0 - Not Found 您要找的资源已被删除、已更名或暂时不可用。
  3. 好奇,我们常用的 Integer 内部为什么会去实现 Comparable 接口,他的作用是什么?...
  4. Leet Code OJ 101. Symmetric Tree [Difficulty: Easy]
  5. 持续集成之配置TeamCity
  6. shell 生活0806012145
  7. 计算机网络之物理层基本概念
  8. 二维数组作为函数的实参,定义函数形参的方法
  9. 在树莓派2上安装 Windows 10
  10. kali局域网扫描ip_kali 扫描局域网的QQ
  11. Symfony 上传图片教程
  12. SRIO学习(三)——SRIO包
  13. 使用hue时hive的历史查询记录结果无法下载
  14. 多变量微积分笔记18——连通区域
  15. 如何快速识别图片中的文字?建议使用者两种方法
  16. 宋体测试液晶屏测试小程序
  17. 【概率论与数理统计】猴博士 笔记 p11-14 一维、二维离散型求分布函数和期望、方差
  18. c++:警告:warning: catching polymorphic type ‘class std::exception’ by value
  19. php日志分析,PHP SeasLog实现高性能日志记录
  20. 华为美女小姐姐,被外派墨西哥后,发生的事...

热门文章

  1. Debian10.12安装oracle11g(亲测有效)
  2. 高斯模糊与图像失焦,附Python代码实现
  3. luoguP2711 小行星
  4. 论文阅读:GeoTransformer
  5. 戴尔燃7000笔记本充不进去电,开机提示Alert!,点Continue进去后电脑变卡的解决方案。
  6. 团体程序设计天梯赛 -- 练习集 (L1合集)
  7. ROS2 基础概念 节点
  8. 计算机录音机应用程序在哪,win10电脑自带录音在哪里打开
  9. springboot+vue+安卓二手交易平台源码
  10. 怎么远程控制linux,Linux远程控制