Verilog同步FIFO设计

同步FIFO(synchronous)的写时钟和读时钟为同一个时钟,FIFO内部所有逻辑都是同步逻辑,常常用于交互数据缓冲。

异步FIFO:数据写入FIFO的时钟和数据读出FIFO的时钟是异步的(asynchronous)

在这里插入图片描述

典型同步FIFO有三部分组成:

(1) FIFO写控制逻辑;

(2)FIFO读控制逻辑;

(3)FIFO 存储实体(如Memory、Reg)。

FIFO写控制逻辑主要功能:产生FIFO写地址、写有效信号,同时产生FIFO写 满、写错等状态信号;

FIFO读控制逻辑主要功能:产生FIFO读地址、读有效信号,同时产生FIFO读 空、读错等状态信号。

  • 基本概念

    FIFO:先进先出(First-in-first-out) FIFO的深度 同一块数据内存的大小

    FIFO的宽度:写指针:Write-pointer 读指针:Read-pointer

    一般FIFO使用循环指针(计数溢出自动归零)。一般可以称写指针为头head,读指针为尾tail。 初始化时,读写指针指向同一数据地址。下图可见,FIFO初始化时,WP和RP指针指向同一数据单元。WP指向下一个将要写入的数据单元,RP指向将要读出的数据单元
    在这里插入图片描述

    2种方法判断空满:

    1. counter计数器:判断有效数据是否等于FIFO的深度,为0就表示空

      使用fifo_counter记录FIFO RAM中的数据个数,等于0时,给出empty信号,等于BUF_LENGTH时,给出full信号。

      写而未满时增加1 读而未空时减1 同时发生读写操作时,fifo_counter不变

    2. pointer:如果深度为8,那么3bit就可以表示8个数,但是为了判断空满,会多定义一位,也即4bit,WP为1000,RP为0000,我们使用最高位去判断是否在同一单元,用高位判断空满,如果高位相异,就表示满,如果相同表示空。

  • 程序代码

    `define BUF_WIDTH 4 // 地址宽度为3+1,
    `define BUF_SIZE 8 // 数据个数,FIFO深度
    module fifo_counter( clk,rst_n,buf_in,buf_out,wr_en,rd_en,buf_empty,buf_full,fifo_cnt);input clk,rst_n; // 时钟与复位信号input wr_en,rd_en; // 读写使能信号input [7:0] buf_in; // 写数据output reg [7:0] buf_out; // 读数据output wire buf_empty,buf_full; // 空满两个状态信号output reg [`BUF_WIDTH-1:0] fifo_cnt;  //判断空满计数器// 读写指针:数据指针3位宽度,0-7索引,8个数据深度,循环指针0-7-0-7reg [`BUF_WIDTH-2:0] rd_ptr,wr_ptr;// 读写容器reg [7:0] buf_mem[0:`BUF_SIZE-1];//判断空满 方式1assign buf_empty = (fifo_cnt == 0); //buf_empty若是reg类型则错,不能使用assign持续赋值assign buf_full = (fifo_cnt == `BUF_SIZE);// fifo_cnt = 8就是满的//判断空满 方式2assign buf_empty = (rd_ptr[3] == wr_ptr[3])&&(rd_ptr[2:0] == wr_ptr[2:0]); assign buf_full = (rd_ptr[3] != wr_ptr[3])&&(rd_ptr[2:0] == wr_ptr[2:0]); // 前后必须同时为1//读数据always @(posedge clk or negedge rst_n) begin if(!rst_n)buf_out <= 0;if(rd_en && !buf_empty)buf_out <= buf_mem[rd_ptr];end// 写数据always @(posedge clk) beginif(wr_en && !buf_full)buf_mem[wr_ptr] <= buf_in;end// 更改读写指针always @(posedge clk or negedge rst_n)beginif(!rst_n)beginwr_ptr <= 0;rd_ptr <= 0;endelse begin// 满足写的条件,就把写指针+1if(!buf_full && wr_en)wr_ptr <= wr_ptr + 1;// 满足读的条件,就把读指针+1if(!buf_empty && rd_en)rd_ptr <= rd_ptr + 1;endend// 监控fifo_cntalways @(posedge clk or negedge rst_n)beginif(!rst_n)fifo_cnt <= 0;else if((!buf_full&&wr_en)&&(!buf_empty&&rd_en)) // 同时读写,数量不变fifo_cnt <= fifo_cnt;else if(!buf_full && wr_en) // 写数据:写而未满增加1fifo_cnt <= fifo_cnt + 1;else if(!buf_empty && rd_en) // 读数据:读而未空减1fifo_cnt <= fifo_cnt-1;elsefifo_cnt <= fifo_cnt; // 维持end
    endmodule
    
  • TestBench

    `define BUF_WIDTH 4 //地址宽度为3+1,
    `define BUF_SIZE (8) //数据个数,FIFO深度
    module tb_fifo_counter;reg clk,rst_n;reg wr_en,rd_en;reg [7:0] buf_in; // data input to be pushed to bufferwire [7:0] buf_out; // port to output the data using pop. wire buf_empty,buf_full; // buffer empty and full indicationwire [`BUF_WIDTH-1:0] fifo_cnt; // number of data pushed in to bufferfifo_counter dut(.clk(clk),.rst_n(rst_n),.buf_in(buf_in),.buf_out(buf_out),.wr_en(wr_en),.rd_en(rd_en),.buf_empty(buf_empty),.buf_full(buf_full),.fifo_cnt(fifo_cnt));fifo_counter dut(.clk		(clk),.rst_n	(rst_n),.buf_in	(buf_in),.buf_out	(buf_out),.wr_en	(wr_en),.rd_en	(rd_en),.buf_empty	(buf_empty),.buf_full	(buf_full),.fifo_cnt	(fifo_cnt));always #10 clk = ~clk;// 定义一个临时的数据,将读出来的数据暂存reg [7:0] tempdata;initial beginclk = 0;rst_n = 0;wr_en = 0;rd_en = 0;buf_in = 0;#15; rst_n = 1;push(1);// 同时读写forkpush(2);pop(tempdata); // 读取tempdata = 1joinpush(10);push(20);push(30);push(40);push(50);push(60);push(70);// 70push 就会满push(80);push(90);push(100);push(110);push(120);push(130);pop(tempdata); // 读取tempdata = 2push(tempdata); pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);push(140); // 可以写进去pop(tempdata);push(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);pop(tempdata);push(5);pop(tempdata);// 读取tempdata = 5#50 $finish;end// 将data写入fifotask push (input [7:0] data);if(buf_full)$display("---Cannot push %d: Buffer Full---",data);else begin$display("Push",,data);buf_in = data;wr_en = 1;@(posedge clk);#5 wr_en = 0;endendtask// 将data读取出来task pop(output[7:0] data);if(buf_empty)$display("---Cannot Pop: Buffer Empty---");else beginrd_en = 1;@(posedge clk);#3 rd_en = 0;data = buf_out;$display("------Poped:",,data);endendtask
    endmodule
    

    find -name "*.v" > file.list

    makefile文件:

    all:clean com sim
    SEED=1
    com:vcs -full64 -R -sverilog -debug_all -f file.list -l comp.log +ntb_random_seed=$(SEED) \-cm line+cond+fsm+branch+tgl -cm_name simv -cm_dir ./covdir.vdb
    sim:./simv -l sim.log
    rung:./simv -gui -l sim.log
    cov:dve -full64 -covdir *.vdb &
    clean:rm -rf ./csrc *.daidir *.log *.vpd *.vdb simv* *.key *race.out*rm -rf AN.DBrm -rf novas*rm -rf DVEfilesrm -rf urgReport
    
    VCS Coverage Metrics Release O-2018.09-1_Full64 Copyright (c) 1991-2018 by Synopsys Inc.
    Push   1
    Push   2
    ------Poped:   1
    Push  10
    Push  20
    Push  30
    Push  40
    Push  50
    Push  60
    Push  70
    ---Cannot push  80: Buffer Full---
    ---Cannot push  90: Buffer Full---
    ---Cannot push 100: Buffer Full---
    ---Cannot push 110: Buffer Full---
    ---Cannot push 120: Buffer Full---
    ---Cannot push 130: Buffer Full---
    ------Poped:   2
    Push   2
    ------Poped:  10
    ------Poped:  20
    ------Poped:  30
    ------Poped:  40
    Push 140
    ------Poped:  50
    Push  50
    ------Poped:  60
    ------Poped:  70
    ------Poped:   2
    ------Poped: 140
    ------Poped:  50
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    ---Cannot Pop: Buffer Empty---
    Push   5
    ------Poped:   5
    

    查看波形:make rung

