Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【手撕代码】同步 FIFO、LIFO/Stack

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

作者头像
碎碎思
发布于 2023-08-30 02:20:13
发布于 2023-08-30 02:20:13
32600
代码可运行
举报
文章被收录于专栏:OpenFPGAOpenFPGA
运行总次数:0
代码可运行

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

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

为什么要自己设计FIFO

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

FIFO 规格\性能

  • 同步,单时钟。
  • 基于寄存器的 FIFO,适用于中小型 FIFO。
  • Full、Empty、Almost-full、Almost-empty 标志。
  • 完全可配置的数据宽度、深度和标志。
  • 完全可综合的系统 Verilog 代码。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*===============================================================================================================================
   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 ❞

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 OpenFPGA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
谈谈跨时钟域传输问题(CDC)
CDC(Clock Domain Conversion)问题,一直是IC前端设计,FPGA设计的热点问题,特别是在校招面试笔试时候,是问的最多的一个问题,我之前关于这个问题以及相关问题,写了一些总结,但比较分散,今天简单汇总总结一下。
Reborn Lee
2020/06/29
3.6K0
同步FIFO和异步FIFO
FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据, 其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
碎碎思
2020/06/30
2K0
FPGA基础知识极简教程(4)从FIFO设计讲起之异步FIFO篇
一开始是想既然是极简教程,就应该只给出FIFO的概念,没想到还是给出了同步以及异步FIFO的设计,要不然总感觉内容不完整,也好,自己设计的FIFO模块不用去担心因IP核跨平台不通用的缺陷!那我们开始吧。
Reborn Lee
2020/06/29
1.7K0
关于异步FIFO的知识点–详细代码解释(很干)[通俗易懂]
异步FIFO的空满也是通过地址位扩展进行,这与同步FIFO是一致的,但异步FIFO不能通过计数器进行空满判断且转换成格雷码带来的问题又与同步FIFO的判断算法不一致,这是异步FIFO的一个难点。关于格雷码的判断空满,仔细下文。
全栈程序员站长
2022/09/06
6180
关于异步FIFO的知识点–详细代码解释(很干)[通俗易懂]
【FPGA——基础篇】同步FIFO与异步FIFO——Verilog实现「建议收藏」
FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据, 其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
全栈程序员站长
2022/07/28
6.3K0
【FPGA——基础篇】同步FIFO与异步FIFO——Verilog实现「建议收藏」
​同步FIFO
FIFO 根据读和写的时钟是否为同一时钟分为同步 FIFO 和异步 FIFO 。异步 FIFO 相比同步 FIFO 来说,设计更加复杂一点。
数字芯片社区
2020/08/27
1.2K0
​同步FIFO
笔试 | 同步FIFO设计详解及代码分享(这一篇就足够~)
FPGA/数字IC笔试面试,无线通信物理层及数字信号处理,Verilog和Vivado HLS高层次综合技术。
FPGA探索者
2022/05/26
4.1K1
笔试 | 同步FIFO设计详解及代码分享(这一篇就足够~)
FPGA零基础学习:SPI 协议驱动设计
本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
FPGA技术江湖
2020/12/30
1.7K0
FIFO系列(二):同步FIFO的verilog设计
关于同步fifo的设计疑惑了半天,本以为这个代码是错的,后来自己又写了一遍,但是写到最后又觉得这个是正确的,主要是wr_cnt和rd_cnt的理解。
根究FPGA
2020/06/29
3.5K0
FPGA逻辑设计回顾(6)多比特信号的CDC处理方式之异步FIFO
异步FIFO是处理多比特信号跨时钟域的最常用方法,简单来说,异步FIFO是双口RAM的一个封装而已,其存储容器本质上还是一个RAM,只不过对其添加了某些控制,使其能够实现先进先出的功能,由于这个功能十分的实用,因此得以广泛应用。真双口RAM可以实现在一端存储,另一端读取的功能,两端的时钟可以不同,将数据存入一个容器,再取出来,这个过程在双口RAM的两端完全不存在亚稳态的问题。由于异步FIFO的实现中也存在数据的存取问题,和双口RAM类似,再加上空满信号的控制,存在跨时钟域的问题,因此只要处理好,空满信号的判断中的跨时钟域问题,就可以使用FIFO解决多比特信号的跨时钟域问题。下面从多个方面来了解一下,异步FIFO的内容,最后会给出异步FIFO的一种普遍的实现方式及其仿真,让我们一起进入今天的内容吧。
Reborn Lee
2021/01/21
1.2K0
基于FPGA的CAN总线控制器的设计(中)
今天给大侠带来基于FPGA的CAN总线控制器的设计,由于篇幅较长,分三篇。今天带来第二篇,中篇,CAN 通信控制器的具体实现。话不多说,上货。
FPGA技术江湖
2021/05/11
1.3K0
基于FPGA的CAN总线控制器的设计(中)
【收藏】FPGA数字IC刷题58个Verilog代码及讲解(状态机、跨时钟、同步/异步FIFO、DMUX、奇数/小数分频)
牛客 Verilog 刷题入门篇1~24 + 进阶篇1~34 题解代码,所有代码均能通过测试,配合视频讲解效果更佳。本文给出代码,部分题目给出必要说明。 很多题目本身出题有些问题,着重理解题目,没必要钻牛角尖。
FPGA探索者
2022/11/01
3.1K0
【收藏】FPGA数字IC刷题58个Verilog代码及讲解(状态机、跨时钟、同步/异步FIFO、DMUX、奇数/小数分频)
FPGA零基础学习:图像显示系统设计
大侠好,欢迎来到FPGA技术江湖。本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
FPGA技术江湖
2021/03/23
5560
FPGA零基础学习:图像显示系统设计
异步FIFO
如上图所示的同步模块synchronize to write clk,其作用是把读时钟域的指针rptr采集到写时钟wr_clk域,然后和写时针wptr进行比较从而产生或撤销写写满标志wfull;类似地,同步模块synchronize to read clk的作用是把写时钟域的写指针wptr采集到读时钟域,然后和读指针rptr进行比较从而产生或撤销读空标志位rempty。
数字芯片社区
2020/08/27
1.4K0
异步FIFO
FPGA基础知识极简教程(3)从FIFO设计讲起之同步FIFO篇
缩写FIFO代表 First In First Out。FIFO在FPGA和ASIC设计中无处不在,它们是基本的构建模块之一。而且它们非常方便!FIFO可用于以下任何目的:
Reborn Lee
2020/06/29
4.8K0
FPGA零基础学习:SPI 协议驱动设计(下)
该模块负责将外部写fifo中的数据写入到flash中。wr_fifo_rd为写fifo的读使能信号,wrdata为从写fifo中读出的数据,wr_len为需要写入flash中数据的长度,wr_addr为写入地址。
FPGA技术江湖
2021/03/23
1.4K0
FPGA零基础学习:SPI 协议驱动设计(下)
FPGA零基础学习:SDR SDRAM 驱动设计
本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
FPGA技术江湖
2021/03/23
1K0
FPGA零基础学习:SDR SDRAM 驱动设计
FPGA零基础学习:IP CORE 之 FIFO设计
本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
FPGA技术江湖
2021/03/22
5070
FPGA零基础学习:IP CORE 之 FIFO设计
跨时钟域传输总结(包含verilog代码|Testbench|仿真结果)
快时钟域相比慢时钟域采样速度更快,也就是说从慢时钟域来到快时钟域的信号一定可以被采集到。既然快时钟一定可以采集到慢时钟分发的数据,那么考虑的问题就只剩下如何保证采样到的信号质量!最常用的同步方法是双级触发器缓存法,俗称延迟打拍法。信号从一个时钟域进入另一个时钟域之前,将该信号用两级触发器连续缓存两次,可有效降低因为时序不满足而导致的亚稳态问题。
Loudrs
2023/06/08
5.9K1
跨时钟域传输总结(包含verilog代码|Testbench|仿真结果)
IP CORE 之 FIFO 设计- ISE 操作工具
本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
FPGA技术江湖
2020/12/30
1.1K0
相关推荐
谈谈跨时钟域传输问题(CDC)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验