一 介绍
通过仿真FIFO IP,进一步理解FIFO工作机制以及各信号变化情况。
二 fifo配置
1 first word fall through类型
配置一个FIFO,配置参数如下图,关键参数,read mode选择first word fall through,数据宽度8,深度2048,设置prog full阈值为1279,勾选输出count标识。
2 standard fifo类型
与first类型的区别如下:
三 仿真代码功能描述
复位后,向fifo中写数据,写满后,再依次读出来,fifo为空后再次写数据,按此无限循环。
四 仿真结果
1 first word fall through类型
仿真图形如下
上图,系统复位后开始往fifo中写数据,可以发现:
- wr_en有效,则往fifo写入din的数据,同时count计数增加1。
- fifo存了2个数据,empty信号才有效。
- empty有效后,dout引脚出现fifo中的第一个数据。
上图,fifo写入prog full设置的阈值1279个数据后,prog full信号有效。
上图,fifo写满,可以发现:
- fifo设置的深度为2048,但是full信号在fifo存了2049个数据后才有效,并且full有效时还能写入1个数据,fifo能够存放2050个数据。
- rd_en有效,从fifo读出数据,同时count计数减1。
上图,fifo数据读完,fifo没有数据时empty有效。
2 standard fifo类型
仿真图如下:
上图,系统复位后开始往fifo中写数据,可以发现:
- wr_en有效,向fifo写数据,count计数加1;
- fifo有数据后,empty信号立马有效;
- dout引脚一直为0;
上图,fifo内存有1279个数据后,prog_full有效。
上图,fifo写满,可以发现:
- fifo存满2048个数据后再向fifo中写数据,full会有效,同时count溢出,从下图可以看出差异(下图是修改了testbench代码,修改wr_en拉低时刻),实际fifo可以存放2049个数据,之后无法向fifo中写入数据;
- full有效期间,count计数器溢出,标明fifo中有2049个数据,之后wr_en有效但不会写入数据,这个在下图读出fifo数据仿真图中是可以看到。
- rd_en有效,同时count开始减1,从溢出状态变为2047。
- dout从rd_en有效2个时钟后开始输出数据。
上图,fifo读空,可以发现:
- dout数据相较rd_en延迟2个时钟才输出。
- empty有效期间,rd_en没有意义,不会从fifo中读出数据。
- empty上升沿到来时,实际fifo还有2个数据没有输出。
五 结论
对比fifo的两种read mode模式,如下:
stardard mode | first word fall through | |
dout输出fifo数据的时刻 (相较于rd_en信号延迟时钟数) | 0 | 2 |
fifo容量 | 2049 | 2050 |
full有效时刻 | fifo存满2049 | fifo存满2050 |
full无效时刻 | rd_en有效 | rd_en有效 |
empty有效时刻 | count =0 | count=0 |
empty无效时刻 | count=0 | count = 2 |
prog_flag有效时刻 | count=1279 | count=1279 |
仿真代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 09/21/2022 02:08:52 PM
// Design Name:
// Module Name: tb_fifo
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_fifo(
);
reg clk;
reg srst;
reg [7:0] din;
reg wr_en;
reg rd_en;
wire [7:0] dout;
wire full;
wire empty;
wire [10:0] data_count;
wire prog_full;
wire wr_rst_busy;
wire rd_rst_busy;
initial begin
clk = 0;
srst = 1;
din =0;
wr_en = 0;
rd_en = 0;
#100;
srst =0;
end
always #5 clk = ~clk;
reg [1:0] st;
always @(posedge clk)begin
if(~srst)begin
case(st)
2'd0:begin//wr
wr_en <= 1'b1;
din <= din + 1'b1;
if(data_count == 11'd2046)begin//full
st <= 2'd1;
wr_en <= 1'b0;
din <= 8'd0;
end
end
2'd1:begin
rd_en <= 1'b1;
if(empty)begin
rd_en <= 1'b0;
st <= 1'b0;
end
end
default:begin
st <= 1'b0;
end
endcase
end
else begin
din <= 0;
wr_en <= 0;
rd_en <= 0;
st <= 0;
end
end
// fifo_generator_0 your_instance_name ( //first
// .clk(clk), // input wire clk
// .srst(srst), // input wire srst
// .din(din), // input wire [7 : 0] din
// .wr_en(wr_en), // input wire wr_en
// .rd_en(rd_en), // input wire rd_en
// .dout(dout), // output wire [7 : 0] dout
// .full(full), // output wire full
// .empty(empty), // output wire empty
// .data_count(data_count), // output wire [11 : 0] data_count
// .prog_full(prog_full), // output wire prog_full
// .wr_rst_busy(wr_rst_busy), // output wire wr_rst_busy
// .rd_rst_busy(rd_rst_busy) // output wire rd_rst_busy
// );
fifo_generator_0 your_instance_name (//stardard fifo
.clk(clk), // input wire clk
.srst(srst), // input wire srst
.din(din), // input wire [7 : 0] din
.wr_en(wr_en), // input wire wr_en
.rd_en(rd_en), // input wire rd_en
.dout(dout), // output wire [7 : 0] dout
.full(full), // output wire full
.empty(empty), // output wire empty
.data_count(data_count), // output wire [10 : 0] data_count
.prog_full(prog_full), // output wire prog_full
.wr_rst_busy(wr_rst_busy), // output wire wr_rst_busy
.rd_rst_busy(rd_rst_busy) // output wire rd_rst_busy
);
endmodule