IP核之FIFO

一.FIFO简介

  • FIFO(First In First Out)即先入先出,适用于跨时钟域信号传递。

1.FIFO分类

  • FIFO 从输入时钟的角度来分,有两种类型:单时钟 FIFO(SCFIFO)和双时钟 FIFO(DCFIFO);其中,双时钟 FIFO 又可从输出数据的位宽的角度,分为普通双时钟(DCFIFO)和混合宽度双时钟 FIFO(DCFIFO_MIXED_WIDTHS)。

  • 可以将FIFO想象成一个管道,它有一定的宽度和一定的深度(长度),数据依次进入,然后依次输出,以达到先进先出的功能
    在这里插入图片描述

  • 混合宽度双端口可以看作是如下图
    在这里插入图片描述

2.端口作用

常用端口功能
data写入的数据
wrreq写使能
rereq读使能
wrclk写时钟
rdclk读时钟
aclr复位信号
wrfull写满标志
rdempty读空标志
q读出的数据

二.单时钟(普通模式/前显模式)

1.普通模式配置

  • 右侧IP catalog中选择FIFO
    在这里插入图片描述

  • 选择保存的位置及文件名
    在这里插入图片描述

  • 选择数据宽度和数据深度,并且选择单时钟模式
    在这里插入图片描述

  • 勾选空满信号,已使用的空间数以及复位信号
    在这里插入图片描述

  • 选择普通模式
    在这里插入图片描述

  • Next后默认
    在这里插入图片描述

  • 仿真工具库保持默认
    在这里插入图片描述

  • 勾选xxx_inst.v文件
    在这里插入图片描述

2.普通模式调用

module FIFO_test1( 
    input				clk		,
    input				rst_n	,
    input       [7:0]   data    ,
    input               rdreq   ,
    input               wrreq   ,

    output              empty   ,
    output              full    ,
    output      [7:0]   q       ,
    output      [3:0]   usedw   
);								 
//---------<参数定义>--------------------------------------------------------- 
    
//---------<内部信号定义>-----------------------------------------------------
    FIFO_normal	FIFO_normal_inst (
	    .aclr ( ~rst_n ),
	    .clock ( clk ),
	    .data ( data ),
	    .rdreq ( rdreq ),
	    .wrreq ( wrreq ),
	    .empty ( empty ),
	    .full ( full ),
	    .q ( q ),
	    .usedw ( usedw )
	);
       
endmodule

3.普通模式仿真

3.1仿真代码

`timescale 1ns/1ns
    
module tb_FIFO_test1();

//激励信号定义 
    reg				tb_clk  	;
    reg				tb_rst_n	;
    reg             tb_rdreq    ;
    reg             tb_wrreq    ;
    reg     [7:0]   tb_data     ;   

//输出信号定义	 
    wire                empty   ;
    wire                full    ; 
    wire	[7:0]		q	    ;
    wire	[3:0]		usedw   ;

//时钟周期参数定义	
    parameter		CLOCK_CYCLE = 20;   

//模块例化
    FIFO_test1 u_FIFO_test1(	
        .clk		(tb_clk),
        .rst_n	    (tb_rst_n),
        .data       (tb_data),
        .rdreq      (tb_rdreq),
        .wrreq      (tb_wrreq),
        .empty      (empty),
        .full       (full),
        .q          (q),
        .usedw      (usedw)
    );

//产生时钟
    initial 		tb_clk = 1'b0;
    always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;

//产生激励
    integer i = 0,j = 0;

    initial begin
        tb_clk = 1'b1;
        tb_rst_n = 1'b1;
        #200.1;
        tb_rst_n = 1'b0;

        //赋初值
        tb_rdreq = 1'b0;
        tb_wrreq = 1'b0;
        tb_data = 0;
        #200;
        tb_rst_n = 1'b1;
        #200;

        //写
        for(i=0;i<256;i=i+1)begin
            tb_wrreq = 1'b1;//高电平有效
            tb_data = {$random};
            #20;
        end
        tb_wrreq = 1'b0;//写完拉低
        #100;

        //读
        for(j=0;j<256;j=j+1)begin
            tb_rdreq = 1'b1;
            #20;
        end
        tb_rdreq = 1'b0;//读完拉低
        #200;
        $stop;
    end


endmodule 

3.2仿真总效果

在这里插入图片描述

3.3仿真细节之写满

  • 即使写使能一直为高,一直在生成数据,但是数据深度限制了只能写一定量的数据。usedw信号会注明FIFO已经占用了多少深度。
    在这里插入图片描述

3.4仿真细节之读空

  • 我们已知之前写满了数据,后面读使能拉高后,开始读数据,但是当FIFO被读空之后,就不再读数据,只能读到我们之前写满的最后一位(也就是数据198),usedw仍然会显示FIFO的使用情况
    在这里插入图片描述

4.前显模式配置

  • 与普通模式一致,除了选择模式的位置更改勾选为Show ahead模式
    在这里插入图片描述

5.前显模式调用

module FIFO_test2( 
    input				clk		,
    input				rst_n	,
    input       [7:0]   data    ,
    input               rdreq   ,
    input               wrreq   ,
    output              empty   ,
    output              full    ,
    output      [7:0]   q       ,
    output      [3:0]   usedw   
);								 
//---------<参数定义>--------------------------------------------------------- 
    
//---------<内部信号定义>-----------------------------------------------------
    FIFO_ahead	FIFO_ahead_inst (
	    .aclr ( ~rst_n ),
	    .clock ( clk ),
	    .data ( data ),
	    .rdreq ( rdreq ),
	    .wrreq ( wrreq ),
	    .empty ( empty ),
	    .full ( full ),
	    .q ( q ),
	    .usedw ( usedw )
	);
 
endmodule

6.前显模式仿真

6.1仿真代码

`timescale 1ns/1ns
    
