数字IC前端学习笔记:FIFO的Verilog实现(一)

相关文章

数字IC前端学习笔记:LSFR(线性反馈移位寄存器)

数字IC前端学习笔记:跨时钟域信号同步

数字IC前端学习笔记:信号同步和边沿检测

数字IC前端学习笔记:锁存器Latch的综合

数字IC前端学习笔记:格雷码(含Verilog实现的二进制格雷码转换器)

数字IC前端学习笔记:FIFO的Verilog实现(二)

数字IC前端学习笔记:仲裁轮询(一)

数字IC前端学习笔记:仲裁轮询(二)

数字IC前端学习笔记:仲裁轮询(三)

数字IC前端学习笔记:仲裁轮询(四)

数字IC前端学习笔记:仲裁轮询(五)

数字IC前端学习笔记:仲裁轮询(六)

数字IC前端学习笔记:近期最少使用(LRU)算法


目录

1.引言

2.FIFO操作

3.同步FIFO原理

4.同步FIFO的Verilog实现


1.引言

        FIFO表示先入先出(First in First out),它是一种存储器结构,被广泛用于芯片设计中。FIFO由存储器单元队列或阵列组成,如名所示,先被写入队列的数据也是先被读出。在芯片设计中,FIFO可以满足下列需求:

        (1)当输入数据速率和输出速率不匹配时,作为临时存储单元。例如,CPU可以先将数据写入FIFO,然后继续做其他工作,设备可以很方便地从FIFO中读取数据。再如因特网控制器,它将从网络接收来的数据存入FIFO,后端的DMA(Direct Memory Access,直接存储器访问)控制器(位于PCIe或PCI接口电路中)从FIFO中读取数据,然后写入系统存储器。

        (2)用于不同时钟域之间的同步。实际应用中,数据有时会从一个时钟域进入另一个时钟域,此时FIFO不仅做临时数据存储单元,也起到数据同步的作用。

        (3)输入数据和输出数据的数据宽度不匹配时,可以用数据宽度调整电路。

        我们在后面再详细介绍这些应用,现在先给出FIFO的结构和输入输出端口,如下图所示,宽度为6、深度为8的FIFO。这意味着此FIFO中有8个存储位置,每个位置可以存储6位数据。注意,实际上读写指针对于外部是不可见的,图中画出只是为了后面说明方便。

2.FIFO操作

        电路复位后,FIFO为空,写指针和读指针都指向同一个位置,该位置通常是0。数据由write_data端口输入,由控制信号write_en控制,由read_data端口输出,由控制信号read_en控制。write_pointer指针指向下一个可能的空位置(队列尾元素的后一个位置),而read_pointer指向下一个被读取的位置(队列首元素)。我们一般采取循环队列的方式构建FIFO,即如果我们持续写入,当write_pointer指向最大值时(例如111),如果再次写入元素,write_pointer将回到0。读指针也拥有这种循环的性质,换句话说,写指针和读指针以环形的方式移动,写指针在前,读指针在后追随。写操作和读操作也被称为push/pop、put/get或fill/drain操作。

        我们也可以同时进行读操作和写操作,因为两种操作使用不同的指针、控制信号和数据总线。FIFO的这种操作就像一个水箱,它有一个进水口让水进入水箱,还有一个出口让水流出水箱。在任何时候,可以一边进水一边放水,我们需要关注的是,除了FIFO空或满,读指针和写指针不能相同。我们要确保两种情况不会发生,一是给满的FIFO写入数据(所有位置都有数据,没有多余位置);二是从空的FIFO中读取数据(FIFO中没有有效数据)。它们分别被称为上溢(overrun)和下溢(underrun)。FIFO会产生fifo_full和fifo_empty信号,用于表示FIFO是否已满或已空。当FIFO为满时,禁止写入数据;当FIFO为空时,禁止继续读取数据。

        在详细叙述前,先通过时序图来进一步增强我们的理解,如下图所示。

3.同步FIFO原理

         在同步FIFO中,单一时钟用于写入和读取操作。数据流和相关的控制逻辑在一个时钟域内工作。同步FIFO用于临时存储数据,此时写入和读取操作即可以同时发生,也可以发生在不同时刻。由于同步FIFO只使用了一个时钟,其控制逻辑相对于异步FIFO来说简单得多前面讨论过一些输入和输出端口,现在需要增加一些有用的输出,如fifo_full、fifo_empty、room_available、data_available。从名称中可以看出,fifo_full信号表示FIFO为满,fifo_empty表示FIFO为空。这两个信号作为边界条件,提醒外部电路不要写满的FIFO和读空的FIFO。

        FIFO还可能提供其他信号,如almost_full和almost_empty,用于提前提供FIFO的满和空的信息。例如,当做设计的FIFO还剩余2到3个空余位置时,almost_full信号有效,此时负责外围写入的电路就要考虑停止写入了,因为从决定停止到write_en信号被置为无效可能还需要多个时钟周期。如果写入逻辑等待fifo_full标识有效后才将write_en信号置为无效,就可能太迟了,可能会有信号被错误写入或遗漏(取决于是否有保险措施)。almost_empty也采用类似的工作方式用于防止数据下溢。相较于almost_full和almost_empty信号,我们有时更愿意使用room_available和data_available来提供准确的剩余空间和数据深度信息(本文下面的FIFO就是使用了这两个信号)。写逻辑使用room_available,因为它关注还有多少空间,读逻辑使用data_available,因为它关注还有多少数据可读。

