异步fifo深度计算_异步fifo verilog

异步fifo深度计算_异步fifo verilog文章目录一、异步FIFO介绍1.1.空满判断1.2.跨时钟域问题1.3.格雷码转换1.4.格雷码计数器二、代码code一、异步FIFO介绍  FIFO有同步和异步两种,同步即读写时钟相同,同步FIFO用的少,可以作为数据缓存;异步即读写时钟不相同,异步FIFO可以解决跨时钟域的问题,在应用时需根据实际情况考虑好fifo深度即可。  与同步FIFO相同,异步FIFO也主要由五大模块组成,不同…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、异步FIFO介绍

  FIFO有同步和异步两种,同步即读写时钟相同,同步FIFO用的少,可以作为数据缓存;异步即读写时钟不相同,异步FIFO可以 解决跨时钟域的问题,在应用时需根据实际情况考虑好fifo深度即可。
  与同步FIFO相同,异步FIFO也主要由五大模块组成,不同的是,异步FIFO的读写逻辑控制还包括了格雷码转换和时钟同步部分:
    (1)、 FIFO写逻辑控制——产生FIFO写地址、写有效信号,同时产生FIFO写满、写错等状态信号;
    (2)、 FIFO读逻辑控制——产生FIFO读地址、读有效信号,同时产生FIFO读空、读错等状态信号;
    (3)、 时钟同步逻辑——通过两级DFF分别将写时钟域的写指针同步到读时钟域,将读时钟域的读指针同步到写时钟域;
    (4)、 格雷码计数器——格雷码计数器中二进制计数器的低(n-1)位可以直接作为FIFO存储单元的地址指针;
    (3)、 FIFO存储体(如Memory,reg等)。
    
其逻辑结构如下所示:
在这里插入图片描述

1.1.空满判断

对于异步FIFO采用地址扩展一位的方式对FIFO进行读写计数,进而判断空满。  
   读空信号:复位的时候,读指针和写指针相等,读空信号有效(这里所说的指针其实就是读地址、写地址)
       当读指针赶上写指针的时候,写指针等于读指针意味着最后一个数据被读完,此时读空信号有效。
   写满信号:当写指针比读指针多一圈时,写指针等于读指针意味着写满了,此时写满信号有效

当最高位相同,其余位相同认为是读空
当最高位不同,其余位相同认为是写满

该方法试用的是二进制数之间的空满比较判断,详情参见同步FIFO设计方法2。

因为异步FIFO采用格雷码计数,而格雷码是镜像对称的,若只根据最高位是否相同来区分是读空还是写满是有问题的。如下如图所示:
在这里插入图片描述
因此用格雷码判断是否为读空或写满时应使用理论 2,看最高位和次高位是否相等,具体如下:
当最高位和次高位相同,其余位相同认为是读空
当最高位和次高位不同,其余位相同认为是写满

  通俗的讲:当FIFO空时即读指针赶上写指针,此时两个格雷码完全相同(包括扩展位)。当FIFO写满时候需要考虑如下3个条件

  • 写指针的格雷码与同步到写时钟域的读指针格雷码的最高位不同
  • 写指针的格雷码与同步到写时钟域的读指针格雷码的次高位不相等
  • 写指针的格雷码与同步到写时钟域的读指针格雷码的其余位都相等

1.2.跨时钟域问题

  由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题,如何解决?

  跨时钟域的问题:上面我们已经提到要通过比较读写指针来判断产生读空和写满信号,但是读指针是属于读时钟域的,写指针是属于写时钟域的,而异步FIFO的读写时钟域不同,是异步的,要是将读时钟域的读指针与写时钟域的写指针不做任何处理直接比较肯定是错误的,因此我们需要进行同步处理以后仔进行比较。

