同步FIFO的verilog实现(2)——高位扩展法

一、前言

        在之前的文章中,我们介绍了同步FIFO的verilog的一种实现方法:计数法。其核心在于:在同步FIFO中,我们可以很容易的使用计数来判断FIFO中还剩下多少可读的数据,从而可以判断空、满。

        关于计数法实现同步FIFO的详细内容,请参考:同步FIFO的verilog实现(1)——计数法

二、高位扩展法原理

        我们知道对于FIFO的设计来说,其核心在于设计读写指针,并且生成可靠的空、满信号。

        当读/写地址指针在复位操作期间被置为零时,或者当读指针在从FIFO中读取了最后一个字之后追上了写指针,此时读指针和写指针相等代表着FIFO为空状态。而当写指针再次追上读指针时,此时读指针和写指针相等代表着FIFO为写满。也就是说当读写指针相等时,FIFO要么为空,要么为满。
   因此我们可以将地址位扩展一位,用最高位来判断空满,其余低位还是正常用于读写地址索引。当写指针递增超过FIFO的最大地址时,写指针的MSB位将置为1,同时将其余低位设置回零。读指针也是如此。如果读指针和写指针的MSB不同,则意味着写指针比读指针多绕了一次,表示FIFO写满。如果两个指针的MSB相同,则表示两个指针的回绕次数相同,表示FIFO读空。如下图所示:

        当最高位不同,且其他位相同,则表示读指针或者写指针多跑了一圈,这显然不可能发生,情况只能是写指针多跑了一圈,与就意味着FIFO被写满了。
        当最高位相同,且其他位相同,则表示读指针追到了写指针或者写指针追到了读指针,而显然不会让写指针追读指针(这种情况只能是写指针超过读指针一圈),所以可能出现的情况只能是读指针追到了写指针,也就意味着FIFO被读空了。

三、同步FIFO的verilog实现

        理解了原理,我们就能很快设计出相应的verilog代码:

//------------------------<高位扩展法设计同步FIFO>----------------------------
module sync_fifo1#(  
//-----------------------------<参数定义>---------------------------------parameter FIFO_WIDTH = 16,                          //FIFO宽度parameter FIFO_DEPTH = 16                           //FIFO深度
)(
//-----------------------------<接口定义>---------------------------------input clk,                                          //时钟信号input rst,                                          //复位信号input [FIFO_WIDTH-1:0] din,                         //FIFO输入数据(写数据)input rd_en,                                        //读使能信号 input wr_en,                                        //写使能信号output reg [FIFO_WIDTH-1:0] dout,                   //FIFO输出数据(读数据) output empty,                                       //FIFO空标志 output full                                         //FIFO满标志 
); //-----------------------------<reg定义>---------------------------------reg [FIFO_WIDTH-1:0] fifo_buffer[FIFO_DEPTH-1:0];	//用二维数组实现RAM	reg [$clog2(FIFO_DEPTH):0] wr_addr;			     	//写地址(写指针),位宽要多出一位reg [$clog2(FIFO_DEPTH):0] rd_addr;			    	//读地址(读指针),位宽要多出一位//-----------------------------<wire定义>---------------------------------     wire [$clog2(FIFO_DEPTH) - 1 : 0]	wr_addr_true;	//真实写地址指针wire [$clog2(FIFO_DEPTH) - 1 : 0]	rd_addr_true;   //真实读地址指针wire								wr_addr_msb;	//写地址指针地址最高位wire								rd_addr_msb;	//读地址指针地址最高位assign {wr_addr_msb,wr_addr_true} = wr_addr;		//将最高位与其他位拼接assign {rd_addr_msb,rd_addr_true} = rd_addr;		//将最高位与其他位拼接       //-----------------------------<读操作>-----------------------------------
always@(posedge clk or posedge rst)begin if(rst)rd_addr <= 0;else if(rd_en && !empty)begin                       //读使能有效且FIFO非空rd_addr	<=	rd_addr + 1'd1;                     //读指针递增dout	<=	fifo_buffer[rd_addr_true];               //fifo读出数据endelse beginrd_addr	<=	rd_addr;                            dout	<=	dout;end
end//-----------------------------<写操作>-----------------------------------
always@(posedge clk or posedge rst)begin if(rst)wr_addr <= 0;else if(wr_en && !full)begin                       //写使能有效且FIFO非满wr_addr	<=	wr_addr + 1'd1;                    //读指针递增fifo_buffer[wr_addr_true] <= din;              //数据写入fifoendelse beginwr_addr	<=	wr_addr;                            end
end//-----------------------------<通过地址扩展位更新空/满信号>-----------------------------------
assign	empty = ( wr_addr == rd_addr ) ? 1'b1 : 1'b0;                                              //当所有位相等时,读指针追到了写指针,FIFO被读空
assign	full  = ((wr_addr_msb != rd_addr_msb ) && ( wr_addr_true == rd_addr_true )) ? 1'b1 : 1'b0; //当最高位不同但是其他位相等时,写指针超过读指针一圈,FIFO被写满endmodule

四、测试代码

        给出如下的测试代码:

`timescale 1ns/1ns
//-----------------------------<高位扩展法同步FIFO测试>---------------------------------
module tb_sync_fifo1();parameter WIDTH	= 8;parameter DEPTH	= 8;reg                 clk         ;reg                 rst         ;reg  [WIDTH-1:0]	din    		;reg 				wr_en  		;reg 				rd_en  		;wire [WIDTH-1:0]	dout		;wire 				full        ;wire 				empty       ;//-----------------------------<测试模块例化>---------------------------------
sync_fifo1 #(.FIFO_WIDTH	(WIDTH),		 //FIFO宽度.FIFO_DEPTH (DEPTH)          //FIFO深度
)
sync_fifo_u1(.clk		(clk		),.rst		(rst		),.din     	(din 	    ),.rd_en		(rd_en		),.wr_en		(wr_en		),.dout    	(dout	    ),	.empty		(empty		),	.full		(full		)	
);//-----------------------------<模块测试>---------------------------------
initial beginclk = 1'b0;							//初始时钟为0rst <= 1'b0;						//初始复位din <= 'd0;		wr_en <= 1'b0;		rd_en <= 1'b0;
#10rst <= 1'b1;
#10 rst <= 1'b0;repeat(10)#10 beginwr_en <= 1'b1;rd_en <= 1'b0;din <= $random;                   //生成8位的随机数endrepeat(10)#10 beginwr_en <= 1'b0;rd_en <= 1'b1;end
$finish;
end//------------------------------<设置时钟>----------------------------------------
always #5 clk = ~clk;			endmodule

五、结果

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/103205.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

『SpringBoot 源码分析』run() 方法执行流程:(3)刷新应用上下文-处理 @ComponentScan 注解

『SpringBoot 源码分析』run() 方法执行流程&#xff1a;&#xff08;3&#xff09;刷新应用上下文-处理 ComponentScan 注解 基于 2.2.9.RELEASE问题&#xff1a;当方法进行了注释标记之后&#xff0c;springboot 又是怎么注入到容器中并创建类呢&#xff1f; 首先创建测试主…

流程图用什么软件做比较好?这几个实用软件了解下

流程图用什么软件做比较好&#xff1f;流程图的制作对于企业管理、项目管理、产品设计等领域都非常重要。制作流程图可以帮助我们更好地理解事物之间的关系和流程&#xff0c;从而规划和组织工作。因此&#xff0c;选择一个合适的流程图软件是非常必要的。下面就给大家介绍几种…

Linux命令200例:free用来显示系统内存使用情况

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0…

C++新特性:智能指针

一 、为什么需要智能指针 智能指针主要解决以下问题&#xff1a; 1&#xff09;内存泄漏&#xff1a;内存手动释放&#xff0c;使用智能指针可以自动释放 2&#xff09;共享所有权指针的传播和释放&#xff0c;比如多线程使用同一个对象时析构问题&#xff0c;例如同样的数据…

Matlab图像处理之Lee滤波器

目录 一、前言:二、LEE滤波器2.1 LEE滤波器原理2.2 LEE滤波器实现步骤三、MATLAB代码示例一、前言: LEE滤波器是一种常用于合成孔径雷达(SAR)图像去噪的滤波器。它能增强图像的局部对比度。今天我们将通过MATLAB来实现这种滤波器。 二、LEE滤波器 2.1 LEE滤波器原理 LEE滤…

【MongoDB】Ubuntu22.04 下安装 MongoDB | 用户权限认证 | skynet.db.mongo 模块使用

文章目录 Ubuntu 22.04 安装 MongoDB后台启动 MongoDBshell 连入 MongoDB 服务 MongoDB 用户权限认证创建 root 用户开启认证重启 MongoDB 服务创建其他用户查看用户信息验证用户权限删除用户 skynet.db.mongo 模块使用authensureIndexfind、findOneinsert、safe_insertdelete、…

Matlab 如何选择窗函数和 FFT 的长度

Matlab 如何选择窗函数和 FFT 的长度 1、常用的四种窗函数 对于实际信号序列&#xff0c;如何选取窗函数呢&#xff1f;一般来说&#xff0c;选择第一旁瓣衰减大&#xff0c;旁瓣峰值衰减快的窗函数有利于緩解截断过程中产生的頻泄漏问题。但具有这两个特性的窗函数&#xff0…

华为云云耀云服务器L实例评测|华为云上试用主机安全产品Elkeid

文章目录 华为云云耀云服务器L实例评测&#xff5c;华为云上试用主机安全产品Elkeid一、背景&#xff1a;什么是主机安全二、主机安全之Elkeid1. Elkeid 介绍2. Elkeid Server3. Elkeid Server 架构Elkeid AgentCenter&#xff08;下面简称AC&#xff09;Elkeid Service Discov…

QT Creator更改主题和编辑器风格(附几款黑色主题)

适用于qtcreator 一、使用自带主题与编辑器风格 打开Qt选择"工具"->"选项"&#xff1b; 2. 选择"环境"->"Theme"切换不同的主题风格 这里切换的是外边框的风格&#xff0c;如果编辑器中有同名的风格&#xff0c;编辑器的风格也…

快速排序算法的递归和非递归

基本思路 选择一个基准值&#xff0c;将数组划分三个区域&#xff0c;小于基准值的区域位于左侧&#xff0c;等于基准值的区域位于中间&#xff0c;大于基准值的区域位于右侧。将大于和小于区域继续进行分区&#xff0c;周而复始&#xff0c;不断进行分区和交换&#xff0c;直…

手写Spring:第7章-实现应用上下文

文章目录 一、目标&#xff1a;实现应用上下文二、设计&#xff1a;实现应用上下文三、实现&#xff1a;实现应用上下文3.1 工程结构3.2 Spring应用上下文和Bean对象扩展类图3.3 对象工厂和对象扩展接口3.3.1 对象工厂扩展接口3.3.2 对象扩展接口 3.4 定义应用上下文3.4.1 定义…

计算机竞赛 基于深度学习的植物识别算法 - cnn opencv python

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 MobileNetV2网络4 损失函数softmax 交叉熵4.1 softmax函数4.2 交叉熵损失函数 5 优化器SGD6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的植物识别算法 ** …