我是靠谱客的博主 曾经鞋子,最近开发中收集的这篇文章主要介绍同步FIFO的设计和验证,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.FIFO是什么?

fifo是一种先进先出的数据缓存器,与普通存储器的区别是没有外部读写地址线,只能顺序读写,不能随机读写。

2.使用场景

(1)数据缓冲:当突然一股数据流突发写入,fifo可以暂时将数据暂存,起到缓冲作用,且使后续处理流程平滑。

(2)时钟域的隔离:主要用于异步FIFO。对于不同时钟域的数据传输,可以通过fifo进行隔离,避免跨时钟域的数据带来的设计和约束上的复杂程度。

(3)用于不同宽度的数据接口。

3.fifo的分类

同步fifo:读时钟与写时钟是同一个时钟

异步fifo:读时钟与写时钟不是同一个时钟

4.fifo的常见参数

fifo的宽度:一次操作读写的数据位;

fifo的深度:可以存储数据位的数量;

满标志:fifo的深度即将满或已经满了有fifo向电路释放的信号,用来阻止继续向fifo写入数据避免数据溢出;

空标志:fifo已空或者将要空由fifo向电路释放的信号,用来阻止继续向fifo读数据避免无效数据的读出;

读时钟:顾名思义,在每个时钟沿临时读数据。

写时钟:顾名思义,在每个时钟沿临时写数据。

5.同步fifo例子

图1.同步fifo的架构

 5.1fifo的空与满

在设计时,不管是同步fifo还是异步fifo最难分析的部分是如何判断fifo的空状态与满状态。

判断fifo空满的方法一:

满操作:在执行写的操作时,两个指针在下个时钟保持相等,则fifo 判断为满,发出fifo_full信号。原理图如下

图2.fifo满条件

 

图3.代码片段

空操作:在执行读的操作时,两个指针在下个时钟保持相等,则fifo 判断为空,发出fifo_empty信号。

判断fifo空满的方法二:

用计数器持续指示fifo中空或满的个数。引入一计数器,任何读的操作将其递增1,任何写的操作将其递减1。若计数器的值为0,则fifo为空状态;若计数器的值等于fifo的深度值,则为满状态。

`timescale 1ns/ 1ps

module sync_fifo();
    input        clk;
    input        rstn;
    input[7:0]    data_in;
    input        write;
    input        read;

    output[7:0] data_out;
    output full;
    output empty;

    reg [4:0]    wp;                  //写指针
    reg [4:0]    rp;                  //读指针
    reg [7:0]    data_out_reg;        //不懂
    reg [7:0]    RAM [15:0];           //定义存储器

//******************写指令操作********************
    always @ (negedge rstn or posedge clk )
        begin
            if (! rstn)
              begin
                wp <= 5b'0
              end
            else  if (write & !full)
              begin
                RAM [wp[4:0]] <= data_in;
                wp <= wp + 1;
              end
        end
//*****************读指令操作*******************
always @ (negedge rstn or posedge clk)
    begin
        if (!rstn)
            begin
                rp <= 5b'0;
                data_out <= 8'b0;
            end
        else if (!empy & read)
            begin
                data_out_reg <= RAM [rp[4:0]];
                rp <= rp + 1;
            end
    end


//************判断fifo的空满********************
//判断fifo是否空满从不同的角度有不同的方法
//本处采用读写指针位置关系判断空满,简单理解就是空指针与满指针谁追谁的问题
//如果满指针的下一步会追上空指针,则判断为满
//如果空指针的下一步追上满指针,则判断为空

//***************判断fifo是否满****************
always @ (posedge clk or negedge rstn)
    begin
        if (!rstn)
            begin
                full <= 1'b0;
            end
        else if (write & read)
                    ;              //维持原态
        else if (read)
            full <= 1b'0;
        else if (write & read = (write +1))
            full <= 1b'0;
    end
//***************判断fifo是否为空******************
always @ (posedge clk or negedge rstn)
    begin
        if (!rstn)
            empty <= 1'b1;
        else if (write)
            empty <= 1b'0;
        else if (write & read)
                    ;
        else if (read & write = (read + 1))
            empty <= 1b'1;
    end
  assign data_out = data_out_reg;

endmodule





tb

`timescale 1 ns/ 1 ps

module sync_fifo_tb ();
    reg clk;
    reg rstn;
    reg write;
    reg read;
    reg [7:0] data_in;
    wire [7:0] data_out;
    
    wire full;
    wire empty;


sync_fifo fifo 
(
    .clk(clk),
    .rstn(rstn),
    .write(write),
    .read(read),
    .data_in(data_in),
    .data_out(data_out),
    .full(full),
    .empty(empty)
);

//*************定义时钟*****************
initial
    begin
        clk <= 1'b0;
        forever #100 clk <= ~clk;
    end
//************验证初始环境及其验证时长*******************
initial
    begin 
        rstn = 0;                        //为什么用阻塞赋值?
        data_in = 0;
        #100 rstn = 1;
        #10000;
        $finish();
    end
//***************生成data_in数据****************
always @ (posedge clk or negedge rstn)
    begin
        data_in <= data_in + 1b'0;
    end
//**************write信号的判定***********
always @ (posedge clk or negedge rstn)
    begin
        if (!rstn)
            write <= 0;
        else if (!full)
            write <= 1;
        else 
            write <= 0;
    end
//**************read信号的判定***********
always @ (posedge clk or negedge rstn)
    begin
        if (!rstn)
            read <= 0;
        else if (!empty)
            read <= 1;
        else 
           read <= 0;
    end
//*************
inital
    begin
         $fsdbDumpfile("dazhuang");
         $fsdbDumpvars;
         $vcdpluson;
    end
endmodule



最后

以上就是曾经鞋子为你收集整理的同步FIFO的设计和验证的全部内容,希望文章能够帮你解决同步FIFO的设计和验证所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部