4.同步FIFO的Verilog实现

module synch_fifo  #(parameter FIFO_PTR = 4,
                               FIFO_WIDTH = 32,
                               FIFO_DEPTH = 16)
                   (fifo_clk,rstb,
                    fifo_wren,
                    fifo_wrdata,
                    fifo_rden,
                    fifo_rddata,
                    fifo_full,
                    fifo_empty,
                    fifo_room_avail,
                    fifo_data_avail);
//端口声明
//*******************************************************
input                          fifo_clk;
input                          rstb;
input                          fifo_wren;
input   [FIFO_WIDTH - 1 : 0]   fifo_wrdata;
input                          fifo_rden;
input   [FIFO_WIDTH - 1 : 0]   fifo_rddata;
output  reg                    fifo_full;
output  reg                    fifo_empty;
output  reg [FIFO_PTR : 0]     fifo_room_avail;
output  [FIFO_PTR : 0]         fifo_data_avail; 

//变量定义
//*******************************************************
reg [FIFO_PTR-1 : 0]           wr_ptr,wr_ptr_nxt;
reg [FIFO_PTR-1 : 0]           rd_ptr,rd_ptr_nxt;
reg [FIFO_PTR : 0]             num_entries,num_entries_nxt;
reg [FIFO_PTR : 0]             fifo_room_avail;
reg                            fifo_full,fifo_empty;
wire [FIFO_PTR : 0]            fifo_room_avail_nxt;
wire [FIFO_PTR : 0]            fifo_data_avail_nxt;
wire                           fifo_full_nxt,fifo_empty_nxt;

//写指针控制逻辑
//*******************************************************
always@(*) begin
    wr_ptr_nxt = wr_ptr;
    if(fifo_wren) begin
        if(wr_ptr == FIFO_DEPTH - 1)
            wr_ptr_nxt = 0;
        else
            wr_ptr_nxt = wr_ptr + 1;
    end
end

//读指针控制逻辑
//*******************************************************
always@(*) begin
    rd_ptr_nxt = rd_ptr;
    if(fifo_rden) begin
        if(rd_ptr == FIFO_DEPTH - 1)
            rd_ptr_nxt = 0;
        else
            rd_ptr_nxt = rd_ptr + 1;
    end
end

//计算FIFO内的数据量
//*******************************************************
always@(*) begin
    num_entries_nxt = num_entries;
    if(fifo_wren && fifo_rden)
        num_entries_nxt = num_entries;
    else if(fifo_wren)
        num_entries_nxt = num_entries + 1;
    else if(fifo_rden)
        num_entries_nxt = num_entries - 1;
end

//产生提示信号
//*******************************************************
assign fifo_full_nxt = (num_entries_nxt == FIFO_DEPTH);
assign fifo_empty_nxt = (num_entries_nxt == 0);
assign fifo_data_avail = num_entries;
assign fifo_room_avail_nxt = (FIFO_DEPTH - num_entries_nxt);

//寄存器操作
//*******************************************************
always@(posedge fifo_clk or negedge rstb) begin
    if(!rstb) begin
        wr_ptr       <=  0;
        rd_ptr       <=  0;
        num_entries  <=  0;
        fifo_full    <=  0;
        fifo_empty   <=  0;
        fifo_room_avail <=0;
    end
    else begin
        wr_ptr       <=    wr_ptr_nxt;
        rd_ptr       <=    rd_ptr_nxt;
        num_entries  <=    num_entries_nxt;
        fifo_full    <=    fifo_full_nxt;
        fifo_empty   <=    fifo_empty_nxt;
        fifo_room_avail <= fifo_room_avail_nxt;
    end
    
end

//可以自己写一个存储器,也可以直接例化存储器ip(这里选择后者)
//*******************************************************
sram        #(.FIFO_PTR (FIFO_PTR),
              .FIFO_WIDTH (FIFO_WIDTH)) sram_0
            
            (.wrclk(fifo_clk),
             .wren(fifo_wren),
             .wrptr(wr_ptr),
             .wrdata(fifo_wrdata),
             .rdclk(fifo_clk),
             .rden(fifo_rden),
             .rdptr(rd_ptr),
             .rddata(fifo_rddata));

endmodule
            

以上内容来源于《Verilog高级数字系统设计技术和实例分析》

猜你喜欢

转载自blog.csdn.net/weixin_45791458/article/details/129936780