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)双击打开,进行参数设置

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

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

.

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

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

9.是否进行初始化,Next

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

11.总结页面,Generate

二、Vivado

        FIFO:First Input First Output,即先入先出队列,在计算机中,先进先出队列是一种传统的按序执行方法,先进入的指令先完成引退,接着才执行第二条指令。
主要功能包括:
(1)数据的缓冲。如果数据的写入速率高,但间隔大,且会有突发;读出速率小,但相对均匀。则通过设置相应深度的FIFO;可以起到数据暂存的功能,且能够使后续处理流程平滑,避免前级突发时,后级来不及处理而丢弃数据。
(2)时钟域的隔离。对于不同时钟域的数据传递,则数据可以通过FIFO进行隔离,避免跨时钟域的数据传输带来的设计与约束上的复杂度。
(3)不同宽度的数据接口。例如单片机8位数据输出,而DSP是16位数据输入,在单片机和DSP连接时就可以使用FIFO来达到数据匹配的目的。

基于Vivado的FIFO IP核使用实例
1、打开IP Catalog–>搜索fifo—>选择FIFO Generator
 

FIFO1


2、打开FIFO IP核的配置界面
 

FIFO2


Vivado的IP一般分为以下几个步骤:

Component Name:IP名称
Basic:基本设置
Native Ports:本地端口
Status Flags:标志位
Data Counts:数据数量
Summary:总结

一、Basic 基本设置

(1)IP核的一般命名规则:同步/一般_fifo_数据位宽_数据深度
(2) Interface Type:端口类型。一般选择第一个,AXI是Xilinx特有的高速接口。
(3)Fifo Implementation:FIFO的实现方式。
FIFO实现方式有Common Clock同步和Independent Clocks异步两种,每种FIFO下有四种存储形式:

Block RAM:使用FGPA内部的RAM。
Distributed RAM:分布式RAM,使用内部的LUT和逻辑电路组成的fifo。
Shift Register:移位寄存器形式,深度不大于32时可以使用。
Build-in:内部自带的fifo,深度大于128可以使用。

二、Native Ports本地接口

FIFO3


 

FIFO4


1.Read Mode读模式

Standard FIFO:标准FIFO。选择这个模式,读出的数据会之后使能信号1个时钟周期,第1个数据先暂存在存储单元中,当信号变为高电平后,下1个时钟周期输出;

First Word Fall Through:简称FWFT FIFO。第1个数据直接送入输出缓冲区,并保持在输出总线上,当读信号变为高电平后,当前周期输出第1个数据,第2个周期输出第2个数据。
第1个写入数据将被从ram中提前读出到读数据线,第1个数据有效与empty无效同时,即当信号有效后,读数据线将显示下一个数据地址(读出的数据与读使能信号同一个时钟周期)
 

FIFO5


Data Port Parameters 数据接口参数
write width 写宽度
write depth 写深度
read width 读宽度
read depth 读深度
(后面读的设置通常与写的设置相同)

Initialization 初始化
Reset Pin 复位引脚
Enable Safety Circuit 启用安全电路,一般都要选上
Reset Type 复位类型,有两种:异步复位和同步复位
Full Flag Reset Value 复位的值,0为低电平复位,1为高电平复位

三、Status Flag 标志位设置

FIFO6


 

FIFO7


