21_ FIFO

1. FIFO IP 核简介

在这里插入图片描述

2. SCFIFO IP 核调用

2.1 RTL

 module fifo
 (
	// 读写用同一个时钟
	//同步 fifo
	input wire sys_clk , //系统时钟 50Mhz
	//要写入到 FIFO 中的数据
	input wire [7:0] pi_data , //输入顶层模块的数据
	//输入数据有效标志信号
	//也作为 FIFO 的写请求信号
	input wire pi_flag ,
	//FIFO 读请求信号
	input wire rdreq ,
	
	output wire [7:0] po_data , //FIFO 读出的数据
	output wire empty , //FIFO 空标志信号,高有效
	output wire full , //FIFO 满标志信号,高有效
	output wire [7:0] usedw //FIFO 中存在的数据个数
 );
 
scfifo_256_8 scfifo_256_8_inst
(
	.clock ( sys_clk ),
	.data ( pi_data ),//输入顶层模块的数据
	.rdreq ( rdreq ),//FIFO 读请求信号
	.wrreq ( pi_flag),// FIFO 的写请求信号
	
	
	.empty ( empty ),//FIFO 空标志信号,高有效
	.full ( full ), //FIFO 满标志信号,高有效
	.q ( po_data ),//FIFO 读出的数据
	.usedw ( usedw )//FIFO 中存在的数据个数
);

endmodule

2.2 testbench

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

//reg define
reg sys_clk ;
reg [7:0] pi_data ;//输入顶层模块的数据
reg pi_flag ; //也作为 FIFO 的写请求信号
reg rdreq ;
reg sys_rst_n ;
reg [1:0] cnt_baud ;


//wire define
wire [7:0] po_data ;//FIFO 读出的数据
wire empty ;
wire full ;
wire [7:0] usedw ; //FIFO 中存在的数据个数


//对 sys_clk,sys_rst 赋初值,并模拟按键抖动
initial
    begin
      sys_clk = 1'b1;
      sys_rst_n <= 1'b0;
      #100;
      sys_rst_n <= 1'b1;
    end
    
//sys_clk:模拟系统时钟,每 10ns 电平取反一次,周期为 20ns,频率为 50Mhz
always #10 sys_clk = ~sys_clk;
 

