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