FPGA的Verilog设计(二)——异步FIFO

这篇具有很好参考价值的文章主要介绍了FPGA的Verilog设计(二)——异步FIFO。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


阅读本文前,建议先阅读下面几篇文章:
同步FIFO
二进制转格雷码的实现

前言

  在上篇文章同步FIFO中简要介绍了FIFO的基本概念以及同步FIFO的实现。本篇文章将重点介绍异步FIFO的工作原理以及硬件实现。

异步FIFO的工作原理

1. 概述

  异步FIFO的读写时钟不同,FIFO的读写需要进行异步处理,异步FIFO常用于多bit数据跨时钟域处理。异步FIFO一般有复位rst_n、读端口和写端口。读端口一般包括读时钟(rd_clk)、读使能(rd_en)、读数据(data_out)、读空(empty)。写端口一般包括写时钟(wr_clk)、写使能(wr_en)、写数据(data_in)、写满(wr_full)。

2. 地址的跨时钟问题

  实现异步FIFO难点仍在于如何得到读空和写满信号。由于异步FIFO的读写具有不同的时钟,读写独立,但是空满信号的判决仍需要通过读写地址(多bit数据)来实现,这里涉及到了多bit数据的跨时钟域处理,当然这里无法使用异步FIFO来实现这个跨时钟处理,毕竟我们就是为了做异步FIFO。多bit跨时钟处理还可以通过改变编码方式来降低亚稳态的发生概率。当读地址由4’b0111向4’b1000变化时,所有位都需要变化,如果写时钟恰好在地址变化时采样,写时钟得到的读地址是不确定的(为0000~1111中任意一个),因此为了降低该亚稳态的发生概率,地址采用格雷码编码。格雷码每次只变化一位,可以有效降低亚稳态的发生概率,同时单bit又可以采用打两拍的方法再次降低亚稳态发生的概率。
  综上所述,为有效解决地址的跨时钟问题,采取格雷码编码+打两拍的方式降低地址变化发生亚稳态的概率。二进制转格雷码的实现。

3. 空满信号的判决条件

  由于异步FIFO的读写地址采用格雷码,空满信号的判决条件不同于同步FIFO。同同步FIFO,可以将读写地址扩展一位,用于判断是否读写完一轮,即深度为8,地址为4bit。以下为深度为8的异步FIFO进行读写情况,以下只列举了四种操作,其余读写少于深度个数据的情况也是类似的。
FPGA的Verilog设计(二)——异步FIFO,# 常用数字电路模块,fpga开发

  综上所述,读空empty信号拉高的判决条件是读写地址的格雷码相同。写满信号拉高的判决条件是读写地址的格雷码的高2位不同,其余位相同
  但是上述判决条件可能存在一些问题。由于读写地址需要打两拍,如果打拍期间还有读写操作,那读写地址又改变了,得到的并不是真正的空满信号,那会出现数据丢失的情况吗?举例说明如下:

  • 判断空信号:判断空信号,需要比较rd_clk的读地址rd_addr从wr_clk打拍到rd_clk的写地址wr_addr_w2r,如果在打拍过程中,还写入数据(wr_addr增加),那么用于判断空信号的wr_addr_w2r会小于实际的写地址wr_addr。如果此时判断为空,其实FIFO并不是真空,只不过此时FIFO不能再读出数据,此种情况并不会发生数据丢失。并且下一个时钟,空信号便会失效,并不会影响FIFO的正常使用。
  • 判断满信号:判断满信号,需要比较wr_clk的写地址wr_addr从rd_clk打拍到wr_clk的读地址rd_addr_r2w,如果在打拍过程中,还读出数据(rd_addr增加),那么用于判断满信号的rd_addr_r2w会小于实际的读地址rd_addr。如果此时判断为满,其实FIFO并不是真满,只不过此时FIFO不能再写入数据,此种情况并不会发生数据丢失。并且下一个时钟,满信号便会失效,并不会影响FIFO的正常使用。

异步FIFO的实现