解决方法:两级寄存器同步 + 格雷码
  (1)将写时钟域的写指针同步到读时钟域,将同步后的写指针与读时钟域的读指针进行比较产生读空信号
  (2)将读时钟域的读指针同步到写时钟域,将同步后的读指针与写时钟域的写指针进行比较产生写满信号

  如果直接用二进制编码的读写指针去完成上述的两种同步是不行的,使用格雷码更合适,为什么呢?

  因为二进制编码的指针在跳变的时候有可能是多位数据一起变化,如二进制的7–>8 即 0111 –> 1000 ,在跳变的过程中 4 位全部发生了改变,这样很容易产生毛刺,造成读写过程中数据出错。比如写指针在从0111到1000跳变时4位同时改变,这样读时钟在进行写指针同步后得到的写指针可能是0000-1111的某个值,一共有2^4个可能的情况,而这些都是不可控制的,你并不能确定会出现哪个值,那出错的概率非常大,而格雷码的编码特点是相邻位每次只有 1 位发生变化, 这样在进行指针同步的时候,就可以避免多个bit位同时跳变的情况。

  设计的时候读写指针用了至少两级寄存器同步,同步会消耗至少两个时钟周期,势必会使得判断空或满有所延迟,这会不会导致设计出错呢?

  异步FIFO通过比较读写指针进行满空判断,但是读写指针属于不同的时钟域,所以在比较之前需要先将读写指针进行同步处理,将写指针同步到读时钟域再和读指针比较进行FIFO空状态判断,因为在同步写指针时需要时间,而在这个同步的时间内有可能还会写入新的数据,因此同步后的写指针一定是小于或者等于当前实际的写指针,所以此时判断FIFO为空不一定是真空,这样更加保守,一共不会出现空读的情况,虽然会影响FIFO的性能,但是并不会出错,同理将读指针同步到写时钟域再和写指针比较进行FIFO满状态判断,同步后的读指针一定是小于或者等于当前的读指针,所以此时判断FIFO为满不一定是真满,这样更保守,这样可以保证FIFO的特性:FIFO空之后不能继续读取,FIFO满之后不能继续写入。总结来说异步逻辑转到同步逻辑不可避免需要额外的时钟开销,这会导致满空趋于保守,但是保守并不等于错误,这么写会稍微有性能损失,但是不会出错。

1.3.格雷码转换

  二进制码转换成二进制格雷码,其法则是保留二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高位与次高位相异或,而格雷码其余各位与次高位的求法相类似。

二进制B[n:0]转化为格雷码G[n:0]
G[n] = B[n]//保留最高位作为格雷码的最高位
G[n-1:0] = B[n-1:0]^B[n:1]//次高位格雷码为二进制码的高位与次高位相异或其余类似
在这里插入图片描述
我再换种更简单的描述
二进制数            1 0 1 1 0
二进制数右移1位,空位补0    0 1 0 1 1
异或运算            1 1 1 0 1
这样就可以实现二进制到格雷码的转换了,总结就是移位并且异或,verilog代码实现就一句:
assign wgraynext = ( wbinnext >> 1 ) ^ wbinnext;

格雷码G[n:0]转化为二进制B[n:0]
B[n] = G[n]//保留最高位作为二进制码的最高位
B[n-1:0] = G[n-1:0]^B[n:1]//次高位格雷码为二进制码的高位与次高位相异或其余类似
在这里插入图片描述

1.4.格雷码计数器

图中所示的格雷码计数器中二进制计数器的低(n-1)位可以直接作为FIFO存储单元的地址指针,将二进制数转化为格雷码传输给另外一个时钟域。
在这里插入图片描述

二、代码code