//cnt_baud:计数从 0 到 3 的计数器,用于产生输入数据间的间隔
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		cnt_baud <= 2'b0;
	// 如果计数器数到 3 
	else if(&cnt_baud == 1'b1)
		cnt_baud <= 2'b0;
	else
		cnt_baud <= cnt_baud + 1'b1;


//pi_flag:输入数据有效标志信号
//也作为 FIFO 的写请求信号
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		pi_flag <= 1'b0;
	// 每 4 个时钟周期且没有读请求时产生一个数据有效标志信号
	// 在没有请求读的信号 并且在四个周期完成情况下
	else if((cnt_baud == 2'd0) && (rdreq == 1'b0))
		pi_flag <= 1'b1;
	else	
		pi_flag <= 1'b0;
		
		
//pi_data:输入顶层模块的数据,要写入到 FIFO 中的数据
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		pi_data <= 8'b0;
	//pi_data 的值为 0~255 依次循环
	else if((pi_data == 8'd255) && (pi_flag == 1'b1))
		pi_data <= 8'b0;
	else if(pi_flag == 1'b1)	 //每当 pi_flag 有效时产生一个数据
		pi_data <= pi_data + 1'b1;
		

//rdreq:FIFO 读请求信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rdreq <= 1'b0;
    else if(full == 1'b1) //当 FIFO 中的数据存满时,开始读取 FIFO 中的数据
        rdreq <= 1'b1;
    else if(empty == 1'b1) //当 FIFO 中的数据被读空时停止读取 FIFO 中的数据
        rdreq <= 1'b0;
		

fifo fifo_inst
(
   	.sys_clk ( sys_clk ),
	.pi_data ( pi_data ),//输入顶层模块的数据
	.rdreq ( rdreq ),//FIFO 读请求信号
	.pi_flag( pi_flag),// FIFO 的写请求信号
	
	
	.empty ( empty ),//FIFO 空标志信号,高有效
	.full ( full ), //FIFO 满标志信号,高有效
	.po_data( po_data ),//FIFO 读出的数据
	.usedw ( usedw )//FIFO 中存在的数据个数
);
endmodule

3. DCFIFO IP 核调用

1)RTL 代码顶层的输入信号有:50MHz 的写时钟 wrclk、输入 256 个 8bit 的数据 pi_data(值为十进制 0~255)和伴随该输入数据有效的标志信号 pi_flag、25MHz 的读时钟 rdclk、FIFO 的写请求信号 rdreq。这些输入信号需要在 Testbench 中产生激励。
2)RTL 代码顶层的输出信号有:同步于 wrclk 的 FIFO 空标志信号wrempty、同步于wrclk 的 FIFO 满标志信号 wrfull、同步于 wrclk 指示 FIFO 中存在数据个数的信号wrusedw、从 FIFO 中读取的数据 po_data、同步于 rdclk 的 FIFO 空标志信号 rdempty、同步于 rdclk 的 FIFO 满标志信号 rdfull、同步于 rdclk 指示 FIFO 中存在数据个数的信号rdusedw。这些信号也是我们需要通过仿真 DCFIFO IP 核主要观察的信号,这些信号通过Testbench 中给输入信号激励后产生输出。

3.1 RTL

`timescale  1ns/1ns

module fifo
(
    //如果端口信号较多,我们可以将端口信号进行分组
    //把相关的信号放在一起,使代码更加清晰
    //FIFO写端
    input   wire         wrclk     ,   //同步于FIFO写数据的时钟50MHz
    input   wire  [7:0]  pi_data   ,   //输入顶层模块的数据,要写入到FIFO中
                                       //的数据同步于wrclk时钟
    input   wire         pi_flag   ,   //输入数据有效标志信号,也作为FIFO的
                                       //写请求信号,同步于wrclk时钟
    //FIFO读端
    input   wire         rdclk     ,   //同步于FIFO读数据的时钟25MHz
    input   wire         rdreq     ,   //FIFO读请求信号,同步于rdclk时钟

    //FIFO写端
    output  wire         wrempty   ,   //FIFO写端口空标志信号,高有效,
                                       //同步于wrclk时钟
    output  wire         wrfull    ,   //FIFO写端口满标志信号,高有效,
                                       //同步于wrclk时钟
    output  wire  [7:0]  wrusedw   ,   //FIFO写端口中存在的数据个数,
                                       //同步于wrclk时钟
    //FIFO读端
    output  wire  [15:0] po_data   ,   //FIFO读出的数据,同步于rdclk时钟
    output  wire         rdempty   ,   //FIFO读端口空标志信号,高有效,
                                       //同步于rdclk时钟
    output  wire         rdfull    ,   //FIFO读端口满标志信号,高有效,
                                       //同步于rdclk时钟
    output  wire  [6:0]  rdusedw       //FIFO读端口中存在的数据个数,
                                       //同步于rdclk时钟
);

//----------------------dcfifo_256x8to128x16_inst-----------------------
dcfifo_256_8_to_128_16 dcfifo_256_8_to_128_16_inst 
(
    .data   (pi_data),  //input     [7:0]   data
    .rdclk  (rdclk  ),  //input             rdclk
    .rdreq  (rdreq  ),  //input             rdreq
    .wrclk  (wrclk  ),  //input             wrclk
    .wrreq  (pi_flag),  //input             wrreq

    .q      (po_data),  //output    [15:0]  q
    .rdempty(rdempty),  //output            rdempty
    .rdfull (rdfull ),  //output            rdfull
    .rdusedw(rdusedw),  //output    [6:0]   rdusedw
    .wrempty(wrempty),  //output            wrempty
    .wrfull (wrfull ),  //output            wrfull
    .wrusedw(wrusedw)   //ou
);

endmodule

3.2 testbench

`timescale  1ns/1ns


module tb_fifo();

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

//reg   define
reg          wrclk          ;
reg  [7:0]   pi_data        ;
reg          pi_flag        ;
reg          rdclk          ;
reg          rdreq          ;
reg          sys_rst_n      ;
reg  [1:0]   cnt_baud       ;
reg          wrfull_reg0    ;
reg          wrfull_reg1    ;

//wire  define
wire            wrempty     ;
wire            wrfull      ;
wire    [7:0]   wrusedw     ;
wire    [15:0]  po_data     ;
wire            rdempty     ;
wire            rdfull      ;
wire    [6:0]   rdusedw     ;

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//初始化时钟、复位
initial begin
    wrclk      = 1'b1;
    rdclk      = 1'b1;
    sys_rst_n <= 1'b0;
    #100;
    sys_rst_n <= 1'b1;
end

//wrclk:模拟FIFO的写时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always #10 wrclk = ~wrclk;

//rdclk:模拟FIFO的读时钟,每20ns电平翻转一次,周期为40ns,频率为25MHz
always #20 rdclk = ~rdclk;

//cnt_baud:计数从0到3的计数器,用于产生输入数据间的间隔
always@(posedge wrclk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_baud <= 2'b0;
    else    if(&cnt_baud == 1'b1)
        cnt_baud <= 2'b0;
    else
        cnt_baud <= cnt_baud + 1'b1;

//pi_flag:输入数据有效标志信号,也作为FIFO的写请求信号
always@(posedge wrclk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pi_flag <= 1'b0;
    //每4个时钟周期且没有读请求时产生一个数据有效标志信号
    else    if((cnt_baud == 2'd0) && (rdreq == 1'b0))
        pi_flag <= 1'b1;
    else
        pi_flag <= 1'b0;

//pi_data:输入顶层模块的数据,要写入到FIFO中的数据
always@(posedge wrclk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pi_data <= 8'b0;
    pi_data的值为0~255依次循环
    else    if((pi_data == 8'd255) && (pi_flag == 1'b1))
        pi_data <= 8'b0;
    else    if(pi_flag  == 1'b1)    //每当pi_flag有效时产生一个数据
        pi_data <= pi_data + 1'b1;

//将同步于rdclk时钟的写满标志信号wrfull在rdclk时钟下打两拍
always@(posedge rdclk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)   
        begin
            wrfull_reg0 <= 1'b0;
            wrfull_reg1 <= 1'b0;
        end
    else
        begin
            wrfull_reg0 <= wrfull;
            wrfull_reg1 <= wrfull_reg0;
        end

//rdreq:FIFO读请求信号同步于rdclk时钟
always@(posedge rdclk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rdreq <= 1'b0;
//如果wrfull信号有效就立刻读,则不会看到rd_full信号拉高,
//所以此处使用wrfull在rdclk时钟下打两拍后的信号
    else    if(wrfull_reg1 == 1'b1)
        rdreq <= 1'b1;
    else    if(rdempty == 1'b1)//当FIFO中的数据被读空时停止读取FIFO中的数据
        rdreq <= 1'b0;

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//------------------------fifo_inst------------------------
fifo    fifo_inst(
    //FIFO写端
    .wrclk  (wrclk  ),  //input             wclk
    .pi_data(pi_data),  //input     [7:0]   pi_data
    .pi_flag(pi_flag),  //input             pi_flag
    //FIFO读端
    .rdclk  (rdclk  ),  //input             rdclk
    .rdreq  (rdreq  ),  //input             rdreq

    //FIFO写端
    .wrempty(wrempty),  //output            wrempty
    .wrfull (wrfull ),  //output            wrfull
    .wrusedw(wrusedw),  //output    [7:0]   wrusedw
    //FIFO读端
    .po_data(po_data),  //output    [15:0]  po_data
    .rdempty(rdempty),  //output            rdempty
    .rdfull (rdfull ),  //output            rdfull
    .rdusedw(rdusedw)   //output    [6:0]   rdusedw
);

endmodule

猜你喜欢

转载自blog.csdn.net/HeElLose/article/details/131304789