在这里插入图片描述

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

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

相关文章

arm:day4

1. 实现三盏灯的点亮 .text .global _start_start: led1初始化函数LED_INIT: 1 通过RCC_AHB4_ENSETR寄存器&#xff0c;设置GPIOE F组控制器使能 0x50000A28[5:4]1ldr r0,0X50000A28ldr r1,[r0]orr r1,r1,#(0X3<<4)str r1,[r0] 2.1 通过GPIOE_MODER寄存器&#xff0c;…

史上最简洁实用人工神经元网络c++编写202301

这是史上最简单、清晰…… C语言编写的 带正向传播、反向传播(Forward ……和Back Propagation&#xff09;……任意Nodes数的人工神经元神经网络……。 大一学生、甚至中学生可以读懂。 适合于&#xff0c;没学过高数的程序员……照猫画虎编写人工智能、深度学习之神经网络……

plt绘制箱型图+散点图

import numpy as np import matplotlib.pyplot as plt# 创建示例数据 np.random.seed(1) data [np.random.normal(0, std, 100) for std in range(1, 4)]# 绘制箱型图 plt.boxplot(data, patch_artistTrue,zorder0)# 添加数据点的散点图&#xff0c;并设置参数以避免重叠 for …

6.Web后端开发【SpringBoot入门】

文章目录 1 SpringBoot快速入门1.1 Web分析 2. HTTP协议2.1 HTTP-概述2.1.1 介绍2.2.2 特点 2.2 HTTP-请求协议2.3 HTTP-响应协议2.3.1 格式介绍2.3.2 响应状态码 常见的相应状态码 3 WEB服务器3.1 服务器概述 1 SpringBoot快速入门 Spring的官网Spring Boot 可以帮助我们非常…

探秘Maven神奇力量:使用systemPath加载外部JAR包

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; 探秘Maven神奇力量&#xff1a;使用systemPath加载外部JAR包 ⏱️ 创作…

明星都偏爱的多燕瘦活酵素,不含非法添加事件更健康

不少瘦身人士信奉“运动就能瘦”的准则&#xff0c;每天坚持高强度运动&#xff0c;一段时间后却发现&#xff0c;不仅体重没有下降&#xff0c;甚至整个人看起来都变得更加壮实了&#xff0c;这是为什么&#xff1f; 首先&#xff0c;运动是分为减脂和增肌两种类型的&#xff…

拒绝摆烂!C语言练习打卡第四天

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;每日一练 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、选择题 &#x1f4dd;1.第一题 &#x1f4dd;2.第二题 &#x1f4d…

远程线程注入(简单样例以及原理)

远程线程注入(简单样例以及原理) 注入的目标是将我们的代码注入到目标进程的地址空间中 注入通常可以根据注入的内容分为两种类型&#xff1a; shellcode注入 &#xff1a;这种注入是将我们的代码直接注入到目标内存中&#xff0c;这就要保证我们的代码在贴到其他地址上后仍…

【AI】文心一言的使用

一、获得内测资格&#xff1a; 1、点击网页链接申请&#xff1a;https://yiyan.baidu.com/ 2、点击加入体验&#xff0c;等待通过 二、获得AI伙伴内测名额 1、收到短信通知&#xff0c;点击链接 网页Link&#xff1a;https://chat.baidu.com/page/launch.html?fa&sourc…

SpringBoot + Vue 微人事权限组管理模块 (十四)

权限组前端页面制作 权限组管理角色和菜单之间关系&#xff0c;操作员管理着用户和角色之间的关系。 英文的输入框要有个前缀&#xff0c;SpringSecurity里角色英文名需要加一个ROLE_的前缀 上代码 <div><div class"permissManaTool"><el-input pla…

通过 kk 创建 k8s 集群和 kubesphere

官方文档&#xff1a;多节点安装 确保从正确的区域下载 KubeKey export KKZONEcn下载 KubeKey curl -sfL https://get-kk.kubesphere.io | VERSIONv3.0.7 sh -为 kk 添加可执行权限&#xff1a; chmod x kk创建 config 文件 KubeSphere 版本&#xff1a;v3.3 支持的 Kuber…

go语言中channel类型

目录 什么是channel 为什么要有channel channel操作使用 初始化&#xff1a; 操作&#xff1a; 单向channel 双向channel&#xff0c;可读可写&#xff1a; close下什么场景会出现panic 总结 什么是channel Channels are a typed conduit through which you can send …

【ROS】参数服务器--理论模型与参数操作(C++)

一、概念介绍 参数服务器在ROS中主要用于实现不同节点之间的数据共享。参数服务器相当于是独立于所有节点的一个公共容器&#xff0c;可以将数据存储在该容器中&#xff0c;被不同的节点调用&#xff0c;当然不同的节点也可以往其中存储数据。 作用&#xff1a;存储一些多节点…

Qt实现简单的漫游器

文章目录 Qt的OpenGL窗口GLSL的实现摄像机类的实现简单的漫游器 Qt的OpenGL窗口 Qt主要是使用QOpenGLWidget来实现opengl的功能。  QOpenGLWidget 提供了三个便捷的虚函数&#xff0c;可以重载&#xff0c;用来重新实现典型的OpenGL任务&#xff1a; paintGL&#xff1a;渲染…

Datawhale Django后端开发入门 Vscode TASK02 Admin管理员、外键的使用

一.Admin管理员的使用 1、启动django服务 使用创建管理员之前&#xff0c;一定要先启动django服务&#xff0c;虽然TASK01和TASK02是分开的&#xff0c;但是进行第二个流程的时候记得先启动django服务&#xff0c;注意此时是在你的项目文件夹下启动的&#xff0c;时刻注意要执…

基于CentOS7.9安装部署docker(简洁版)

安装部署 1基于官方脚本安装&#xff08;不推荐 不能自行选择版本&#xff09; 官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 2 使用yum安装 阿里云文档&#xff1a;docker-ce镜像_docker-ce下载地址_docker-ce安装教程-阿里巴巴开源镜像站 # ste…

matlab使用教程(19)—曲线拟合与一元方程求根

1.多项式曲线拟合 此示例说明如何使用 polyfit 函数将多项式曲线与一组数据点拟合。您可以按照以下语法&#xff0c;使用 polyfit 求出以最小二乘方式与一组数据拟合的多项式的系数 p polyfit(x,y,n), 其中&#xff1a; • x 和 y 是包含数据点的 x 和 y 坐标的向量 …

【Linux操作系统】Linux系统编程中的共享存储映射(mmap)

在Linux系统编程中&#xff0c;进程之间的通信是一项重要的任务。共享存储映射&#xff08;mmap&#xff09;是一种高效的进程通信方式&#xff0c;它允许多个进程共享同一个内存区域&#xff0c;从而实现数据的共享和通信。本文将介绍共享存储映射的概念、原理、使用方法和注意…

uni-app的Vue.js实现微信小程序的紧急事件登记页面功能

主要功能实现 完成发生时间选择功能&#xff0c;用户可以通过日期选择器选择事件发生的时间。实现事件类型选择功能&#xff0c;用户可以通过下拉选择框选择事件的类型。添加子养殖场编号输入框&#xff0c;用户可以输入与事件相关的子养殖场编号。完成事件描述输入功能&#…

C++头文件

C头文件 一般头文件特殊头文件windows.hbits/stdc.h 一般头文件 C头文件是一种包含预定义函数、类和变量声明的文件。它们通常用于在源代码文件中引入外部库或模块的功能。 头文件的作用是提供程序所需的声明信息&#xff0c;以便在源代码文件中使用这些声明。当你在源代码文…