/*异步fifo 参考文献 Simulation and Synthesis Techniques for Asynchronous FIFO Design*/
//源码:https://github.com/DeamonYang/FPGA_SYNC_ASYNC_FIFO
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			;
input          fifo_wr_en	;
input	[15:0] fifo_wr_data;
input          fifo_rd_en	;
input          fifo_rd_clk;
input          fifo_wr_clk;
output reg     r_fifo_full	;
output  [15:0] fifo_rd_data;
output reg     r_fifo_empty	;
// output reg fifo_wr_err;
// output reg fifo_rd_err;
//中间信号internal singles 
reg	[9:0]  rdaddress;  //RAM地址为9位地址 扩展一位用于同步
reg	[9:0]  wraddress;  //RAM写地址
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;
wire fifo_empty;
wire fifo_full;
/*二进制转化为格雷码计数器*/
assign gray_rdaddress = (rdaddress >>1) ^ rdaddress;//(({1'b0,rdaddress[9:1]}) ^ rdaddress);
/*二进制转化为格雷码计数器*/
assign gray_wraddress = (({ 
1'b0,wraddress[9:1]}) ^ wraddress);
assign fifo_empty = (gray_rdaddress == sync_w2r_r2);  //格雷码所有bit位均相同
assign fifo_full = (gray_wraddress == { 
~sync_r2w_r2[9:8],sync_r2w_r2[7:0]});  //高两位不同,其余位相同
// 
// assign fifo_wr_err = (w_fifo_full && fifo_wr_en);
// assign fifo_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@(posedge fifo_rd_clk or negedge rst_n)
if(!rst_n)
r_fifo_empty <= 1'b0;
else 
r_fifo_empty <= fifo_empty;
/*在写时钟域判断FIFO满 sync_r2w_r2 实际延迟两个节拍 可能存在非满判断为满 但不会导致覆盖*/
always@(posedge fifo_wr_clk or negedge rst_n)
if(!rst_n)
r_fifo_full <= 1'b0;
else 									
r_fifo_full <= fifo_full;//格雷码判断追及问题 
/*读数据地址生成*/
always@(posedge fifo_rd_clk or negedge rst_n)
if(!rst_n)
rdaddress <= 10'b0;
else if(fifo_rd_en && ~fifo_empty)begin
rdaddress <= rdaddress + 1'b1;
end
/*写数据地址生成*/
always@(posedge fifo_wr_clk or negedge rst_n)
if(!rst_n)
wraddress <= 10'b0;
else if(fifo_wr_en && ~r_fifo_full)begin
wraddress <= wraddress + 1'b1;
end
/*同步读地址到写时钟域*/
always@(posedge fifo_wr_clk or negedge rst_n)
if(!rst_n)begin
sync_r2w_r1 <= 10'd0;
sync_r2w_r2 <= 10'd0;
end else begin
sync_r2w_r1 <= gray_rdaddress;
sync_r2w_r2 <= sync_r2w_r1;		
end
/*同步写地址到读时钟域, 同步以后 存在延迟两个节拍*/
always@(posedge fifo_rd_clk or negedge rst_n)
if(!rst_n)begin
sync_w2r_r1 <= 10'd0;
sync_w2r_r2 <= 10'd0;
end else begin
sync_w2r_r1 <= gray_wraddress ;
sync_w2r_r2 <= sync_w2r_r1;		
end		
endmodule

参考:https://blog.csdn.net/u014070258/article/details/90052281
https://www.cnblogs.com/aslmer/p/6114216.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/170198.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 十大Java编程工具

    十大Java编程工具以下是大多数Java程序员在日常生活中使用的10种最常见的Java开发工具。如果您正在使用Java技术,您应该已经熟悉这些工具,但如果您不熟悉,那么现在是了解和探索它们的好时机。1.Eclipse、NetBeans或IntelliJIDEAIDE是Java开发人员最重要的工具。IDE不仅为您提供集成开发环境,还有助于导航、调试和记录您的代码。由于Eclipse是行业领导者,因此几乎一半的Java开发人员都使用它。我更进一步,除了使用Eclipse,我喜欢使用Netb

  • POJ 3340 &amp; HDU 2410 Barbara Bennett&#39;s Wild Numbers(数学)「建议收藏」

    POJ 3340 &amp; HDU 2410 Barbara Bennett&#39;s Wild Numbers(数学)

  • 垂死或涅槃重生 — Delphi XE5 我们将宣布感情的回归

    垂死或涅槃重生 — Delphi XE5 我们将宣布感情的回归

    2021年12月30日
  • Cent0S下使用LVS+KeepLive进行负载均衡及高可用web服务器

    Cent0S下使用LVS+KeepLive进行负载均衡及高可用web服务器Cent0S下使用LVS+KeepLive,进行负载均衡及高可用web服务器。通过对本文章的阅读:你可以了解LVS+KeepLive的安装,按照步骤一步一步完成就能实现对2台或N台web服务器进行负载均衡,实现LVS的负载均衡及失效转移。一、需要的文件:1、ipvsadm-1.24.tar.gz,下载地址:下载2、keepalived-1.1.15.tar.gz,下载地…

  • mysql的where条件后加case_recommend

    mysql的where条件后加case_recommend背景:数据库用的Oracle;报表用的是【FineReport】,之前没用过,被临时授命解决问题,所以大概了解了一下。里面应该是集成了excel插件,报表样式如下:今天在项目中遇到一个这样的场景:A为汇总页面,显示的是按医院分组统计出来的一些数据,效果如下图图中每一列都能下钻到另一个页面,医院名称和起始时间都作为参数传送。前期因为某一些需求,有一家医院出现了两个不同的名…

  • mac navcat15 激活_在线激活2022.01.31

    (mac navcat15 激活)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.htmlCJM5ZJBPHS-eyJsaWNlbnNlSW…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号