module tb_FIFO_test2();

//激励信号定义 
    reg				tb_clk  	;
    reg				tb_rst_n	;
    reg             tb_rdreq    ;
    reg             tb_wrreq    ;
    reg     [7:0]   tb_data     ;   

//输出信号定义	 
    wire                empty   ;
    wire                full    ; 
    wire	[7:0]		q	    ;
    wire	[3:0]		usedw   ;

//时钟周期参数定义	
    parameter		CLOCK_CYCLE = 20;   

//模块例化
    FIFO_test2 u_FIFO_test2(	
        .clk		(tb_clk),
        .rst_n	    (tb_rst_n),
        .data       (tb_data),
        .rdreq      (tb_rdreq),
        .wrreq      (tb_wrreq),
        .empty      (empty),
        .full       (full),
        .q          (q),
        .usedw      (usedw)
    );

//产生时钟
    initial 		tb_clk = 1'b0;
    always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;

//产生激励
    integer i = 0,j = 0;

    initial begin
        tb_clk = 1'b1;
        tb_rst_n = 1'b1;
        #200.1;
        tb_rst_n = 1'b0;

        //赋初值
        tb_rdreq = 1'b0;
        tb_wrreq = 1'b0;
        tb_data = 0;
        #200;
        tb_rst_n = 1'b1;
        #200;

        //写
        for(i=0;i<256;i=i+1)begin
            tb_wrreq = 1'b1;//高电平有效
            tb_data = {$random};
            #20;
        end
        tb_wrreq = 1'b0;//写完拉低
        #100;

        //读
        for(j=0;j<256;j=j+1)begin
            tb_rdreq = 1'b1;
            #20;
        end
        tb_rdreq = 1'b0;//读完拉低
        #200;
        $stop;
    end


endmodule 

6.2仿真总效果

在这里插入图片描述

6.3两种模式区别

  • 前显模式在读使能拉高之前q有值,普通模式在读使能拉高之前保持未知态。
    在这里插入图片描述

在这里插入图片描述

  • !!!我们通常使用前显模式!!!

三.双时钟(普通双时钟/混合宽度双时钟)

1.普通双时钟配置

  • 右侧IP catalog中选择FIFO
    在这里插入图片描述

  • 选择保存的位置及文件名
    在这里插入图片描述

  • 选择数据宽度和数据深度,并且选择双时钟模式
    在这里插入图片描述

  • Next后保持默认
    在这里插入图片描述

  • 选择空满信号(这时只选择写满和读空)以及复位信号
    在这里插入图片描述

  • 模式选择前显模式
    在这里插入图片描述

  • Next后保持默认
    在这里插入图片描述

  • 仿真工具库保持默认
    在这里插入图片描述

  • 勾选xxx_inst.v文件
    在这里插入图片描述

2.普通双时钟调用

module FIFO_test3( 
    input				rdclk	,
    input               wrclk   ,
    input				rst_n	,
    input       [7:0]   data    ,
    input               rdreq   ,
    input               wrreq   ,

    output      [7:0]   q       ,
    output              rdempty ,
    output              wrfull  
);								 
//---------<参数定义>--------------------------------------------------------- 
    
//---------<内部信号定义>-----------------------------------------------------
    FIFO_normal_double	FIFO_normal_double_inst (
	    .aclr ( ~rst_n ),
	    .data ( data ),
	    .rdclk ( rdclk ),
	    .rdreq ( rdreq ),
	    .wrclk ( wrclk ),
	    .wrreq ( wrreq ),
	    .q ( q ),
	    .rdempty ( rdempty ),
	    .wrfull ( wrfull )
	);
    
endmodule

3.普通双时钟仿真

3.1仿真代码

