在利用FPGA进行数据缓存或者数据位宽和速率的变换中,FIFO是一个使用简单,实现容易的IP核。在实际的使用中遇到一点注意事项
- 模式1:
图1.interface Type 配置
图2.Native ports 配置
测试过程:向FIFO中传入8位,输出为2位,采用同一个时钟,写使能用testbench中手动拉高,每次持续8个时钟周期,读使能条件为非空,得到的仿真结果如图3所示:
图3 仿真结果
从图中的结果可以看出,在写入第一个字节后,empty信号就会拉低为低电平,然后可以开始读数据;此时写使能信号是延迟复位信号6个时钟周期;
然后更改写使能信号,在复位后一个周期拉高,得到的实验结果为图4与图3的实验结果一致:
图4. 仿真结果
2. 模式2:
图5 配置
其他保持不变
读写时钟选择同一个时钟,写使能和读使能保持不变,然后再testbanch中让din_en信号在复位信号为高时,经过24个时钟周期后拉高使能信号,持续八个时钟周期;得到的结果如图6所示:
图6.仿真结果
提前拉高din_en信号,得到的结果图7
图7.仿真结果
继续提前这个信号得到仿真结果如图8所示
图8. 仿真结果
通过实验表明,在选择读写独立时钟进行工作时,虽然选择同一个时钟信号输入到读写时钟接口,在写入数据是需要给fifo复位之后一个处理时间,在此时间写入的数据会丢失,测试的结果是,复位之后15个时钟周期之后开始工作。
- 结果分析:
对于对模式2结果的分析,传入数据为何会在6个时钟周期后,empty才会拉低,查看应用手册PG057,
图9. 芯片手册
这里指出empty信号的latency计算公式,其中因为模式选择N=2,wr_clk(写时钟) = clk, rd_clk(读时钟) =clk, 所以这个latency的结果为6clk。
针对第二个问题,在复位信号后15个工作周期后才可以工作,
图10.reset时序图
是有关于复位的时钟的,包括同步复位和异步复位,这个在PG057的127页开始,单独介绍复位的时钟操作,
如下为使用的测试代码,
module fifotest(
input rst_n,
input clk,
input din,
output dout,
input din_en);
//生成八位数据和采样时钟
wire [7:0]fifo_din;
reg[7:0] fifo_da_temp;
wire [1:0] fifo1_dout;
always@(posedge clk)begin
if(!rst_n)begin
fifo_da_temp <= 8'b0;
end
else begin
fifo_da_temp <= 8'd66;
end
end
//定义一个分频时钟
localparam clk_cnt = 8'd9;
reg [7:0]cnt; //用于分频计数
always@(posedge clk)begin
if(!rst_n)begin
cnt <= 8'd0;
end
else begin
if(cnt >= clk_cnt)begin
cnt <= 8'd0;
end
else begin
cnt <= cnt + 8'd1;
end
end
end
reg clk_plus; //分频时钟
always@(posedge clk)begin
if(!rst_n)begin
clk_plus <= 1'b0;
end
else begin
if(cnt >= clk_cnt)begin
clk_plus <= 1'b1;
end
else begin
clk_plus <= 1'b0;
end
end
end
//输入进入fifo的信号
assign fifo_din = {fifo_da_temp[6],fifo_da_temp[7],fifo_da_temp[4],fifo_da_temp[5],fifo_da_temp[2],fifo_da_temp[3],fifo_da_temp[0],fifo_da_temp[1]};
wire empty_fifo8to2;
//fifo输入8to2
fifo_8to2 u0 (
.rst(!rst_n), // input wire rst
.wr_clk(clk), // input wire wr_clk
.rd_clk(clk), // input wire rd_clk
.din(fifo_din), // input wire [7 : 0] din
.wr_en(din_en), // input wire wr_en
.rd_en((!empty_fifo8to2) & 1'b1), // input wire rd_en
.dout(fifo1_dout), // output wire [1 : 0] dout
.full(), // output wire full
.empty(empty_fifo8to2) // output wire empty
);
//fifo_8to2 u1 (
// .clk(clk), // input wire clk
// .srst(!rst_n), // input wire srst
// .din(fifo_din), // input wire [7 : 0] din
// .wr_en(din_en), // input wire wr_en
// .rd_en((!empty_fifo8to2) & 1'b1), // input wire rd_en
// .dout(fifo1_dout), // output wire [1 : 0] dout
// .full(), // output wire full
// .empty(empty_fifo8to2) // output wire empty
//);
//wire [7:0]fifo2_dout;
//wire fifo2_empty;
ceshi fifo八位输出的数据变化过程
//fifo_2to8 u1 (
// .rst(rst_n), // input wire rst
// .wr_clk(clk), // input wire wr_clk
// .rd_clk(clk), // input wire rd_clk
// .din(fifo1_dout), // input wire [1 : 0] din
// .wr_en(clk), // input wire wr_en
// .rd_en(clk), // input wire rd_en
// .dout(fifo2_dout), // output wire [7 : 0] dout
// .full(), // output wire full
// .empty(fifo2_empty) // output wire empty
//);
endmodule
然后是testbanch代码
`timescale 1ns / 1ps
module top_tb();
reg l_clk;
reg rst_n;
wire din;
wire dout;
reg din_en;
fifotest fifotest_u0(
.rst_n(rst_n),
.clk(l_clk),
.din(din),
.dout(dout),
.din_en(din_en));
initial l_clk = 1;
always #20 l_clk= !l_clk; //15.625
always #10 data_in = 16'b100;
initial begin
rst_n <= 0;
din_en <= 0;
#320;
rst_n <= 1;
#600;
din_en <= 1;
#320;
din_en <= 0;
#18000;
din_en <= 1;
#320;
din_en <= 0;
//#50000000;
#320;
$stop;
end
endmodule