数据缓存器FIFO IP核调取及应用

写在前面的话

在项目设计中我们通常需要在两个模块之间传输数据,如果两个模块的数据处理速率相同,那么自然没有任何问题,直接数据对接就可以。但是,如果两个模块的数据处理速度不同呢?数据接收模块和数据发送模块的速度不一致,必然会导致采集数据的遗漏或错误。那么,该如何解决这个问题呢?梦翼师兄的办法是在他们之间加一个数据缓存器,所有数据先经过缓存器缓存,然后再输入到数据接收模块。那么本节,梦翼师兄和大家一起学习用做数据缓存的存储IP核-FIFO的设计。

项目需求

创建两个模块一个作为数据发送模块,另一个作为数据接收模块。发送模块检测到FIFO为空则开始向FIFO中写入数据,直到FIFO写满为止。数据接收模块检测到FIFO为满则开始从FIFO中读出数据,直到FIFO读空为止。

操作步骤 

在右侧的IP核搜索区,输入fifo,然后双击【FI

选择语言类型为Verilog并命名

点击【OK】

设置fifo的存储深度和每一个存储空间的比特位数,选择输入和读出不是同一个时钟,fifo就会出现读时钟和写时钟

点击【NEXT】,选择端口如下

点击【NEXT】

选中my_fifo_inst.v文件,然后点击【Finish】退出即可。

fifo的读端口信号

fifo的写端口信号

端口名称

端口介绍

端口名称

端口介绍

full

读满信号(rdfull),当fifo被填充满,全部没有读出时,full为真值

full

写满信号(wrfull),当fifo被写满时full为真值

empty

读空信号(rdempty),当fifo所有的数据都被读出时,empty为真值

empty

写空信号(wrempty),当fifo没有任何数据被写入时,empty为真值

注:读端口和写端口的输出会有几拍的时间差,这是由fifo内部的结构导致的。

 顶层架构设计

FIFO是一个重要的数据缓冲器,我们设计出对应的控制模块对FIFO进行读写,根据我们在FIFO设置向导中了解到的信息,我们掌握了FIFO端口的含义,现设计架构图如下(为了方便大家理解在这里我们选择/数据的时钟是相同的) 

模块功能介绍

模块名

功能描述

Wr_fifo

对fifo进行写入

Rd_fifo

对fifo进行读出

My_fifo

数据缓存器

Fifo

系统顶层模块,负责子模块级联

端口和内部连线描述



顶层模块端口介绍

端口名

端口说明

Clk

系统时钟输入

Rst_n

系统复位

q

数据输出

系统内部连线介绍

连线名

连线说明

wrreq

写请求信号

wrfull

写满信号

wrempty

写空信号

rdreq

读请求信号

rdfull

读满信号

rdempty

读空信号

data

输入fifo的数据

代码解释



Wr_fifo模块代码

/****************************************************          

 *   Engineer      :   梦翼师兄

 *   QQ             :   761664056

 *   The module function:fifo进行写入 *****************************************************/

00 module wr_fifo (

01 clk, //模块输入时钟

02 rst_n, //模块复位

03 wrfull,// 写满信号

04 wrempty,//写空信号

05 data,//fifo的输入数据

06 wrreq//写请求信号

07 );

08 //模块输入

09 input clk;//模块输入时钟

10 input rst_n;//模块复位

11 input wrfull;// 写满信号

12 input wrempty;//写空信号

13 //模块输出

14 output reg [7:0] data;//fifo的输入数据

15 output reg wrreq;//写请求信号

16 //定义中间寄存器

17 reg state; //状态寄存器

18

19 always @ (posedge clk or negedge rst_n)

20 begin

21 if (!rst_n)//复位时,将中间寄存器和输出清零

22 begin

23 data <= 0;

24 wrreq <= 0;

25 state <= 0;

26 end

27 else

28 begin

29 case (state)

30 0 : begin

31 if (wrempty)//写空时,写请求拉高,跳到下一个状态

32 begin

33 state <= 1;

34 wrreq <= 1;

35 data <= 0;

36 end

37 else

38 state <= 0;

39 end

40

41 1 : begin

42 if (wrfull)//写满时,写请求拉低,跳回上一个状态

43 begin

44 state <= 0;

45 data <= 0;

46 wrreq <= 0;

47 end

48 else

49 begin

50 data <= data + 1; //没有写满的时候,写请求拉高,继续输入数据

51 wrreq <= 1;

52 end

53 end

54 endcase 

55 end

56 end

57

58 endmodule

rd_fifo模块代码

/****************************************************          

 *   Engineer      :   梦翼师兄

 *   QQ             :   761664056

 *   E_mail        :   zxopenwjf@126.com

 *   The module function:fifo进行读出 *****************************************************/

00 module rd_fifo (

01 clk,  //模块输入时钟

02 rst_n, //模块复位

03 rdfull,//读满信号

04 rdempty,//读空信号

05 rdreq//读请求

06 );