`timescale 1ns/1ns
    
module tb_FIFO_test3();

//激励信号定义 
    reg				tb_rdclk  	;
    reg             tb_wrclk    ;
    reg     [7:0]   tb_data     ;
    reg             tb_rdreq    ;
    reg             tb_wrreq    ;      
    reg				tb_rst_n	;

//输出信号定义	 
    wire	[7:0]		q   	;
    wire                rdempty ;
    wire                wrfull  ;

//时钟周期参数定义	
    parameter		CLOCK_CYCLE = 20;   

//模块例化
    FIFO_test3 u_FIFO_test3(	
        .rdclk	    (tb_rdclk),
        .wrclk      (tb_wrclk),
        .rst_n	    (tb_rst_n),
        .data       (tb_data),
        .rdreq      (tb_rdreq),
        .wrreq      (tb_wrreq),
        .q          (q),
        .rdempty    (rdempty),
        .wrfull     (wrfull)
    );

//产生时钟
    initial 		tb_rdclk = 1'b0;
    always #(CLOCK_CYCLE/2) tb_rdclk = ~tb_rdclk;
    initial 		tb_wrclk = 1'b0;
    always #(CLOCK_CYCLE/2) tb_wrclk = ~tb_wrclk;
//产生激励
    integer i,j;
    initial  begin 
        tb_rst_n = 1'b1;
        #200.1;
        tb_rst_n = 1'b0;

        //赋初值
        tb_rdreq = 1'b0;
        tb_wrreq = 1'b0;
        tb_data = 0;
        #200;
        tb_rst_n = 1'b1;
        #200;

        //写
        for(i=0;i<256;i=i+1)begin
            tb_wrreq = 1'b1;//高电平有效
            tb_data = {$random};
            #20;
        end
        tb_wrreq = 1'b0;//写完拉低
        #100;

        //读
        for(j=0;j<256;j=j+1)begin
            tb_rdreq = 1'b1;
            #20;
        end
        tb_rdreq = 1'b0;//读完拉低
        #200;
        $stop;
    end

endmodule 

3.2仿真效果

在这里插入图片描述

4.混合宽度双时钟配置

  • 混合宽度双时钟与普通双时钟的区别在前文FIFO简介中有图解,其设置上的区别在于设置数据宽度和数据深度页
    在这里插入图片描述

5.混合宽度双时钟调用

module FIFO_test4( 
    input				rdclk   ,
    input               wrclk   ,
    input				rst_n	,
    input       [7:0]   data    ,
    input               rdreq   ,
    input               wrreq   ,

    output      [7:0]   q       ,
    output              rdempty ,
    output              wrfull  
);								 
//---------<参数定义>--------------------------------------------------------- 
    
//---------<内部信号定义>-----------------------------------------------------
    FIFO_mix_double	FIFO_mix_double_inst (
	    .aclr ( ~rst_n ),
	    .data ( data ),
	    .rdclk ( rdclk ),
	    .rdreq ( rdreq ),
	    .wrclk ( wrclk ),
	    .wrreq ( wrreq ),
	    .q ( q ),
	    .rdempty ( rdempty ),
	    .wrfull ( wrfull )
	);
    
endmodule

6.混合宽度双时钟仿真

6.1仿真代码

`timescale 1ns/1ns
    
module tb_FIFO_test4();

//激励信号定义 
    reg				tb_rdclk  	;
    reg             tb_wrclk    ;
    reg     [7:0]   tb_data     ;
    reg             tb_rdreq    ;
    reg             tb_wrreq    ;      
    reg				tb_rst_n	;

//输出信号定义	 
    wire	[7:0]		q   	;
    wire                rdempty ;
    wire                wrfull  ;

//时钟周期参数定义	
    parameter		CLOCK_CYCLE = 20;   

//模块例化
    FIFO_test4 u_FIFO_test4(	
        .rdclk	    (tb_rdclk),
        .wrclk      (tb_wrclk),
        .rst_n	    (tb_rst_n),
        .data       (tb_data),
        .rdreq      (tb_rdreq),
        .wrreq      (tb_wrreq),
        .q          (q),
        .rdempty    (rdempty),
        .wrfull     (wrfull)
    );

//产生时钟
    initial 		tb_rdclk = 1'b0;
    always #(CLOCK_CYCLE/2) tb_rdclk = ~tb_rdclk;
    initial 		tb_wrclk = 1'b1;
    always #(CLOCK_CYCLE/4) tb_wrclk = ~tb_wrclk;
//产生激励
    integer i,j;
    initial  begin 
        tb_rst_n = 1'b1;
        #200.1;
        tb_rst_n = 1'b0;

        //赋初值
        tb_rdreq = 1'b0;
        tb_wrreq = 1'b0;
        tb_data = 0;
        #200;
        tb_rst_n = 1'b1;
        #200;

        //写
        for(i=0;i<256;i=i+1)begin
            tb_wrreq = 1'b1;//高电平有效
            tb_data = {$random};
            #20;
        end
        tb_wrreq = 1'b0;//写完拉低
        #100;

        //读
        for(j=0;j<256;j=j+1)begin
            tb_rdreq = 1'b1;
            #20;
        end
        tb_rdreq = 1'b0;//读完拉低
        #200;
        $stop;
    end

endmodule 

6.2仿真效果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值