当前位置: 首页 > news >正文

Verilog功能模块——同步FIFO


前言

FIFO功能模块分两篇文章,本篇为同步FIFO,另一篇为异步FIFO,传送门:

Verilog功能模块——异步FIFO-CSDN博客

同步FIFO实现起来是异步FIFO的简化版,所以,本博文不再介绍FIFO实现原理,感兴趣的同学可以去看我异步FIFO的文章,基本看懂了异步FIFO,同步FIFO自然就懂了。


二. 模块功能框图与信号说明

信号说明:

分类信号名称输入/输出说明
参数DATA_WIDTH数据位宽
ADDR_WIDTH地址位宽,FIFO深度=2**ADDR_WIDTH
FWFT_ENFirst word fall-through输出模式使能,高电平有效
FIFO写端口dininputFIFO数据输入
wr_eninputFIFO写使能
fulloutputFIFO满信号
almost_fulloutputFIFO快满信号,FIFO剩余容量<=1时置高
FIFO读端口doutoutputFIFO数据输出
rd_eninputFIFO读使能
emptyoutputFIFO空信号
almost_emptyoutputFIFO快空信号,FIFO内数据量<=1时置高
时钟与复位clkinputFIFO读时钟
rstinputFIFO读复位

注意:

  1. 信号的命名与Vivado中的FIFO IP核完全一致
  2. 复位均为高电平复位,与Vivado中的FIFO IP核保持一致
  3. 复位为异步复位
  4. FIFO深度通过ADDR_WIDTH来设置,所以FIFO的深度必然是2的指数,如2、4、8、16等

三. 部分代码展示

//++ 生成读写指针 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
reg  [ADDR_WIDTH:0] rptr;
always @(posedge clk or posedge rst) beginif (rst)rptr <= 0;else if (rd_en & ~empty)rptr <= rptr + 1'b1;
endreg  [ADDR_WIDTH:0] wptr;
always @(posedge clk or posedge rst) beginif (rst)wptr <= 0;else if (wr_en & ~full)wptr <= wptr + 1'b1;
endwire [ADDR_WIDTH-1:0] raddr = rptr[ADDR_WIDTH-1:0];
wire [ADDR_WIDTH-1:0] waddr = wptr[ADDR_WIDTH-1:0];wire [ADDR_WIDTH:0] rptr_p1 = rptr + 1'b1;
wire [ADDR_WIDTH:0] wptr_p1 = wptr + 1'b1;
//-- 生成读写指针 ------------------------------------------------------------//++ 生成empty与almost_empty信号 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
always @(*) beginif (rst)empty <= 1'b1;else if (rptr == wptr)empty <= 1'b1;elseempty <= 1'b0;
endalways @(*) beginif (rst)almost_empty <= 1'b1;else if (rptr_p1 == wptr || empty)almost_empty <= 1'b1;elsealmost_empty <= 1'b0;
end
//-- 生成empty与almost_empty信号 ------------------------------------------------------------//++ 生成full与almost_full信号 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
always @(*) beginif (rst)full  <= 1'b1;else if ((wptr[ADDR_WIDTH] != rptr[ADDR_WIDTH])&& (wptr[ADDR_WIDTH-1:0] == rptr[ADDR_WIDTH-1:0]))full  <= 1'b1;elsefull  <= 1'b0;
endalways @(*) beginif (rst)almost_full <= 1'b1;else if (((wptr_p1[ADDR_WIDTH] != rptr[ADDR_WIDTH])&& (wptr_p1[ADDR_WIDTH-1:0] == rptr[ADDR_WIDTH-1:0]))|| full)almost_full <= 1'b1;elsealmost_full <= 1'b0;
end
//-- 生成full与almost_full信号 ------------------------------------------------------------

三. 功能仿真

比较以下情形中的fifo行为是否与FIFO IP核一致,

情形一:单次写单次读

情形二:写满后再读空

情形三:在读的过程中写,在写的过程中读

判断模块功能正常的依据:

  1. 写入数据是否按顺序正常读出
  2. 空信号和满信号是否正常输出。

为方便比较,编写了顶层文件,实例化了FIFO IP核与自编模块,部分代码如下:

vivado_sync_fifo vivado_sync_fifo_u0 (.clk          (clk                     ), // input wire clk.rst          (rst                     ), // input wire rst.din          (din                     ), // input wire [7 : 0] din.wr_en        (wr_en                   ), // input wire wr_en.rd_en        (rd_en                   ), // input wire rd_en.dout         (vivado_fifo_dout        ), // output wire [7: 0] dout.full         (vivado_fifo_full        ), // output wire full.almost_full  (vivado_fifo_almost_full ), // output wire almost_full.empty        (vivado_fifo_empty       ), // output wire empty.almost_empty (vivado_fifo_almost_empty)// output wire almost_empty
);syncFIFO # (.DATA_WIDTH (DATA_WIDTH),.ADDR_WIDTH (ADDR_WIDTH),.FWFT_EN    (FWFT_EN   )
) syncFIFO_inst (.din          (din         ),.wr_en        (wr_en       ),.full         (full        ),.almost_full  (almost_full ),.dout         (dout        ),.rd_en        (rd_en       ),.empty        (empty       ),.almost_empty (almost_empty),.clk          (clk         ),.rst          (rst         )
);

testbench部分代码如下:

// 生成时钟
localparam CLKT = 2;
initial beginclk = 0;forever #(CLKT / 2) clk = ~clk;
end// 读写使能控制
initial beginrst = 1;#(CLKT * 2)rst = 0;wr_en = 0;rd_en = 0;#(CLKT * 2)wait(~full && ~vivado_fifo_full); // 两个FIFO都从复位态恢复时开始写// 写入一个数据wr_en = 1;#(CLKT * 1)wr_en = 0;// 读出一个数据wait(~empty && ~vivado_fifo_empty);// 两个FIFO都非空时开始读,比较读数据和empty信号是否有差异rd_en = 1;#(CLKT * 1)rd_en = 0;// 写满wr_en = 1;wait(full && vivado_fifo_full); // 两个FIFO都满时停止写,如果两者不同时满,则先满的一方会有写满的情况发生,但对功能无影响// vivado FIFO IP在FWFT模式时, 设定深度16时实际深度为17, 但仿真显示full会在写入15个数据后置高, 过几个时钟后后拉低,// 再写入一个数据, full又置高; 然后过几个时钟又拉低, 再写入一个数据置高, 如此才能写入17个数据// 所以这里多等待12个wclk周期, 就是为了能真正写满vivado FWFT FIFO#(CLKT * 12)wr_en = 0;// 读空wait(~empty && ~vivado_fifo_empty);rd_en = 1;wait(empty && vivado_fifo_empty); // 两个FIFO都空时停止读,如果两者不同时空,则先空的一方会有读空的情况发生,但对功能无影响rd_en = 0;#(CLKT * 10)$stop;
end// 使用以下代码时,先注释掉上面的读写使能控制initial
// 同时读写
// initial begin
//   #(CLKT * 30)
//   $stop;
// end// assign wr_en = ~full || ~vivado_fifo_full; // 未满就一直写
// assign rd_en = ~empty || ~vivado_fifo_empty; // 未空就一直读always @(posedge clk) beginif (rst)din <= 0;else if (wr_en && ~full && ~vivado_fifo_full)din <= din + 1;
endendmodule

8bit,16深度,FWFT FIFO仿真,波形如下:

可以看到模块输出的自编fifo与vivado fwft fifo的写端口和读端口行为是一致的,只是可能会超前或滞后一定的clk周期。

可以看到empty拉低时,数据已经有效了,所以自编模块实现了FWFT功能,Vivado FIFO的实际深度为17,所以它多读出了一个数据,空信号更晚拉高。

因篇幅问题,其它条件下的仿真不再展示,感兴趣的同学可通过更改testbench自行验证。

  1. FWFT_EN改为0,注意同步修改Vivado FIFO的配置

四. 工程分享

Verilog功能模块——同步FIFO,Vivado 2021.2工程。

欢迎大家关注我的公众号:徐晓康的博客,回复以下四位数字获取。

8302

建议复制过去不会码错字!

或者在我的码云仓库获取,传送门:

徐晓康/Verilog功能模块 - 码云 - 开源中国 (gitee.com)


徐晓康的博客持续分享高质量硬件、FPGA与嵌入式知识,软件,工具等内容,欢迎大家关注。

相关文章:

Verilog功能模块——同步FIFO

前言 FIFO功能模块分两篇文章&#xff0c;本篇为同步FIFO&#xff0c;另一篇为异步FIFO&#xff0c;传送门&#xff1a; Verilog功能模块——异步FIFO-CSDN博客 同步FIFO实现起来是异步FIFO的简化版&#xff0c;所以&#xff0c;本博文不再介绍FIFO实现原理&#xff0c;感兴趣…...

Unity ToLua热更框架使用教程(1)

从本篇开始将为大家讲解ToLua在unity当中的使用教程。 Tolua的框架叫LuaFramework&#xff0c;首先附上下载链接&#xff1a; https://github.com/jarjin/LuaFramework_UGUI_V2 这个地址的是UGUI的。 下载完之后导入项目&#xff0c;首先&#xff0c;我们要先让这个项目跑起…...

车载相关名词--车载数据中心方案

车载数据中心方案 参考链接:https://zhuanlan.zhihu.com/p/600031042?utm_id=0 下面这张图是小鹏汽车嵌入式系统高级专家 唐黾 在同ARM一起的一个演讲稿中发布的,是一张未来车载数据中心单芯片方案构想图。主要针对的是智驾域和座舱域融合方案,下面对如上图的内外部组件及…...

helm使用

前言 类似于 Linux 的 YUM、APT&#xff0c;Helm 是 K8S 的包管理工具。 Helm&#xff0c; 一个二进制工具&#xff0c;用来安装、升级、卸载 K8S 中的应用程序。 Helm Chart&#xff0c;一个 tgz 包&#xff0c;类似安卓的 APK。 K8S 应用打包成 Chart&#xff0c;通过 He…...

Python in Visual Studio Code 2023年10月发布

排版&#xff1a;Alan Wang 我们很高兴地宣布 Visual Studio Code 的 Python 和 Jupyter 扩展于 2023 年 10 月发布&#xff01; 此版本包括以下公告&#xff1a; Python 调试器扩展更新弃用 Python 3.7 支持Pylint 扩展更换时的 Lint 选项Mypy 扩展报告的范围和守护程序模式G…...

Webmin远程命令执行漏洞复现报告

漏洞编号 CVE-2019-15107 漏洞描述 Webmin是一个基于Web的系统配置工具&#xff0c;用于类Unix系统。密码重置页面中存在此漏洞&#xff0c;允许未经身份验证的用户通过简单的 POST 请求执行任意命令。 影响版本 Webmin<1.920 漏洞评级 严重 利用方法&#xff08;利…...

webstorm自定义文件模板(Vue + Scss)

最终效果如下&#xff1a; 具体配置如下&#xff1a; 新增文件代码如下&#xff1a; <!--* Description: ${COMPONENT_NAME} 页面* Author: mhf* Date: ${DATE} --> <template><div>${COMPONENT_NAME} </div> </template><script&g…...

楔子-写在之前

最近一年都在忙着一个项目&#xff0c;并且需要学习另一个领域的知识&#xff0c;从单片机过渡到了LINUX嵌入式&#xff0c;倒静不下心去写点东西。看了下之前写的东西&#xff0c;感觉已经过去了很久很久。现在项目快忙完了&#xff0c;准备把最近的心得给大家分享下。 前言 …...

第 5 章 数组和广义表(稀疏矩阵的三元组顺序表存储实现)

1. 背景说明 为了节省存储空间&#xff0c;可以对这类矩阵进行压缩存储。所谓压缩存储是指&#xff1a;为多个值相同的元只分配一个存储空间&#xff0c;对零元不分配空间。 2. 示例代码 1)status.h /* DataStructure 预定义常量和类型头文件 */ #include <string.h>#i…...

【RabbitMQ 实战】11 队列的结构和惰性队列

一、 队列的结构 队列的组成&#xff1a; 队列由 rabbit_amgqueue_process 和 backing_queue两部分组成。rabbit_amqqueue_process负责协议相关的消息处理&#xff0c;即接收生产者发布的消息、向消费者交付消息、处理消息的确认 (包括生产端的 confirm 和消费端的 ack) 等。…...