Optional flag 选择的标志
Almost Full Flag 几乎满标志位
Almost Empty Flag 几乎空标志
Handshakiing Options 握手选项,用于设置什么时候读,什么时候写
write port handshaking 写握手选项
write acknowledge 写标志位 分为高有效和低有效
overflow 溢出标志 分为高有效和低有效
read port handshaking 写握手选项
valid flag 有效读 分为高有效和低有效
underflow flag 读空标志位 分为高有效和低有效
Programmable Flags 自定义标志位 用于自定义什么时候写满和什么时候读空的标准,可编程满或空,推荐使用可编程满或空指示信号,用于保证整包数据写入,避免数据包内的数据丢失。为保证fifo运行的可靠性,尽量多保留些阈值。
(1)Programmable Full Type 可编程写满类型
No Programmable Full Threshold 不采用可编程满
Single Programmable Full Threshold Constant 单个门限值,将门限确认和失效门限设置为同一个值
Multiple Programmbale Full Threshold Constants 单独控制PROG_FULL_THRESH_ASSERT和PROG_FULL_THRESH_NEGATE
(2)Full Threshold Assert Value 可编程满门限确认,可选端口,用于设置可编程满标记使用的确认门限,可以在复位时动态设置;拉高prog_full信号当FIFO中数据的数量大于这个值的时候。
(3) Full Threshold Negate Value 可编程满门限失效,可选端口,用于设置可编程满标记使用的失效门限,可以在复位时动态设置;拉低prog_full信号当FIFO中数据的数量小于这个值的时候。
(4)Programmable Empty Type 可编程空门限,可选端口,这个信号用于输出使可编程空标记(prog_empty)确认或失效的门限值,门限值可以在复位期间动态设置。
No Programmalbe Empty Threshold 不采用可编程读空
Single Programmable Empty Threshold Constant 可编程空门限,将确认门限和失效门限设置为同一个值,用PROG_EMPTY_THRESH
Multiple Programmbale Empty Threshold Constants 单独控制PROG_EMPTY_THRESH_ASSERT和PROG_EMPTY_THRESH_NEGATE
(5) Empty Threshold Assert Value 可编程空门限确认,可选端口,用于设置可编程空标记使用的确认门限,可以在复位时动态设置;prog_empty拉高,当FIFO中存的数据数量小于这个值。
(6) Empty Threshold Negate Value可编程空门限失效,可选端口,用于设置可编程满标志使用的失效门限,可以在复位时动态设置;prog_empty拉低,当FIFO中存的数据数量大于这个值。

四、Data Counts:数据数量

尽量不采用读/写计数,因为它采用二级制划分存储容量,会导致区分的颗粒度较大。

FIFO8

五、Summary 总结

FIFO9

六、FIFO基本原理

FIFO硬件依赖为一块RAM,实际上为一块记忆存储模块(fifo memory),特点为先写入的数据会被先读出。由于异步FIFO读写时钟的不一致,所以要比较读写地址时,首先就是要同步到同一个时钟域,依据一个时钟域来比较。同步的硬件依赖为一个二级的触发器。
当除了最高位MSB外的其他位都相同,最高位不同时则表明此时写指针超过了读指针一圈,FIFO被写满了;当除了最高位MSB外的其他位都相同,最高位相同时则表明此时写指针等于读指针,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
// --- 作者 : 木子
// --- 日期 : 2024-08-30
// --- 描述 : 数据进来,写满就开始读。normal模式和show_ahead模式对比
//==========================================================================

module fifo_ctrl
//---------------------<端口声明>-------------------------------------------
(
input  wire             clk                 , //时钟,50Mhz
input  wire             rst_n               , //复位,低电平有效
input  wire [7:0]       din                 , //输入数据
input  wire             din_vld             , //输入数据指示信号
output reg  [7:0]       dout_normal         ,
output reg  [7:0]       dout_show_ahead
);
//---------------------<信号定义>-------------------------------------------
wire [7:0]              data                ; //fifo输入的数据
wire                    rdreq               ; //fifo读请求
wire                    wrreq               ; //fifo写请求
wire [7:0]              q_normal            ; //fifo输出的数据
wire [7:0]              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>=1 && din<=10; //写进123456789 10


//--------------------------------------------------------------------------
//--   fifo 读
//--------------------------------------------------------------------------
assign rdreq = din_vld && din>=11; //第11个数后开始读


//--------------------------------------------------------------------------
//--   输出
//--------------------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        dout_normal     <= 0;
        dout_show_ahead <= 0;
    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 20 //时钟周期

module fifo_ctrl_tb;

//---------------------<端口定义>-------------------------------------------
reg                     clk                 ; //时钟,50Mhz
reg                     rst_n               ; //复位,低电平有效
reg  [7:0]              din                 ; //输入数据
reg                     din_vld             ; //输入数据指示信号
wire [7:0]              dout_normal         ;
wire [7:0]              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 = 1;
    forever
        #(`Clock/2) clk = ~clk;
end

initial begin
    rst_n = 0; #(`Clock*20+1);
    rst_n = 1;
end

//----------------------------------------------------------------------
//--   设计输入信号
//----------------------------------------------------------------------
reg     [4:0]    i;

task data;
    begin
        for(i=0;i<=20;i=i+1) begin
            din     = i;
            din_vld = 1;
            #(`Clock);
            din_vld = 0;
            #(`Clock*4);
        end
    end
endtask


initial begin
    #1;
    din     = 0;
    din_vld = 0;
    #(`Clock*20+1); //初始化完成

    data;
    #(`Clock*5);
    $stop;
end



endmodule

 

3.仿真波形

  图中信号,绿色为输入信号,红色为fifo写信号,黄色为normal模式的情况,紫色为show-ahead模式的情况。

 

4.结论

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值