IP核——FIFO

时间:2023-03-09 16:32:50
IP核——FIFO

一、Quartus

1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager

2.弹出创建页面,选择Creat a new custom megafunction variation,点Next

IP核——FIFO

3.选择IP核,可以直接搜索fifo,选择fifo,右上方选择器件型号,语言选成Verilog,再填写一下路径名字,点Next,后面就是参数设置了。

IP核——FIFO

4.设置数据的宽度和深度,宽度即数据位宽,深度即fifo里做多存放多少个数据,深度的计算要考虑写的时刻和读的时刻以及时钟快慢。下面是选中同步时钟还是异步时钟,这里选择同步时钟,下面的设置也是基于同步时钟。如果是异步时钟则下面的设置会出现写侧和读侧两对参数进行选择,其实是一样的道理。Next

IP核——FIFO

4.选择一些指示信号,需要就选,不需要就不选,Next

IP核——FIFO

5.选择哪种模式,这还是有些学问的,图上用文字简单的说明了一下,下面做个实验来看看他们究竟有什么不同。存储类型选择默认的Auto就行。Next

IP核——FIFO

6.默认,Next

IP核——FIFO

7.默认,Next

IP核——FIFO

8.一般不勾选bb文件,finish。

IP核——FIFO

 二、ISE

1.创建ISE工程,IP核需要在ISE工程里面进行调用。点击Tools---Core Generator...

2.在新弹出来的界面中创建一个属于IP核的工程:file---new project,并填写文件存储位置和文件名称,一般为ipcore_dir文件夹,点击保存

3.弹出的Part处填写器件的系列、型号、封装以及速度等级,Generation处设置语言为Verilog,点击OK

4.点击文件夹,找到Memories & Storage Elements---FIFOs---FIFO Generator,(也可以直接搜索fifo)双击打开,进行参数设置

IP核——FIFO

5.命名,类型选择默认即可,Next

IP核——FIFO

6.选择同步或异步,一般是选中含有Block RAM的选项,Next

.IP核——FIFO

7.模式选择和宽度、深度选择。Next

IP核——FIFO

8.信号选择,需要就勾选,不需要就不勾选,Next

IP核——FIFO

9.是否进行初始化,Next

IP核——FIFO

10.是否进行数据计数,Next

IP核——FIFO

11.总结页面,Generate

IP核——FIFO

三、Normal(Standard)模式和Show-ahead(First-word fall-through)模式的区别

  对此很多书籍没有多提及,教学视频也就一两句话带过。我一直似懂非懂,于是编了个仿真来测试一下。

1.设计文件

  我例化了两个fifo,一个Normal模式的fifo,一个Show-ahead模式的fifo,他们的写数据、写使能、读使能都一样,用控制变量法观察q的输出情况。这段代码意思很简单,我设计了一个0-21的输入数据和对应输入有效指示信号。将数据为123456789 10时,这些数据写入fifo。在数据等于11 12 13 14 15 16 17 18 19 20时,将刚刚写入fifo的数据读出来。后面又加入一个dout输出,测试rdreq做if条件,后面会出现什么有趣结果。

 //==========================================================================