Python3-批量重命名指定目录中的一组文件,更改其扩展名

Python3-批量重命名指定目录中的一组文件&#xff0c;更改其扩展名 1.argparse模块2.vars内置函数3.os.listdir(path)4.os.path.splitext(filepath)5.os.path.join6.os.rename7.os.path.isfile8.批量重命名指定目录中的一组文件&#xff0c;更改其扩展名 1.argparse模块 argpa…...

渗透测试KAILI系统的安装环境(第八课)

KAILI系统的安装环境(第八课) Kaili是一款基于PHP7的高性能微服务框架&#xff0c;其核心思想是面向服务的架构&#xff08;SOA&#xff09;&#xff0c;支持http、websocket、tcp等多种通信协议&#xff0c;同时还提供了RPC、Service Mesh、OAuth2等功能。Kaili框架非常适合构…...

如何正确方便的理解双指针?力扣102 (二叉树的层序遍历)

双指针&#xff0c;顾名思义就是指针的指针。 在此之前我们需要先理解单指针 &#xff08;简称为指针&#xff09;。指针很简单&#xff0c;直接上例子&#xff1a;例&#xff1a;现有两个变量&#xff0c;a10,b20. 要求&#xff1a;交换他们的值&#xff0c;输出的结果应为a20…...

Vue或uniapp引入自定义字体

一、为什么引入字体 对于大部分APP或网站而言&#xff0c;字体是很重要的一部分。在前端开发中&#xff0c;选用合适的字体往往会极大地提升网站的视觉体验。然而&#xff0c;网页中默认字体的种类和风格有限&#xff0c;且在不同的设备、浏览器上渲染效果不尽相同。因此&…...

​力扣:LCR 122. 路径加密​ 题目:剑指Offer 05.替换空格(c++)

本文章代码以c为例&#xff01; 力扣&#xff1a;LCR 122. 路径加密 题目&#xff1a; 代码&#xff1a; class Solution { public:string pathEncryption(string path) {for(int i0;i<path.size();i){if(path[i].){path[i] ;}}return path;} }; 难度升级&#xff08;原…...

cJson堆内存释放问题

cJSON_Delete()&#xff0c;是用来释放json对象的&#xff0c;释放父JSON对象后&#xff0c;子JSON对象也会被释放。 CJSON_free()&#xff0c;是用来释放其他对象的。 int main(void) {cJSON* cjson_test NULL;cJSON* cjson_address NULL;cJSON* cjson_skill NULL;char* s…...

论文阅读/写作扫盲

第一节&#xff1a;期刊科普 JCR分区和中科院分区是用于对期刊进行分类和评估的两种常见方法。它们的存在是为了帮助学术界和研究人员更好地了解期刊的学术质量、影响力和地位。 JCR分区&#xff08;Journal Citation Reports&#xff09;&#xff1a;JCR分区是由Clarivate Ana…...

一文拿捏对象内存布局及JMM(JAVA内存模型)

1 JMM(Java Memory Model) 1 概述 Java内存模型(Java Memory Model简称JMM)是一种抽象的概念&#xff0c;并不真实存在&#xff0c;它描述的一组规则或者规范。通过这些规则、规范定义了程序中各个变量的访问方式。jvm运行的程序的实体是线程&#xff0c;而每个线程运行时&am…...

Android组件通信——ActivityGroup(二十五)

1. ActivityGroup 1.1 知识点 &#xff08;1&#xff09;了解ActivityGroup的作用&#xff1b; &#xff08;2&#xff09;使用ActivityGroup进行复杂标签菜单的实现&#xff1b; &#xff08;3&#xff09;使用PopupWindow组件实现弹出菜单组件开发&#xff1b; 1.2 具体…...

js的继承的方式

1.对象冒充继承 使用 bind,call,apply 解决构造函数属性的继承 缺点:不能继承原型上的属性和方法 //-------------父类-------------function Person(name, age, sex) {this.name name;this.age age;this.sex sex;}Person.prototype.run function () {console.log(我${this…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...