07 //模块输入

08 input clk;//模块输入时钟

09 input rst_n;//模块复位

10 input rdfull;//读满信号

11 input rdempty;//读空信号

12 //模块输出

13 output reg rdreq;//读请求

14 //定义中间寄存器

15 reg state;//状态寄存器

16

17 always @ (posedge clk or negedge rst_n)

18 begin

19 if (!rst_n)//复位时,将中间寄存器和输出清零

20 begin

21 rdreq <= 0;

22 state <= 0;

23 end

24 else

25 case (state)

26 0 : begin

27 if (rdfull)//读满时,读请求拉高,跳到下一个状态

28 begin

29 rdreq <= 1;

30 state <= 1;

31 end

32 else

33 state <= 0;

34 end

35

36 1 : begin

37 if (rdempty)//读空时,读请求拉低,跳回上一个状态

38 begin

39 rdreq <= 0;

40 state <= 0;

41 end

42 else

43 begin

44 rdreq <= 1;//没有读空的时候,读请求拉高,继续读出数据

45 state <= 1;

46 end

47 end

48 endcase

49

50 end

51

52 endmodule

顶层连接模块

/****************************************************          

 *   Engineer      :   梦翼师兄

 *   QQ             :   761664056

 *   The module function:顶层连接模块 *****************************************************/

00 module fifo (

01 clk,  //系统输入时钟

02 rst_n,  //系统复位

03 q //输出数据

04 );

05  //系统输入

06 input clk; //系统输入时钟

07 input rst_n; //系统复位

08 //系统输出

09 output [7:0] q; //输出数据

10 //定义中间连线

11 wire wrfull; // 写满信号

12 wire wrempty;//写空信号

13 wire [7:0] data;//fifo的输入数据

14 wire wrreq; //写请求信号

15 wire rdfull;//读满信号

16 wire rdempty;//读空信号

17 wire rdreq;//读请求

18 // 实例化wr_fifo模块

19 wr_fifo  wr_fifo (

20 .clk(clk),  //系统输入时钟

21 .rst_n(rst_n), //系统复位

22 .wrfull(wrfull), // 写满信号

23 .wrempty(wrempty), //写空信号

24 .data(data), //fifo的输入数据

25 .wrreq(wrreq)//写请求信号

26 );

27 // 实例化rd_fifo模块

28 rd_fifo rd_fifo (

29 .clk(clk),  //系统输入时钟

30 .rst_n(rst_n), //系统复位

31 .rdfull(rdfull), //读满信号

32 .rdempty(rdempty), //读空信号

33 .rdreq(rdreq)//读请求

34 );

35 //实例化my_fifo

36 my_fifo my_fifo_inst (

37 .data ( data ),//fifo的输入数据

38 .rdclk ( clk ),//读时钟

39 .rdreq ( rdreq ),//读请求

40 .wrclk ( clk ),//写时钟

41 .wrreq ( wrreq ),//写请求

42 .q ( q ),//输出数据

43 .rdempty ( rdempty ),//读空信号

44 .rdfull ( rdfull ),//读满信号

45 .wrempty ( wrempty ),//写空信号

46 .wrfull ( wrfull )//写满信号

47 );

48

49 endmodule

编写完可综合代码之后首先查看RTL视图如下

RTL视图可以看出代码综合以后成的电路和我们所设计的系统框图一致说明顶层模块连接正确接下来编写测试代码如下

/****************************************************          

 *   Engineer      :   梦翼师兄

 *   QQ             :   761664056

 *   The module function:fifo的仿真测试 *****************************************************/

00  `timescale 1ns/1ps       //时间单位和精度定义

01  module fifo_tb;

02      //系统输入

03      reg clk;        //系统输入时钟

04      reg rst_n;  //系统复位

05      //系统输出

06      wire [7:0] q;       //输出数据

07

08      initial begin

09          clk = 1;

10          rst_n = 0;

11          # 200.1

12          rst_n = 1;

13      end

14      

15      always # 10 clk = ~clk; //50MHz的时钟

16      

17      //实例化fifo

18      fifo fifo (

19                          .clk(clk),      //系统输入时钟

20                          .rst_n(rst_n),  //系统复位

21                          .q(q)           //输出数据

22                      );

23

24  endmodule 

仿真分析

复位结束后,由于fifo中没有任何数据,所以写空信号为1,当写入一个数据之后,写空信号变成0,写满信号一直为0

当输入数据到达256个的时候写满信号变高,并且经过几拍之后读满信号变成1(这是由fifo内部结构导致的),当读出一个数据之后,读满信号马上就拉低

当读出的数据达到256后,读空信号变高,经过几拍之后写空信号变高(由fifo内部结构决定),之后开始重新写数据,开始循环。


 




 

原文地址:https://www.cnblogs.com/mengyi1989/p/11518290.html