【手撕代码】同步 FIFO、LIFO/Stack

2023-08-30 10:20:13 浏览数 (1)

FIFO 是FPGA设计中最有用的模块之一。FIFO 在模块之间提供简单的握手和同步机制,是设计人员将数据从一个模块传输到另一个模块的常用选择。

在这篇文章中,展示了一个简单的 RTL 同步 FIFO,可以直接在自己的设计中配置和使用它,该设计是完全可综合的。

为什么要自己设计FIFO

那么,为什么呢?网上有很多关于 FIFO 的 Verilog/VHDL 代码的资源,过去,我自己也使用过其中的一些。但令人沮丧的是,它们中的大多数都存在问题,尤其是在上溢出和下溢出条件下。所以想一劳永逸地解决这些问题。

FIFO 规格性能

  • 同步,单时钟。
  • 基于寄存器的 FIFO,适用于中小型 FIFO。
  • Full、Empty、Almost-full、Almost-empty 标志。
  • 完全可配置的数据宽度、深度和标志。
  • 完全可综合的系统 Verilog 代码。
代码语言:javascript复制
/*===============================================================================================================================
   Design       : Single-clock Synchronous FIFO

   Description  : Fully synthesisable, configurable Single-clock Synchronous FIFO based on registers.
                  - Configurable Data width.
                  - Configurable Depth.
                  - Configurable Almost-full and Almost-empty signals. 
===============================================================================================================================*/

module my_fifo #(
                   parameter DATA_W           = 4      ,        // Data width
                   parameter DEPTH            = 8      ,        // Depth of FIFO                   
                   parameter UPP_TH           = 4      ,        // Upper threshold to generate Almost-full
                   parameter LOW_TH           = 2               // Lower threshold to generate Almost-empty
                )

                (
                   input                   clk         ,        // Clock
                   input                   rstn        ,        // Active-low Synchronous Reset
                   
                   input                   i_wren      ,        // Write Enable
                   input  [DATA_W - 1 : 0] i_wrdata    ,        // Write-data
                   output                  o_alm_full  ,        // Almost-full signal
                   output                  o_full      ,        // Full signal

                   input                   i_rden      ,        // Read Enable
                   output [DATA_W - 1 : 0] o_rddata    ,        // Read-data
                   output                  o_alm_empty ,        // Almost-empty signal
                   output                  o_empty              // Empty signal
                );


/*-------------------------------------------------------------------------------------------------------------------------------
   Internal Registers/Signals
-------------------------------------------------------------------------------------------------------------------------------*/

logic [DATA_W - 1        : 0] data_rg [DEPTH] ;        // Data array
logic [$clog2(DEPTH) - 1 : 0] wrptr_rg        ;        // Write pointer
logic [$clog2(DEPTH) - 1 : 0] rdptr_rg        ;        // Read pointer
logic [$clog2(DEPTH)     : 0] dcount_rg       ;        // Data counter
      
logic                         wren_s          ;        // Write Enable signal generated iff FIFO is not full
logic                         rden_s          ;        // Read Enable signal generated iff FIFO is not empty
logic                         full_s          ;        // Full signal
logic                         empty_s         ;        // Empty signal


/*-------------------------------------------------------------------------------------------------------------------------------
   Synchronous logic to write to and read from FIFO
-------------------------------------------------------------------------------------------------------------------------------*/
always @ (posedge clk) begin

   if (!rstn) begin     
          
      data_rg   <= '{default: '0} ;
      wrptr_rg  <= 0              ;
      rdptr_rg  <= 0              ;      
      dcount_rg <= 0              ;

   end

   else begin

      ready_rg <= 1'b1 ;
      
      /* FIFO write logic */            
      if (wren_s) begin                          
         
         data_rg [wrptr_rg] <= i_wrdata ;        // Data written to FIFO

         if (wrptr_rg == DEPTH - 1) begin
            wrptr_rg <= 0               ;        // Reset write pointer  
         end

         else begin
            wrptr_rg <= wrptr_rg   1    ;        // Increment write pointer            
         end

      end

      /* FIFO read logic */
      if (rden_s) begin         

         if (rdptr_rg == DEPTH - 1) begin
            rdptr_rg <= 0               ;        // Reset read pointer
         end

         else begin
            rdptr_rg <= rdptr_rg   1    ;        // Increment read pointer            
         end

      end

      /* FIFO data counter update logic */
      if (wren_s && !rden_s) begin               // Write operation
         dcount_rg <= dcount_rg   1 ;
      end                    
      else if (!wren_s && rden_s) begin          // Read operation
         dcount_rg <= dcount_rg - 1 ;         
      end

   end

end


/*-------------------------------------------------------------------------------------------------------------------------------
   Continuous Assignments
-------------------------------------------------------------------------------------------------------------------------------*/

// Full and Empty internal
assign full_s      = (dcount_rg == DEPTH) ? 1'b1 : 0 ;
assign empty_s     = (dcount_rg == 0    ) ? 1'b1 : 0 ;

// Write and Read Enables internal
assign wren_s      = i_wren & !full_s                ;  
assign rden_s      = i_rden & !empty_s               ;

// Full and Empty to output
assign o_full      = full_s                          ;
assign o_empty     = empty_s                         ;

// Almost-full and Almost Empty to output
assign o_alm_full  = (dcount_rg > UPP_TH) ? 1'b1 : 0 ;
assign o_alm_empty = (dcount_rg < LOW_TH) ? 1'b1 : 0 ;

// Read-data to output
assign o_rddata    = data_rg [rdptr_rg]              ;   


endmodule

/*=============================================================================================================================*/

基于 RAM 的 FIFO

在上面的步骤中,我们看到了一个基于寄存器的同步FIFO。接下来,我们来看看基于 RAM 的 FIFO。该 FIFO 在 RAM 而不是寄存器上实现其数据阵列。这适用于在硬件上实现大型 FIFO ;特别是在 FPGA 上,FPGA 里有大量的Block RAM 可用。这将降低资源利用率,也可以获得更好的时序性能。

详细代码:

❝https://github.com/iammituraj/FIFOs ❞

0 人点赞