module async_fifo#(  
    parameter    DEPTH = 16,  
    parameter    WIDTH = 8,
    parameter    ADDR_BIT = 4,      //log2(DEPTH)
    parameter    RAM_STYLE_VAL = "distributed" 
)(  
    input        wr_clk,  
    input        rst_n,  
    input        wr_en,  
    input  [WIDTH-1:0]  data_in,  
    input        rd_clk,  
    input        rd_en,  
    output  [WIDTH-1:0]  data_out,  
    output        full,  
    output        empty
);
	(*ram_style=RAM_STYLE_VAL*)
    reg  [WIDTH-1:0]   mem [DEPTH-1:0];
    reg  [WIDTH-1:0]   data_out_r;
    reg  [ADDR_BIT:0]  wr_addr;
    wire [ADDR_BIT:0]  wr_addr_gray;
    reg  [ADDR_BIT:0]  wr_addr_w2r1;
    reg  [ADDR_BIT:0]  wr_addr_w2r2;
    reg  [ADDR_BIT:0]  rd_addr;
    wire [ADDR_BIT:0]  rd_addr_gray;
    reg  [ADDR_BIT:0]  rd_addr_r2w1;
    reg  [ADDR_BIT:0]  rd_addr_r2w2;
    
    //*********************** Address ***********************//
    //write address
    always @ (posedge wr_clk or negedge rst_n)begin  
    	if(!rst_n)    wr_addr <= 'd0;  
    	else if(wr_en)    wr_addr <= wr_addr + 1;  
    	else    wr_addr <= wr_addr;
    end

    //write address - > gray
    assign  wr_addr_gray = (wr_addr>>1)^wr_addr;
    
    //Write address synchronization to read clock domain
    always @ (posedge wr_clk or negedge rst_n)begin  
    	if(!rst_n)    
    	   {wr_addr_w2r2,wr_addr_w2r1} <= 'd0;
      	else  
      	   {wr_addr_w2r2,wr_addr_w2r1} <= {wr_addr_w2r1,wr_addr_gray};
    end
    //read address
    always @ (posedge rd_clk or negedge rst_n)begin  
    	if(!rst_n)    
    	   rd_addr <= 'd0;  
    	else if(rd_en)   
    	   rd_addr <= rd_addr + 1;  
    	else    
    	   rd_addr <= rd_addr;  
    end
    //write address - > gray
    assign  rd_addr_gray = (rd_addr>>1)^rd_addr;
    //Read address synchronization to write clock domain
    always @ (posedge rd_clk or negedge rst_n)begin  
    	if(!rst_n)    
    	   {rd_addr_r2w2,rd_addr_r2w1} <= 'd0;  
    	else    
    	   {rd_addr_r2w2,rd_addr_r2w1} <= {rd_addr_r2w1,rd_addr_gray};
    end
    //************************* Data *************************//
    //write data
    always @ (posedge wr_clk)begin  
        if(wr_en) 
            mem[wr_addr] <= data_in;
        else      
            mem[wr_addr] <= mem[wr_addr];
    end
    //read data delay 1clk
    assign  data_out = data_out_r;
    always @ (posedge rd_clk or negedge rst_n)begin  
    	if(!rst_n)    
    	   data_out_r <= {WIDTH{1'b0}};  
    	else if(rd_en==1)    
    	   data_out_r <= mem[rd_addr];  
    	else    
    	   data_out_r <= data_out_r;
    end
    //********************** Full/Empty *********************//
    //Empty signal judgment
    assign empty = (wr_addr_w2r2 == rd_addr_gray);
    //Full signal judgment
    assign full  = ({~(rd_addr_r2w2[4:3]),rd_addr_r2w2[2:0]}==wr_addr_gray[4:0]);
    
endmodule

异步FIFO的仿真测试

module tb_async;
    reg      wr_clk,rd_clk;
    reg      rst_n;
    reg      wr_en;
    reg      rd_en;
    reg  [7:0] data_in;
    wire [7:0] data_out;
    wire    full;
    wire    empty;
    
    parameter WR_PERIOD = 10;
    parameter RD_PERIOD = 20 ;
    
    async_fifo async_fifo(  
        .wr_clk     (wr_clk     ),  
        .rst_n      (rst_n      ),  
        .wr_en      (wr_en      ),  
        .data_in    (data_in    ),  
        .rd_clk     (rd_clk     ),
        .rd_en      (rd_en      ), 
        .data_out   (data_out   ), 
        .full       (full       ),  
        .empty      (empty      )     
        );
        
    initial begin  
        wr_clk = 0;rd_clk=0;rst_n = 0;  
        wr_en <= 0;rd_en <= 0;data_in  = 'd0;    
        #15  rst_n = 1; 
        write_data(16); 
        #100
        read_data(16);
        #100
        $finish;
    end
    always # (WR_PERIOD/2) wr_clk = ~wr_clk;
    always # (RD_PERIOD/2) rd_clk = ~rd_clk;
    
    task  write_data(input [7:0] t);  
    begin
        repeat(t)begin
            @(posedge wr_clk)
            data_in <= {$random}%256;
            wr_en   <= 1;
        end
        @(posedge wr_clk) wr_en <= 0;data_in <= 'd0;
    end
    endtask  
    
    task  read_data(input [7:0] t);  
        integer  i;  
        begin    
            repeat(t)begin
                @(posedge rd_clk)
                rd_en   <= 1;
            end
            @(posedge rd_clk) rd_en <= 0;
        end  
    endtask      
endmodule

  仿真结果如下,可以发现该异步fifo逻辑正确。
FPGA的Verilog设计(二)——异步FIFO,# 常用数字电路模块,fpga开发文章来源地址https://www.toymoban.com/news/detail-759219.html

到了这里,关于FPGA的Verilog设计(二)——异步FIFO的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 异步FIFO(Verilog)

    简介:        FIFO(First In First Out)是异步数据传输时经常使用的存储器。该存储器的特点是数据先进先出(后进后出)。其实,多位宽数据的异步传输问题,无论是从快时钟到慢时钟域,还是从慢时钟到快时钟域,都可以使用 FIFO 处理。异步FIFO 是指读写时钟不一致,读写

    2024年02月08日
    浏览(45)
  • 【小白入门】Verilog实现异步FIFO

       之前也在CSDN上面写过两个FIFO相关的文章,不过代码看起来比较复杂,且注释也比较少,不利于新手入门。很多时候都没有耐心继续看下去。 http://t.csdn.cn/0dPX6 http://t.csdn.cn/lYvoY  因为自己本身是一个初学者,就从初学者的视角来看待并学习FIFO。 为什么选择学习FIFO? 在学

    2024年02月09日
    浏览(43)
  • Verilog学习笔记(3):Verilog数字逻辑电路设计方法

    例:用Verilog设计模256(8bits)计数器 (a)可综合程序描述方式 (b)常见的错误描述方式 同时Verilog的电路描述方式具有多样性,这也决定了对于电路设计的多样性。 例:用Verilog设计数字多路选择器 (a)采用真值表形式的代码 (b)采用逻辑表达式形式的代码 (c)采用结

    2023年04月08日
    浏览(116)
  • 数字集成电路设计(四、Verilog HDL数字逻辑设计方法)(二)

    所有的是时序逻辑电路都可以拆成组合逻辑电路+存储 (关于组合逻辑电路的理解可以参考我数电的博客https://blog.csdn.net/y_u_yu_yu_/article/details/127592466) 可以分成两个部分,组合逻辑电路和存储电路。组合逻辑电路的输入一个是x信号一个是当前的状态,这两个信号决定了组合

    2024年02月06日
    浏览(48)
  • 数字电路EDA综合设计verilog笔记(持续更新)

    目录 1、常用组合电路模块的设计 1、基本门电路(常用3种描述方法) 2、译码器与编码器 (1)译码器(decoder) (2)编码器(encoder) 2、常用时序电路模块的设计 1、D触发器 2、数据锁存器 3、实用电路设计 1、基本门电路 2、译码器与编码器 3、数据选择器 4、奇偶校验产生器

    2024年02月09日
    浏览(45)
  • 数字集成电路设计(六、Verilog HDL高级程序设计举例)

    在我们的数电,集成电路设计里面,一定是层次化设计的 在一个手机芯片的一个部分,写的硬件描述语言的层次都能达到20几层,对于这样的设计,我i们就能想到采用底层的设计,中间层的设计和顶层的设计。对于小规模电路,极小规模电路,通常想的是先有模块然后去搭一

    2024年04月16日
    浏览(55)
  • 【FPGA】Verilog:组合电路设计 | 三输入 | 多数表决器

    前言: 本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载的示例:表决器(三人表决器)。 功能特性: 采用 Xilinx Artix-7 XC7A35T芯片  配置方式:USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度  存储器:2Mbit SRAM   N25Q064A SPI Flash(样图旧款为N25Q032A) 通用

    2023年04月08日
    浏览(38)
  • Verilog数字系统设计——10进制计数器,具有异步复位功能

    编程实现10进制计数器,具有异步复位功能,十位和个位用8421BCD码表示,各端口定义如下图所示: 仔细考虑端口定义中每个端口的含义; 要求完成程序编辑、编译、时序仿真; 实验提交Verilog设计文件(.v文件)、仿真波形截图以及对于第3个步骤所提出问题的回答,文件打包

    2024年02月11日
    浏览(35)
  • Verilog功能模块——读写位宽不同的异步FIFO

    FIFO系列文章目录: Verilog功能模块——异步FIFO-CSDN博客 Verilog功能模块——同步FIFO-CSDN博客 Verilog功能模块——读写位宽不同的异步FIFO-CSDN博客 Verilog功能模块——读写位宽不同的同步FIFO-CSDN博客 Verilog功能模块——标准FIFO转FWFT FIFO-CSDN博客 前面的博文已经讲了异步FIFO和同步

    2024年02月01日
    浏览(41)
  • 【数字IC手撕代码】Verilog无毛刺时钟切换电路|题目|原理|设计|仿真

    芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球 四社区 联合力荐 !近500篇 数字IC精品文章收录 ! 【数字IC精品文章收录】学习路线·基础知识·总线·脚本语言·芯片求职·EDA工具·低功耗设计Verilog·STA·设计·验证·FPGA·架构·AMBA·书籍 本系列旨在提

    2023年04月08日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包