Verilog同步FIFO设计

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

同步FIFO(synchronous)的写时钟和读时钟为同一个时钟,FIFO内部所有逻辑都是同步逻辑,常常用于交互数据缓冲。

异步FIFO:数据写入FIFO的时钟和数据读出FIFO的时钟是异步的(asynchronous)

Verilog同步FIFO设计,学无止境,驱动开发,fpga开发,硬件工程,硬件架构

典型同步FIFO有三部分组成:

(1) FIFO写控制逻辑;

(2)FIFO读控制逻辑;

(3)FIFO 存储实体(如Memory、Reg)。

FIFO写控制逻辑主要功能:产生FIFO写地址、写有效信号,同时产生FIFO写 满、写错等状态信号;

FIFO读控制逻辑主要功能:产生FIFO读地址、读有效信号,同时产生FIFO读 空、读错等状态信号。

  • 基本概念

    FIFO:先进先出(First-in-first-out) FIFO的深度 同一块数据内存的大小

    FIFO的宽度:写指针:Write-pointer 读指针:Read-pointer

    一般FIFO使用循环指针(计数溢出自动归零)。一般可以称写指针为头head,读指针为尾tail。 初始化时,读写指针指向同一数据地址。下图可见,FIFO初始化时,WP和RP指针指向同一数据单元。WP指向下一个将要写入的数据单元,RP指向将要读出的数据单元
    Verilog同步FIFO设计,学无止境,驱动开发,fpga开发,硬件工程,硬件架构

    2种方法判断空满:

    1. counter计数器:判断有效数据是否等于FIFO的深度,为0就表示空

      使用fifo_counter记录FIFO RAM中的数据个数,等于0时,给出empty信号,等于BUF_LENGTH时,给出full信号。

      写而未满时增加1 读而未空时减1 同时发生读写操作时,fifo_counter不变

    2. pointer:如果深度为8,那么3bit就可以表示8个数,但是为了判断空满,会多定义一位,也即4bit,WP为1000,RP为0000,我们使用最高位去判断是否在同一单元,用高位判断空满,如果高位相异,就表示满,如果相同表示空。

  • 程序代码

    `define BUF_WIDTH 4 // 地址宽度为3+1,
    `define BUF_SIZE 8 // 数据个数,FIFO深度
    module fifo_counter( clk,rst_n,buf_in,buf_out,wr_en,rd_en,buf_empty,buf_full,fifo_cnt);
        input clk,rst_n; // 时钟与复位信号
        input wr_en,rd_en; // 读写使能信号
        input [7:0] buf_in; // 写数据
        output reg [7:0] buf_out; // 读数据
        output wire buf_empty,buf_full; // 空满两个状态信号
        output reg [`BUF_WIDTH-1:0] fifo_cnt;  //判断空满计数器
    
        // 读写指针:数据指针3位宽度,0-7索引,8个数据深度,循环指针0-7-0-7
        reg [`BUF_WIDTH-2:0] rd_ptr,wr_ptr;
        // 读写容器
        reg [7:0] buf_mem[0:`BUF_SIZE-1];
    
        //判断空满 方式1
        assign buf_empty = (fifo_cnt == 0); //buf_empty若是reg类型则错,不能使用assign持续赋值
        assign buf_full = (fifo_cnt == `BUF_SIZE);// fifo_cnt = 8就是满的
    
        //判断空满 方式2
        assign buf_empty = (rd_ptr[3] == wr_ptr[3])&&(rd_ptr[2:0] == wr_ptr[2:0]); 
        assign buf_full = (rd_ptr[3] != wr_ptr[3])&&(rd_ptr[2:0] == wr_ptr[2:0]); // 前后必须同时为1
    
        //读数据
        always @(posedge clk or negedge rst_n) 
            begin 
                if(!rst_n)
                    buf_out <= 0;
                if(rd_en && !buf_empty)
                    buf_out <= buf_mem[rd_ptr];
            end
    
        // 写数据
        always @(posedge clk) 
            begin
                if(wr_en && !buf_full)
                    buf_mem[wr_ptr] <= buf_in;
            end
    
        // 更改读写指针
        always @(posedge clk or negedge rst_n)
            begin
                if(!rst_n)
                    begin
                        wr_ptr <= 0;
                        rd_ptr <= 0;
                    end
                else 
                    begin
                        // 满足写的条件,就把写指针+1
                        if(!buf_full && wr_en)
                            wr_ptr <= wr_ptr + 1;
                        // 满足读的条件,就把读指针+1
                        if(!buf_empty && rd_en)
                            rd_ptr <= rd_ptr + 1;
                    end
            end
    
        // 监控fifo_cnt
        always @(posedge clk or negedge rst_n)begin
            if(!rst_n)
                fifo_cnt <= 0;
            else if((!buf_full&&wr_en)&&(!buf_empty&&rd_en)) // 同时读写,数量不变
                fifo_cnt <= fifo_cnt;
            else if(!buf_full && wr_en) // 写数据:写而未满增加1
                fifo_cnt <= fifo_cnt + 1;
            else if(!buf_empty && rd_en) // 读数据:读而未空减1
                fifo_cnt <= fifo_cnt-1;
            else
                fifo_cnt <= fifo_cnt; // 维持
        end
    endmodule
    
  • TestBench

    `define BUF_WIDTH 4 //地址宽度为3+1,
    `define BUF_SIZE (8) //数据个数,FIFO深度
    module tb_fifo_counter;
        reg clk,rst_n;
        reg wr_en,rd_en;
        reg [7:0] buf_in; // data input to be pushed to buffer
        wire [7:0] buf_out; // port to output the data using pop. wire buf_empty,buf_full; // buffer empty and full indication
        wire [`BUF_WIDTH-1:0] fifo_cnt; // number of data pushed in to buffer
        fifo_counter dut(
            .clk(clk),
            .rst_n(rst_n),
            .buf_in(buf_in),
            .buf_out(buf_out),
            .wr_en(wr_en),
            .rd_en(rd_en),
            .buf_empty(buf_empty),
            .buf_full(buf_full),
            .fifo_cnt(fifo_cnt));
        fifo_counter dut(
            .clk		(clk),
            .rst_n	(rst_n),
            .buf_in	(buf_in),
            .buf_out	(buf_out),
            .wr_en	(wr_en),
            .rd_en	(rd_en),
            .buf_empty	(buf_empty),
            .buf_full	(buf_full),
            .fifo_cnt	(fifo_cnt));
        always #10 clk = ~clk;
        // 定义一个临时的数据,将读出来的数据暂存
        reg [7:0] tempdata;
        initial begin
            clk = 0;
            rst_n = 0;
            wr_en = 0;
            rd_en = 0;
            buf_in = 0;
            #15; rst_n = 1;
            push(1);
    
            // 同时读写
            fork
                push(2);
                pop(tempdata); // 读取tempdata = 1
            join
    
            push(10);
            push(20);
            push(30);
            push(40);
            push(50);
            push(60);
            push(70);
            // 70push 就会满
            push(80);
            push(90);
            push(100);
            push(110);
            push(120);
            push(130);
            pop(tempdata); // 读取tempdata = 2
            push(tempdata); 
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            push(140); // 可以写进去
            pop(tempdata);
            push(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            pop(tempdata);
            push(5);
            pop(tempdata);// 读取tempdata = 5
            #50 $finish;
        end
        // 将data写入fifo
        task push (input [7:0] data);
            if(buf_full)
                $display("---Cannot push %d: Buffer Full---",data);
            else begin
                $display("Push",,data);
                buf_in = data;
                wr_en = 1;
                @(posedge clk);
                #5 wr_en = 0;
            end
        endtask
        // 将data读取出来
        task pop(output[7:0] data);
            if(buf_empty)
                $display("---Cannot Pop: Buffer Empty---");
            else begin
                rd_en = 1;
                @(posedge clk);
                #3 rd_en = 0;
                data = buf_out;
                $display("------Poped:",,data);
            end
        endtask
    endmodule
    

    find -name "*.v" > file.list

    makefile文件:

    all:clean com sim
    SEED=1
    com:
    	vcs -full64 -R -sverilog -debug_all -f file.list -l comp.log +ntb_random_seed=$(SEED) \
    	-cm line+cond+fsm+branch+tgl -cm_name simv -cm_dir ./covdir.vdb
    sim:
    	./simv -l sim.log
    rung:
    	./simv -gui -l sim.log
    cov:
    	dve -full64 -covdir *.vdb &
    clean:
    	rm -rf ./csrc *.daidir *.log *.vpd *.vdb simv* *.key *race.out*
    	rm -rf AN.DB
    	rm -rf novas*
    	rm -rf DVEfiles
    	rm -rf urgReport
    
    VCS Coverage Metrics Release O-2018.09-1_Full64 Copyright (c) 1991-2018 by Synopsys Inc.
    Push   1
    Push   2
    ------Poped:   1
    Push  10
    Push  20
    Push  30
    Push  40
    Push  50
    Push  60
    Push  70
    ---Cannot push  80: Buffer Full---
    ---Cannot push  90: Buffer Full---
    ---Cannot push 100: Buffer Full---
    ---Cannot push 110: Buffer Full---
    ---Cannot push 120: Buffer Full---
    ---Cannot push 130: Buffer Full---
    ------Poped:   2
    Push   2
    ------Poped:  10
    ------Poped:  20
    ------Poped:  30
    ------Poped:  40
    Push 140
    ------Poped:  50
    Push  50
    ------Poped:  60
    ------Poped:  70
    ------Poped:   2
    ------Poped: 140
    ------Poped:  50
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    Push   5
    ------Poped:   5
    

    查看波形:make rung

Verilog同步FIFO设计,学无止境,驱动开发,fpga开发,硬件工程,硬件架构文章来源地址https://www.toymoban.com/news/detail-650685.html

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

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

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

相关文章

  • FIFO设计笔记(双口RAM、同步FIFO、异步FIFO)Verilog及仿真

    0.1、FIFO FIFO (First-In-First-Out) 是一种先进先出的数据缓存器,在数字ASIC设计中常常被使用。在实际开发中,多数都是直接使用公司经过top-out验证的FIFO IP或者是ISE/Vivado工具自带的FIFO IP,并不需要自己造轮子。但是,作为设计者,必须要掌握FIFO的设计方法,这样可以适配于各种

    2023年04月09日
    浏览(36)
  • 万物皆数,算无止境 | 「雪浪算力开发者大赛」圆满收官

    时在中春,阳和方起。 4月23日, 「雪浪算力开发者大赛」 在雪浪小镇迎来完美收官。 本次大赛吸引了全球超过 2422名 开发者, 共有 624支 企业队伍, 288支 高校队伍报名参赛, 累计提交作品 9895份 。 经过三个月激烈的角逐与评委会严格评选, 最终有 72支 队伍脱颖而出 并

    2024年02月01日
    浏览(31)
  • 【Verilog】同步FIFO原理及verilog实现(参数化)

            旨在学习理解,项目中还是用成熟IP靠谱~ 目录 一、FIFO原理 二、同步FIFO设计 2.1 位宽和深度 2.2 空、满标志 2.3 FIFO计数 2.4 ram模型 2.5 读/写操作 三、​​​​​​​verilog代码 四、仿真验证 后记 FIFO( First Input First Output)是指先进先出。模型如下:           F

    2024年02月05日
    浏览(27)
  • 【Verilog】用双口RAM实现同步FIFO

    端口说明如下表。 双口RAM端口说明: 同步FIFO端口说明: 输入描述: input clk , input rst_n , input winc , input rinc , input [WIDTH-1:0] wdata 输出描述: output reg wfull , output reg rempty , output wire [WIDTH-1:0] rdata 双口RAM和代码框架: 同步FIFO,就是我们学习其他经典计算机语言(如C语言)的数据结

    2024年02月07日
    浏览(29)
  • 同步FIFO的verilog实现(2)——高位扩展法

            在之前的文章中,我们介绍了同步FIFO的verilog的一种实现方法:计数法。其核心在于:在同步FIFO中,我们可以很容易的使用计数来判断FIFO中还剩下多少可读的数据,从而可以判断空、满。         关于计数法实现同步FIFO的详细内容,请参考:同步FIFO的verilog实现(

    2024年02月09日
    浏览(29)
  • 手把手Verilog HDL同步Vaild-Ready握手FIFO机制

    三级目录 V-R握手FIFO机制,即是两级时钟速率不同的模块之间传递信号的机制,上游往下游传递的数据暂时缓存在FIFO中,上游和FIFO、FIFO和下游之间通过握手传递信号。即在一个FIFO模块外层套了一层握手机制。如下图: 如何用Verilog代码实现呢?我们可以这么来做, 1、先实现

    2024年02月16日
    浏览(26)
  • FIFO的Verilog设计(三)——最小深度计算

    FIFO的设计可参考 FIFO的Verilog设计(一)——同步FIFO FPGA的Verilog设计(二)——异步FIFO 参考文献 [1]FIFO最小深度计算   在实际使用FIFO时,需要考虑FIFO的深度如何设置,如果深度设置不当,可能会出现资源浪费或者数据丢失等情况。下面将简要介绍FIFO的最小深度如何计算。

    2024年02月04日
    浏览(80)
  • FPGA的Verilog设计(二)——异步FIFO

    阅读本文前,建议先阅读下面几篇文章: 同步FIFO 二进制转格雷码的实现   在上篇文章同步FIFO中简要介绍了FIFO的基本概念以及同步FIFO的实现。本篇文章将重点介绍异步FIFO的工作原理以及硬件实现。   异步FIFO的读写时钟不同,FIFO的读写需要进行异步处理, 异步FIFO常用

    2024年02月04日
    浏览(36)
  • FPGA的通用FIFO设计verilog,1024*8bit仿真,源码和视频

    名称:FIFO存储器设计1024*8bit 软件:Quartus 语言:Verilog 本代码为FIFO通用代码,其他深度和位宽可简单修改以下参数得到 代码功能: 设计一个基于FPGA的FIFO存储器,使之能提供以下功能  1.存储空间至少1024 储器  2.存储位宽8bit  3.拓展功能:存储器空、满报警 演示视频:http://

    2024年02月06日
    浏览(27)
  • verilog设计技巧 (1) :复位技术(同步复位、异步复位、异步复位同步释放)

    一、复位的类型和划分 通常,芯片的复位信号分为两大类, 全局复位 和 局部复位 ; 全局复位: 能够确保每个寄存器都处于可控的状态; 局部复位: 基于软件功能的需求而存在的独立复位,对于某一个模块的单独控制,建议使用局部复位; ( 等待完善 ) 二、同步复位 定义

    2023年04月21日
    浏览(28)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包