// --- 名称 : fifo_ctrl.v
// --- 作者 : xianyu_FPGA
// --- 日期 : 2019-01-03
// --- 描述 : 数据进来,写满就开始读。normal模式和show_ahead模式对比
//========================================================================== module fifo_ctrl
//---------------------<端口声明>-------------------------------------------
(
input wire clk , //时钟,50Mhz
input wire rst_n , //复位,低电平有效
input wire [:] din , //输入数据
input wire din_vld , //输入数据指示信号
output reg [:] dout_normal ,
output reg [:] dout_show_ahead
);
//---------------------<信号定义>-------------------------------------------
wire [:] data ; //fifo输入的数据
wire rdreq ; //fifo读请求
wire wrreq ; //fifo写请求
wire [:] q_normal ; //fifo输出的数据
wire [:] q_show_ahead ; //fifo输出的数据 //--------------------------------------------------------------------------
//-- FIFO例化
//--------------------------------------------------------------------------
ip_fifo_normal u_1
(
.clock (clk ),
.data (data ),
.rdreq (rdreq ),
.wrreq (wrreq ),
.empty ( ),
.full ( ),
.usedw ( ),
.q (q_normal )
); ip_fifo_show_ahead u_2
(
.clock (clk ),
.data (data ),
.rdreq (rdreq ),
.wrreq (wrreq ),
.empty ( ),
.full ( ),
.usedw ( ),
.q (q_show_ahead )
); //--------------------------------------------------------------------------
//-- fifo 写
//--------------------------------------------------------------------------
assign data = din;
assign wrreq = din_vld && din>= && din<=; //写进123456789 10 //--------------------------------------------------------------------------
//-- fifo 读
//--------------------------------------------------------------------------
assign rdreq = din_vld && din>=; //第11个数后开始读 //--------------------------------------------------------------------------
//-- 输出
//--------------------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
dout_normal <= ;
dout_show_ahead <= ;
end
else if(rdreq) begin
dout_normal <= q_normal;
dout_show_ahead <= q_show_ahead;
end
end endmodule

2.测试文件

  输入数据和对应指示信号,数据为:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

 `timescale 1ns/1ps  //时间精度
`define Clock //时钟周期 module fifo_ctrl_tb; //---------------------<端口定义>-------------------------------------------
reg clk ; //时钟,50Mhz
reg rst_n ; //复位,低电平有效
reg [:] din ; //输入数据
reg din_vld ; //输入数据指示信号
wire [:] dout_normal ;
wire [:] dout_show_ahead ; //--------------------------------------------------------------------------
//-- 模块例化
//--------------------------------------------------------------------------
fifo_ctrl u_fifo_ctrl
(
.clk (clk ),
.rst_n (rst_n ),
.din (din ),
.din_vld (din_vld ),
.dout_normal (dout_normal ),
.dout_show_ahead (dout_show_ahead )
); //----------------------------------------------------------------------
//-- 时钟信号和复位信号
//----------------------------------------------------------------------
initial begin
clk = ;
forever
#(`Clock/) clk = ~clk;
end initial begin
rst_n = ; #(`Clock*+);
rst_n = ;
end //----------------------------------------------------------------------
//-- 设计输入信号
//----------------------------------------------------------------------
reg [:] i; task data;
begin
for(i=;i<=;i=i+) begin
din = i;
din_vld = ;
#(`Clock);
din_vld = ;
#(`Clock*);
end
end
endtask initial begin
#;
din = ;
din_vld = ;
#(`Clock*+); //初始化完成 data;
#(`Clock*);
$stop;
end endmodule

3.仿真波形

  波形中出现了多个rdreq信号,其实是同一个,为了方便看情况,我进行了复制信号而且改了颜色罢了。图中信号,绿色为输入信号,红色为fifo写信号,黄色为normal模式的情况,紫色为show-ahead模式的情况。

IP核——FIFO

4.结论

  ①Normal:先有rdreq,q中再有数据。输出不能用rdreq做if判断,否则会丢数据,如果一定要用到rdreq搞事情,那么rdreq打一拍再用就行了。

  ②Show-ahead:q上一直有数据,有rdreq就切换到下一个数据,rdreq信号像是应答信号ack。输出可以直接用rdreq做if判断。

四、ROM、RAM和FIFO的区别

1.ROM有地址,只能读而不能写。用初始化文件mif/ceo将内容存进去,读取不会使得数据减少消失。

2.RAM有地址,可以进行寻址读写,数据写进去后,读取不会使得数据减少消失。

3.FIFO没有地址,只能是先进先出,数据写进去后,读取会使得数据减少消失,读一个少一个。

参考资料:

[1]小梅哥FPGA教程

[2]威三学院FPGA教程