同步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



  • 2
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答您的问题。关于您的问题:同步FIFO验证Verilog代码,我可以为您提供一些基本的思路和代码示例。请注意,这仅仅是一个基本的示例,具体的实现取决于您的应用场景和具体需求。 下面是一个基本的同步FIFO验证Verilog代码: ```verilog module fifo_verif; // inputs input clk; // 同步时钟 input rst; // 同步重置 input data_in; // 输入数据 input wr_en; // 写入使能 input rd_en; // 读取使能 // outputs output data_out; // 输出数据 output fifo_empty; // FIFO是否为空 output fifo_full; // FIFO是否已满 output fifo_almost_full; // FIFO是否快满 // internal signals reg [7:0] fifo [15:0]; // FIFO存储 reg [3:0] wr_ptr; // 写指针 reg [3:0] rd_ptr; // 读指针 wire [3:0] fifo_count; // FIFO中的元素数量 // 写入逻辑 always @(posedge clk or posedge rst) begin if (rst) // 重置状态 wr_ptr <= 0; else if (wr_en && !fifo_full) // 写入数据 begin fifo[wr_ptr] <= data_in; wr_ptr <= wr_ptr + 1; end end // 读取逻辑 always @(posedge clk or posedge rst) begin if (rst) // 重置状态 rd_ptr <= 0; else if (rd_en && !fifo_empty) // 读取数据 begin data_out <= fifo[rd_ptr]; rd_ptr <= rd_ptr + 1; end end // FIFO状态检测逻辑 assign fifo_empty = (wr_ptr == rd_ptr); assign fifo_full = (fifo_count == 16); assign fifo_almost_full = (fifo_count >= 13); // FIFO中的元素数量计算 assign fifo_count = (wr_ptr >= rd_ptr) ? (wr_ptr - rd_ptr) : (16 - (rd_ptr - wr_ptr)); endmodule ``` 上述代码实现了一个带有同步时钟和重置的FIFO,可以支持并行读写,并提供了FIFO状态检测功能(为空、已满、快满)。当然,具体应用中的FIFO设计会更为复杂,需要根据具体的需求进行调整。 我希望这个代码示例可以对您有所帮助,如果您还有其他问题,请随时向我提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值