FIFO一般用于不同时钟域之间的数据传输,也常用来实现不同位宽的接口的数据匹配。(可以避免两个模块时钟不一致,造成的亚稳态状态,也可以进行数据缓存,也可以解决数据发送时两边时钟不一致)
利用FIFO在不同位宽的接口之间作数据匹配:(可以将fifo输入端设计为8位,输出端设计为16位,就可以解决该问题)
下面是本次实验的系统框图
1.fifo ip核的设计
在ip catalog中搜索fifo,双击fifo
然后在工程文件夹中创建IPcore文件夹,然后再在里面建fifo文件夹,最后将ip核定义为fifo保存
并选择verilog
开始配置
正常模式:
前显模式:
最下面那个框不勾,不使用逻辑资源去实现fifo功能
点击finish,完成设计
2.程序设计
fifo_rd模块
module fifo_rd(
//system clock
input clk , // 时钟信号
input rst_n , // 复位信号(低有效)
//user interface
input [7:0] data , // 从FIFO输出的数据
input rdfull , // 读满信号
input rdempty, // 读空信号
output reg rdreq // 读请求
);
//reg define
reg [7:0] data_fifo; // 读取的FIFO数据
reg [1:0] flow_cnt ; // 状态流转计数
//*****************************************************
//** main code
//*****************************************************
//从FIFO中读取数据
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rdreq <= 1'b0;
data_fifo <= 8'd0;
end
else begin
case(flow_cnt)
2'd0: begin
if(rdfull) begin
rdreq <= 1'b1;
flow_cnt <= flow_cnt + 1'b1;
end
else
flow_cnt <= flow_cnt;
end
2'd1: begin
if(rdempty) begin
rdreq <= 1'b0;
data_fifo <= 8'd0;
flow_cnt <= 2'd0;
end
else begin
rdreq <= 1'b1;
data_fifo <= data;
end
end
default: flow_cnt <= 2'd0;
endcase
end
end
endmodule
fifo_wr模块
module fifo_wr(
//mudule clock
input clk , // 时钟信号
input rst_n , // 复位信号
//user interface
input wrempty, // 写空信号
input wrfull , // 写满信号
output reg [7:0] data , // 写入FIFO的数据
output reg wrreq // 写请求
);
//reg define
reg [1:0] flow_cnt; // 状态流转计数
//*****************************************************
//** main code
//*****************************************************
//向FIFO中写入数据
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
wrreq <= 1'b0;
data <= 8'd0;
flow_cnt <= 2'd0;
end
else begin
case(flow_cnt)
2'd0: begin
if(wrempty) begin //写空时,写请求拉高,跳到下一个状态
wrreq <= 1'b1;
flow_cnt <= flow_cnt + 1'b1;
end
else
flow_cnt <= flow_cnt;
end
2'd1: begin //写满时,写请求拉低,跳回上一个状态
if(wrfull) begin
wrreq <= 1'b0;
data <= 8'd0;
flow_cnt <= 2'd0;
end
else begin //没有写满的时候,写请求拉高,继续输入数据
wrreq <= 1'b1;
data <= data + 1'd1;
end
end
default: flow_cnt <= 2'd0;
endcase
end
end
endmodule
顶层模块:
module ip_fifo( //顶层文件
input sys_clk , // 时钟信号
input sys_rst_n // 复位信号
);
//wire define
wire wrreq ; // 写请求信号
wire [7:0] data ; // 写入FIFO的数据
wire wrempty ; // 写侧空信号
wire wrfull ; // 写侧满信号
wire wrusedw ; // 写侧FIFO中的数据量
wire rdreq ; // 读请求信号
wire [7:0] q ; // 从FIFO输出的数据
wire rdempty ; // 读侧空信号
wire rdfull ; // 读侧满信号
wire rdusedw ; // 读侧FIFO中的数据量
//*****************************************************
//** main code
//*****************************************************
//例化FIFO模块
fifo u_fifo(
.wrclk ( sys_clk ), // 写时钟
.wrreq ( wrreq ), // 写请求
.data ( data ), // 写入FIFO的数据
.wrempty ( wrempty ), // 写空信号
.wrfull ( wrfull ), // 写满信号
.wrusedw ( wrusedw ), // 写侧数据量
.rdclk ( sys_clk ), // 读时钟
.rdreq ( rdreq ), // 读请求
.q ( q ), // 从FIFO输出的数据
.rdempty ( rdempty ), // 读空信号
.rdfull ( rdfull ), // 读满信号
.rdusedw ( rdusedw ) // 读侧数据量
);
//例化写FIFO模块
fifo_wr u_fifo_wr(
.clk (sys_clk ), // 写时钟
.rst_n (sys_rst_n), // 复位信号
.wrreq (wrreq ), // 写请求
.data (data ), // 写入FIFO的数据
.wrempty (wrempty ), // 写空信号
.wrfull (wrfull ) // 写满信号
);
//例化读FIFO模块
fifo_rd u_fifo_rd(
.clk (sys_clk ), // 读时钟
.rst_n (sys_rst_n), // 复位信号
.rdreq (rdreq ), // 读请求
.data (q ), // 从FIFO输出的数据
.rdempty (rdempty ), // 读空信号
.rdfull (rdfull ) // 读满信号
);
endmodule
仿真文件
`timescale 1 ns/ 1 ns
module ip_fifo_tb();
parameter T = 20;
reg sys_clk;
reg sys_rst_n;
wire wrreq ; // 写请求信号
wire [7:0] data ; // 写入FIFO的数据
wire wrempty ; // 写侧空信号
wire wrfull ; // 写侧满信号
wire wrusedw ; // 写侧FIFO中的数据量
wire rdreq ; // 读请求信号
wire [7:0] q ; // 从FIFO输出的数据
wire rdempty ; // 读侧空信号
wire rdfull ; // 读侧满信号
wire rdusedw ; // 读侧FIFO中的数据量
initial
begin
sys_clk = 1'b0;
sys_rst_n = 1'b0;
#200
sys_rst_n = 1'b1;
//模拟发送一帧数据
#1500000 $stop;
end
always #(T/2) sys_clk = ~sys_clk;
fifo u_fifo(
.wrclk ( sys_clk ), // 写时钟
.wrreq ( wrreq ), // 写请求
.data ( data ), // 写入FIFO的数据
.wrempty ( wrempty ), // 写空信号
.wrfull ( wrfull ), // 写满信号
.wrusedw ( wrusedw ), // 写侧数据量
.rdclk ( sys_clk ), // 读时钟
.rdreq ( rdreq ), // 读请求
.q ( q ), // 从FIFO输出的数据
.rdempty ( rdempty ), // 读空信号
.rdfull ( rdfull ), // 读满信号
.rdusedw ( rdusedw ) // 读侧数据量
);
//例化写FIFO模块
fifo_wr u_fifo_wr(
.clk (sys_clk ), // 写时钟
.rst_n (sys_rst_n), // 复位信号
.wrreq (wrreq ), // 写请求
.data (data ), // 写入FIFO的数据
.wrempty (wrempty ), // 写空信号
.wrfull (wrfull ) // 写满信号
);
//例化读FIFO模块
fifo_rd u_fifo_rd(
.clk (sys_clk ), // 读时钟
.rst_n (sys_rst_n), // 复位信号
.rdreq (rdreq ), // 读请求
.data (q ), // 从FIFO输出的数据
.rdempty (rdempty ), // 读空信号
.rdfull (rdfull ) // 读满信号
);
endmodule