Verilog | FIFO简单实现
FIFO( First Input First Output)简单说就是指先进先出,也是缓存机制的一种,下面是我总结的 FIFO 的三大用途:
1)提高传输效率,增加 DDR 带宽的利用率。比如我们有 4 路视频数据缓存到 DDR 中去,比较笨的方法是,每个通道视频数据对应一颗 DDR。现在对于 DDR 来说非常浪费,因为现在的 DDR3 可以跑 1600Mbps DDR4 可以跑到2400Mbps,如果你还是把一路视频数据对应一颗 DDR 显然严重浪费了带宽。加入 FIFO 后,只要把 4 路数据先缓存进入 DDR,在缓存的过程中,快速得把数据从 FIFO 取出并且写入到 DDR 中,只要 FIFO 没有满就不会出现数据丢失。现在我们带宽够用,FIFO 给的足够大就可以确保数据不丢失。
2)数据位宽转换,比如我们有 32bit 的数据需要转换成 128bit 或者 32bit 的数据需要转换成 8bit,那么用 FIFO 来转换也是非常方便的。
3)跨时钟域的应用,比如数据是 2 个不同步的时钟,那么我们就可以用 FIFO 实现跨时钟域的传输。
以上总计的三点,很多时候是混合使用的。
FIFO的重点和难点是空满状态的判断。
同步FIFO
同步FIFO是指读写数据使用的是同一个时钟,所以不用进行跨时钟域处理。有两种设计方法:高位扩展法和计数器法
本程序设置了统计FIFO内部数据数量的计数器cnt,并根据计数器的大小判断空满。设FIFO的深度是DEPTH,如果cnt==0,说明FIFO内没有数据;如果cnt==DEPTH,说明FIFO已存满。
计数器根据读写信号自增或者自减。当读写同时进行时,计数器数值不变;当有效写入时计数器减1;当有效读取时,计数器加1。
`timescale 1ns/1ns
/**********************************RAM************************************/
module dual_port_RAM #(parameter DEPTH = 16,parameter WIDTH = 8)(input wclk,input wenc,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。,input [WIDTH-1:0] wdata //数据写入,input rclk,input renc,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。,output reg [WIDTH-1:0] rdata //数据输出
);reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];always @(posedge wclk) beginif(wenc)RAM_MEM[waddr] <= wdata;
end always @(posedge rclk) beginif(renc)rdata <= RAM_MEM[raddr];
end endmodule /**********************************SFIFO************************************/
module sfifo#(parameter WIDTH = 8,parameter DEPTH = 16
)(input clk , input rst_n ,input winc ,input rinc ,input [WIDTH-1:0] wdata ,output reg wfull ,output reg rempty ,output wire [WIDTH-1:0] rdata
);reg [$clog2(DEPTH)-1:0] waddr, raddr;reg [$clog2(DEPTH) :0] cnt;always@(posedge clk or negedge rst_n) beginif(~rst_n)waddr <= 0;elsewaddr <= winc&~wfull? waddr+1: waddr;endalways@(posedge clk or negedge rst_n) beginif(~rst_n)raddr <= 0;elseraddr <= rinc&~rempty? raddr+1:raddr;endalways@(posedge clk or negedge rst_n) beginif(~rst_n)cnt <= 0;else if(rinc&~rempty&winc&~wfull)cnt <= cnt;else if(winc&~wfull)cnt <= cnt + 1;else if(rinc&~rempty)cnt <= cnt - 1;elsecnt <= cnt;endalways@(posedge clk or negedge rst_n) beginif(~rst_n) beginwfull = 0;rempty = 0;endelse beginwfull = cnt == DEPTH;rempty = cnt == 0;endenddual_port_RAM #(.DEPTH(DEPTH ),.WIDTH(WIDTH ))myRAM(.wclk (clk ), .wenc (winc&~wfull ), .waddr(waddr ), .wdata(wdata ), .rclk (clk ), .renc (rinc&~rempty), .raddr(raddr ), .rdata(rdata ));
endmodule
异步FIFO
异步FIFO的与同步FIFO的核心区别是它的读时钟和写时钟是不同步的。所以用对比读写地址的方法产生空满信号时,要进行跨时钟域处理。为了降低亚稳态可能性,异步FIFO还引入了格雷码。同时,格雷码也更方便产生空满信号。
| 二进制 | 写地址 | 读地址 | 格雷码 | 写地址 | 读地址 |
|---|---|---|---|---|---|
| 空FIFO | 0 0000 | 0 0000 | 0 0000 | 0 0000 | |
| 写满 | 1 0000 | 0 0000 | 1 1000 | 0 0000 | |
| 读空 | 1 0000 | 1 0000 | 1 1000 | 1 1000 | |
| 写满 | 0 0000 | 1 0000 | 0 0000 | 1 1000 | |
| 读空 | 0 0000 | 0 0000 | 0 0000 | 0 0000 |
FIFO深度为16时,地址位宽位5,当最高位和次高位不相同,其余位相同认为是写满;当所有位相同认为是读空。


异步FIFO主要包含四部分:读写地址发生器、格雷码的产生与打拍、空满信号发生器以及RAM。
`timescale 1ns/1ns/***************************************RAM*****************************************/
module dual_port_RAM #(parameter DEPTH = 16,parameter WIDTH = 8)(input wclk,input wenc,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。,input [WIDTH-1:0] wdata //数据写入,input rclk,input renc,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。,output reg [WIDTH-1:0] rdata //数据输出
);reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];always @(posedge wclk) beginif(wenc)RAM_MEM[waddr] <= wdata;
end always @(posedge rclk) beginif(renc)rdata <= RAM_MEM[raddr];
end endmodule /***************************************AFIFO*****************************************/
module asyn_fifo#(parameter WIDTH = 8,parameter DEPTH = 16
)(input wclk , input rclk , input wrstn ,input rrstn ,input winc ,input rinc ,input [WIDTH-1:0] wdata ,output wire wfull ,output wire rempty ,output wire [WIDTH-1:0] rdata
);parameter addr_width = $clog2(DEPTH);//写指针--二进制reg [addr_width:0]wptr_bin,rptr_bin;always@(posedge wclk or negedge wrstn)beginif(!wrstn) wptr_bin <= 0;else if(winc && !wfull) wptr_bin <= wptr_bin +1;else ;end//读指针--二进制always@(posedge rclk or negedge rrstn)beginif(!rrstn) rptr_bin <= 0;else if(rinc && !rempty) rptr_bin <= rptr_bin +1;else ;end// 指针二进制转格雷码wire [addr_width:0]wptr_gray,rptr_gray;assign wptr_gray = wptr_bin ^ wptr_bin>>1;assign rptr_gray = rptr_bin ^ rptr_bin>>1;//reg [addr_width:0]wptr,rptr;always @(posedge wclk or negedge wrstn)beginif(!wrstn) wptr <= 0;else wptr <= wptr_gray;end// always @(posedge rclk or negedge rrstn)beginif(!rrstn) rptr <= 0;else rptr <= rptr_gray;end// 经两级锁存器进行时钟同步reg [addr_width:0]sync_r2w,rptr_temp,sync_w2r,wptr_temp;// 写时针同步always @(posedge wclk or negedge wrstn)beginif(!wrstn) beginsync_r2w <= 0 ;rptr_temp <= 0;endelse beginrptr_temp <= rptr;sync_r2w <= rptr_temp;endend// 读时针同步always @(posedge rclk or negedge rrstn)beginif(!rrstn) beginsync_w2r <= 0 ;wptr_temp <= 0;endelse beginwptr_temp <= wptr;sync_w2r <= wptr_temp;endend// 判断写满读空状态assign wfull = wptr == {~sync_r2w[addr_width:addr_width-1],sync_r2w[addr_width-2:0]};assign rempty = rptr == sync_w2r;// 读数据(调用ram)dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH))dual_port_RAM(.wclk(wclk),.wenc(winc && !wfull),.waddr(wptr_bin[addr_width-1:0]),.wdata(wdata),.rclk(rclk),.renc(rinc && !rempty),.raddr(rptr_bin[addr_width-1:0]),.rdata(rdata));endmodule
补充
- 空和满时,读写指针末尾不一定全是0哦。换句话说,fifo的工作过程不一定是:先写满再读空再写满再读空这样的,也可能是边读边写,甚至可能同时读写。因此假设读指针为10011,写指针为00011(二进制),这也是fifo满。
- 亚稳态是在时钟跳变时,寄存器采样到一个逻辑0和逻辑1参考电压的中间值,这是亚稳态的概念。而亚稳态经过一段时间逐渐恢复成逻辑0或1,而具体会成为0还是1这件事是无法预测的。说回来,出现亚稳态的原因根源是被采样信号在时钟沿发生了跳变。一般情况下,同步时钟在保证setup和hold的情况下不会出现亚稳态(这也同步时钟不需要转格雷码的原因),而异步时钟相位关系无法设定,有可能同步前的信号正好在目标时钟沿跳变,有概率出现亚稳态,使用格雷码降低这种概率。一旦格雷码在跳变时也出现亚稳态,因为亚稳态最终也会恢复成逻辑0或1嘛,所以亚稳态后的格雷码相比于跳变前也可能会出现两种情况:正常跳变或者没有跳变。对于正常跳变,当然不会对结果产生任何影响;对于非正常跳变也就是格雷码没有跳变,会使被同步的指针更加保守,而可能加剧假空或者假满的程度,但不会造成功能错误,这也是选择用格雷码跨时钟的重要原因。
相关文章:
Verilog | FIFO简单实现
FIFO( First Input First Output)简单说就是指先进先出,也是缓存机制的一种,下面是我总结的 FIFO 的三大用途: 1)提高传输效率,增加 DDR 带宽的利用率。比如我们有 4 路视频数据缓存到 DDR 中去,比较笨的方法是&#x…...
设计模式应用场景
设计模式简介 工厂模式(Factory Pattern):使用工厂方法创建对象,而不是使用new关键字直接实例化对象。 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关对象的接口,…...
还在老一套?STM32使用新KEIL5的IDE,全新开发模式RTE介绍及使用
Keil新版本出来了,推出了一种全新开发模式RTE框架( Run-Time Environment),更好用了。然而网上的教程资料竟还都是把Keil5当成Keil4来用,直接不使用这个功能。当前正点原子或野火的教程提供的例程虽有提到Keil5,但也是基本上当Kei…...
Java时间类(十一) -- Date类工具类 -- Java获取当天、本周、本月、本年 开始及结束时间
目录 1. 今天的日期如下: 2. DateUtils工具类的源代码: 3. 测试类 1. 今天的日期如下:...
Alma Linux 9.2、Rocky Linux 9.2现在是RHEL 9.2的替代品
随着Red Hat Enterprise Linux (RHEL) 9.2的发布,Alma Linux 9.2和Rocky Linux 9.2成为了RHEL 9.2的备选替代品。这两个Linux发行版旨在提供与RHEL兼容的功能和稳定性,以满足那些需要企业级操作系统的用户需求。本文将详细介绍Alma Linux 9.2和Rocky Lin…...
推荐5款提高生活和工作效率的好帮手
在这个数字化时代,软件工具已经深深地影响和改变了我们的生活和工作。有着各种各样的软件工具,它们都可以在特定的领域内让我们变得更加高效,完成复杂的任务。选择一款适合你的软件工具,不但可以极大地释放生产力,也可以让生活变得更加便捷。 1.桌面图标管理工具——TileIconi…...
美团小组长薪资被应届生员工倒挂7K,不把老员工当人?
一位美团的小管理爆出,无意中看到了整个部门薪资,本以为自己算比较高的,但看完之后整个人都傻眼了。小组长的职位月薪28K,而手下组员却是35K,当天晚上抽了一包烟也没想明白是为什么。 楼主表示,自己是美团的…...
【Java多线程案例】使用阻塞队列实现生产者消费者模型
前言 本篇文章讲解多线程案例之阻塞队列。主要讲解阻塞队列的特性、实际开发中常用的到的生产者消费者模型,以及生产者消费者模型解耦合、削峰填谷的好处。并且使用 Java 多线程模拟实现一个生产者消费者模型、阻塞队列版的生产者消费者模型。 文章从什么是阻塞队列…...
Spark 3:Spark Core RDD持久化
RDD 的数据是过程数据 RDD 的缓存 # coding:utf8 import timefrom pyspark import SparkConf, SparkContext from pyspark.storagelevel import StorageLevelif __name__ __main__:conf SparkConf().setAppName("test").setMaster("local[*]")sc SparkC…...
字节跳动五面都过了,结果被刷了,问了hr原因竟说是...
摘要 说在前面,面试时最好不要虚报工资。本来字节跳动是很想去的,几轮面试也通过了,最后没offer,自己只想到几个原因:1、虚报工资,比实际高30%;2、有更好的人选,这个可能性不大&…...
Python日期带时区转换工具类总结
文章目录 1.背景2. 遇到的坑3. 一些小案例3.1 当前日期、日期时间、UTC日期时间3.2 昨天、昨天UTC日期、昨天现在这个时间点的时间戳3.3 日期转时间戳3.4 时间戳转日期3.5 日期加减、小时的加减 4. 总结5. 完整的编码 1.背景 最近项目是国际项目,所以需要经常需要用…...
视频会议产品对比分析
内网视频会议系统如何选择?有很多单位为了保密,只能使用内部网络,无法连接互联网,那些SaaS视频会议就无法使用。在内网的优秀视频会议也有很多可供选择,以下是几个常用的: 1. 宝利通:它支持多种…...
每日一练 | 华为认证真题练习Day47
1、某台路由器输出信息如下,下列说法错误的是?(多选) A. 本路由器开启了区域认证 B. 本设备出现故障,配置的Router Id和实际生效的Router ID不一致 C. 本设备生效的Router Id为10.0.12.1 D. 本设备生效的Router Id为…...
ChatIE(LLM大模型用于信息抽取)
Zero-Shot Information Extraction via Chatting with ChatGPT paper:https://arxiv.org/abs/2302.10205 利用ChatGPT实现零样本信息抽取(Information Extraction,IE),看到零样本就能大概明白这篇文章将以ChatGPT作为…...
提升企业管理效率的利器——ADManager Plus
在当今信息时代,企业的规模和复杂性不断增长,管理各个方面变得愈发具有挑战性。而在企业管理中,活跃目录(Active Directory)起着至关重要的作用。它是一种用于组织内部的用户、计算机、组和其他对象进行集中管理的目录…...
《入侵的艺术》读书心得:第六章:渗透测试中的智慧与愚昧
第六章:渗透测试中的智慧与愚昧 这些想法是愚昧的 1.任何期待渗透测试结果是“毫无破绽”、“无懈可击”…都是极其愚昧的: 第一层含义:测试的不可穷尽性原理(同软件测试) 第二层含义:作为优秀甚至只是合…...
SAP-MM-采购申请-价值特性
采购申请审批在维护价值特性时要注意是抬头价值还是行价值,要确定选择哪个,配置时对应配置。 1、创建价值特性CT04 字段名称:CEBAN-GSWRT,和CEBAN-GFWRT 抬头总价值:CEBAN-GFWRT;如果选择的是抬头审批&am…...
设计模式 - 代理模式
基本介绍: 代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理 对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的 功能操作,即扩展目标对象的功能。被代理的对象可以是远程对象、创建开销大的对象或需要安全控…...
IOC初始化 IOC启动阶段 (Spring容器的启动流程)
[toc](IOC初始化 IOC启动阶段 (Spring容器的启动流程)) IOC初始化 IOC启动阶段 (Spring容器的启动流程) Resource定位过程:这个过程是指定位BeanDefinition的资源,也就是配置文件(如xml)的位置,并将其封装成Resource对…...
Java后端入职第四天,就被要求代码回退(Git回退实战)
一、需求背景 初入职场,由于自己的失误或者对git不熟悉,把被人的代码给冲突掉了,然后需要立马回滚,对于新手开发,应该比较常见吧!或者,比较多一种情况,错误把工程add了到了暂存区,比如一些本地配置,本来就不应该提交的,又或者,开发中只提交部分代码,又想最新的提…...
MySQL报错注入实战:从错误信息读取到文件写入
1. 这不是“SQL注入教程”,而是一次真实渗透测试中的边界突破实践很多人看到“基于报错的SQL注入”第一反应是:老掉牙的技术,现在还有用?我去年在给一家本地政务系统做授权渗透时,就遇到了一个看似完全无感的登录接口—…...
多重样本分割:提升异质性处理效应估计稳定性的关键技术
1. 项目概述:为什么我们需要更稳定的异质性处理效应估计?在政策评估、药物临床试验或者互联网产品的A/B测试中,我们常常想知道一个干预措施(比如一项新政策、一种新药、一个产品功能)对不同人群的效果是否一样。这个“…...
[智能体-29]:Chatbox 一款开源、跨平台的「AI 客户端聚合工具」,它本身不提供 AI 模型,而是帮你统一接入 ChatGPT、DeepSeek、Ollama 等几乎所有主流大模
Chatbox 是一款开源、跨平台的「AI 客户端聚合工具」,它本身不提供 AI 模型,而是帮你统一接入 ChatGPT、Claude、Gemini、DeepSeek、Ollama 等几乎所有主流大模型,提供一个隐私优先、功能丰富的统一交互界面。一、核心定位与本质你可以把 Cha…...
医疗AI公平性评估:从数据复杂性到系统任意性的三支柱分析框架
1. 项目概述:当医疗AI遇上公平性拷问在医疗健康领域,机器学习模型正从实验室的“概念验证”阶段,大步迈向临床决策支持的“实战”前线。无论是预测糖尿病风险,还是辅助诊断心脏病,这些算法模型的核心承诺是:…...
Burp Suite扫描深度配置指南:被动扫描、主动扫描与自定义插入点协同调优
1. 这不是“点一下就扫完”的配置,而是扫描质量的分水岭 很多人把 Burp Suite Scanner 当成一个“自动漏洞探测器”——填个 URL,点下“Active Scan”,等它跑完弹出一堆高危告警,就以为任务完成了。我见过太多这样的场景ÿ…...
机器学习优化算法在激光等离子体加速实验中的应用与选型指南
1. 项目概述:当机器学习算法遇见激光等离子体加速在激光等离子体加速(Laser Wakefield Acceleration, LWFA)这类前沿物理实验中,我们常常面临一个经典难题:如何从一堆相互耦合、影响复杂的实验参数中,快速、…...
【Lovable高阶开发者私藏技巧】:绕过平台限制实现自定义CSS/JS注入与第三方SDK深度对接
更多请点击: https://kaifayun.com 第一章:Lovable无代码开发教程 Lovable 是一款面向业务人员与轻量级开发者的可视化应用构建平台,它通过拖拽式界面、逻辑编排画布和内置数据连接器,将复杂功能封装为可复用的模块。无需编写传统…...
山东防爆监控哪个品牌好用
在当前的工业生产环境中,尤其是矿山、石化、制药等高危行业,防爆监控设备已成为确保安全生产的重要工具。然而,面对市场上琳琅满目的品牌和产品,企业往往难以做出最佳选择。本次推荐的5家[主体类型],均在山东防爆监控领…...
问题不是要不要审,而是审查放在哪条路径
很多团队把输出审核接进大模型服务后,第一反应是“更安全了”,真正上线才发现另一个代价更吓人:用户看到的流式回复开始一卡一顿,P95 首包时间和整段输出时间一起抖。⚠️ 这类问题往往不是审核模型慢,而是审核位置放错…...
瑞数6代JSVMP对抗实战:Node.js环境补全与412绕过
1. 这不是“绕过验证码”,而是一场Web前端对抗的深度解剖瑞数6代,业内常被称作“JSVMP黑盒”的典型代表——它不靠传统混淆堆砌代码体积,也不依赖简单的时间戳或行为采集做判断,而是把整个校验逻辑编译进一套自定义的、高度定制化…...
