【Verilog学习日常】—牛客网刷题—Verilog进阶挑战—VL45

异步FIFO

描述

请根据题目中给出的双口RAM代码和接口描述,实现异步FIFO,要求FIFO位宽和深度参数化可配置。

电路的接口如下图所示。

双口RAM端口说明:

端口名

I/O

描述

wclk

input

写数据时钟

wenc

input

写使能

waddr

input

写地址

wdata

input

输入数据

rclk

input

读数据时钟

renc

input

读使能

raddr

input

读地址

rdata

output

输出数据

异步FIFO端口说明:

端口名

I/O

描述

wclk

input

写时钟

rclk

input

读时钟

wrstn

input

写时钟域异步复位

rrstn

input

读时钟域异步复位

winc

input

写使能

rinc

input

读使能

wdata

input

写数据

wfull

output

写满信号

rempty

output

读空信号

rdata

output

读数据

双口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) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end endmodule  

输入描述:

    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

解题思路

同步FIFO的设计原理及代码

【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL68-CSDN博客

同步FIFO和异步FIFO

主要参考以下博文:

(1)什么是异步FIFO?与同步FIFO有何不同?异步FIFO的设计理念和设计要点是什么?同步FIFO和异步FIFO的应用场景分别是什么? - CSDN文库

同步FIFO和异步FIFO总结[通俗易懂]-腾讯云开发者社区-腾讯云 (tencent.com)

同步FIFO和异步FIFO

同步FIFO和异步FIFO是两种不同的数据传输方式。

同步FIFO是一种基于时钟的数据传输方式,数据的输入和输出都是在时钟边沿进行的。在同步FIFO中,数据的输入和输出操作是同步的,即在每个时钟周期内,输入和输出操作需要在时钟的边沿进行。这种同步方式可以确保数据的稳定性和可靠性,但需要保证输入和输出的时钟频率一致。

异步FIFO是一种不依赖时钟的数据传输方式,数据的输入和输出是根据输入端和输出端的请求来进行的。在异步FIFO中,输入和输出操作是异步的,数据可以在不同的的时间进行输入和输出操作。这种方式相对于同步FIFO来说更加灵活,但需要额外的电路来处理输入和输出之间的时序问题。

同步FIFO和异步FIFO的优点

同步FIFO的优点

  • 同步FIFO在数据读写时使用相同的时钟,因此不需要考虑时钟域的问题,设计和验证相对简单。
  • 同步FIFO的读写造作是同步的,可以保证数据的可靠性和一致性。
  • 同步FIFO的读写指针可以通过同步逻辑进行控制,可以实现更复杂的读写操作。

异步FIFO的优点

  • 异步FIFO可以在不同的时钟域之间进行数据传输,适用于异步系统或者时钟频率不同的系统。
  • 异步FIFO的读写操作是异步的,可以实现更高的并发性和吞吐量。
  • 异步FIFO的读写指针可以通过异步逻辑进行控制,可以实现更灵活的读写操作。
 FIFO的使用场景
  1. 数据缓冲——当数据写入过快,并且间隔时间长(突发写入)。那么通过设置一定深度的FIFO,可以起到数据暂存的功能,且使得后续处理流程平滑。
  2. 时钟域的隔离——主要用于异步FIFO。对于不同时钟域的数据传输,可以通过FIFO进行隔离,避免跨时钟域的数据传输带来的设计和约束上的复杂度。
  3. 同于不同宽度的数据接口。例如单片机1是8位,DSP是16.

异步FIFO的设计原理

主要参考以下博文:

verilog实现异步FIFO_异步fifo verilog代码-CSDN博客

同步FIFO和异步FIFO总结_synchronization stages-CSDN博客

 对于FIFO的设计,最重要的两点如下:

  • 读写时钟的移动
  • FIFO队列空满检测(对于异步FIFO的空满检测,还涉及到一个跨时钟域问题
异步FIFO的跨时钟域问题

将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题。因为采用二进制计数器时所有位都有可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码(Gray码)时只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该Gray码同步到另一个时钟域进行对比,作为空满状态的检测(还需添加一个二级同步器)。

下面画出异步FIFO的指针同步电路

异步FIFO的Verilog代码设计,主要分为以下几个模块

1.定义读写指针

该步骤与同步FIFO类似,唯一不同的点在于异步FIFO的读写操作中的时钟信号和异步复位信号是不同的;

    assign wenc = winc & (~wfull); assign renc = rinc & (~rempty);//定义读写指针parameter	POINT_WIDTH = $clog2(DEPTH);reg [POINT_WIDTH: 0] w_point_b, r_point_b, w_point_g, r_point_g;//写指针always @(posedge wclk or negedge wrstn) beginif (!wrstn)	w_point_b <= 'b0;else beginif (wenc)	w_point_b <= w_point_b + 1'b1;  //同步FIFO写法else		w_point_b <= w_point_b; endend//读指针always @(posedge rclk or negedge rrstn) beginif (!rrstn) r_point_b <= 'b0;else beginif (renc) r_point_b <= r_point_b + 1'b1; //同步FIFO写法else	  r_point_b <= r_point_b;endend
2.二进制到gray码的转换电路
//二进制码转换为Gray码Bit_To_Gray BG_W ( .Bit_Code(w_point_b), .clk(wclk), .rst_n(wrstn), .Gray_Code(w_point_g_w));	Bit_To_Gray BG_R ( .Bit_Code(r_point_b), .clk(rclk), .rst_n(rrstn), .Gray_Code(r_point_g_w));	always @(*) beginw_point_g <= w_point_g_w;r_point_g <= r_point_g_w;endmodule Bit_To_Gray(input	[4:0] 	Bit_Code,input	clk,input    rst_n,output reg[4:0]   Gray_Code);always @(posedge clk or negedge rst_n) beginif (!rst_n) Gray_Code <= 'd0;else        Gray_Code <= (Bit_Code >> 1) ^ Bit_Code;
end
endmodule
 3.同步信号

同步信号为空满检测的前一步;

  • 当需要从FIFO中读数据时,应该将在wclk时钟域中的写指针地址(w_point_g)同步到rclk时钟域中,因此添加了一个两级同步器,最终在rclk时钟域上输出写指针地址(wq_2);并且在读数据时,应该进行判空操作。因此,使用rclk时钟域下的读指针地址(r_point_g)和同步后的写指针地址(wq_2)来判定当前FIFO是否为空;
  • 当需要从FIFO中写数据时,应该将在rclk时钟域中的读指针地址(r_point_g)同步到wclk时钟域中,因此添加了一个两级同步器,最终在wclk时钟域上输出读指针地址(rq_2);并且在写数据时,应该进行判满操作。因此,使用wclk时钟域下的写指针地址(w_point_g)同步后的读指针地址(rq_2)来判定当前FIFO时候已满;

(PS:信号同步器的相关知识可见【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL69-CSDN博客)

	//同步信号部分reg [POINT_WIDTH: 0] rq_1, rq_2;always @(posedge wclk or negedge wrstn) beginif (!wrstn ) begin rq_1 <= 'd0;      rq_2 <= 'd0; endelse begin  	   rq_1 <=r_point_g; rq_2 <= rq_1; endendreg [POINT_WIDTH: 0] wq_1, wq_2;always @(posedge rclk or negedge rrstn) beginif (!rrstn ) begin wq_1 <= 'd0;      wq_2 <= 'd0; endelse begin  	   wq_1 <=w_point_g; wq_2 <= wq_1; endend
4.空满检测

异步FIFO的判空与同步FIFO的判空相同,即判断读写指针地址(包含折回标志位)是否完全相同;

异步FIFO的判满:根据格雷码的性质;由于添加了一个折回标志位(最高位);当以01000(15)为对称轴时,可发前两高位互补,后三低位相同;因此,当读写指针满足该条件时,FIFO队列为满;

//空满检测assign rempty = (wq_2 == r_point_g) ? 1'b1 : 1'b0;assign wfull = (w_point_g[POINT_WIDTH] != rq_2[POINT_WIDTH] && w_point_g[POINT_WIDTH-1] != rq_2[POINT_WIDTH-1] && w_point_g[POINT_WIDTH-2:0] == rq_2[POINT_WIDTH-2:0]) ? 1'b1: 1'b0;
完整代码如下
`timescale 1ns/1ns/***************************************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      //读数据
);assign wenc = winc & (~wfull); assign renc = rinc & (~rempty);//定义读写指针parameter	POINT_WIDTH = $clog2(DEPTH);reg [POINT_WIDTH: 0] w_point_b, r_point_b, w_point_g, r_point_g;//写指针always @(posedge wclk or negedge wrstn) beginif (!wrstn)	w_point_b <= 'b0;else beginif (wenc)	w_point_b <= w_point_b + 1'b1;  //同步FIFO写法else		w_point_b <= w_point_b; endend//读指针always @(posedge rclk or negedge rrstn) beginif (!rrstn) r_point_b <= 'b0;else beginif (renc) r_point_b <= r_point_b + 1'b1; //同步FIFO写法else	  r_point_b <= r_point_b;endend//读写指针的二进制码转换为格雷码wire [POINT_WIDTH:0] w_point_g_w, r_point_g_w;/*assign w_point_g_w = (w_point_b >> 1) ^ w_point_b;assign r_point_g_w = (r_point_b >> 1) ^ r_point_b;always @(posedge wclk or negedge wrstn) beginif (!wrstn) w_point_g <= 'd0;else		w_point_g <= w_point_g_w;endalways @(posedge rclk or negedge rrstn) beginif (!rrstn) r_point_g <= 'd0;else		r_point_g <= r_point_g_w;end*/Bit_To_Gray BG_W ( .Bit_Code(w_point_b), .clk(wclk), .rst_n(wrstn), .Gray_Code(w_point_g_w));	Bit_To_Gray BG_R ( .Bit_Code(r_point_b), .clk(rclk), .rst_n(rrstn), .Gray_Code(r_point_g_w));	always @(*) beginw_point_g <= w_point_g_w;r_point_g <= r_point_g_w;end//同步信号部分reg [POINT_WIDTH: 0] rq_1, rq_2;always @(posedge wclk or negedge wrstn) beginif (!wrstn ) begin rq_1 <= 'd0;      rq_2 <= 'd0; endelse begin  	   rq_1 <=r_point_g; rq_2 <= rq_1; endendreg [POINT_WIDTH: 0] wq_1, wq_2;always @(posedge rclk or negedge rrstn) beginif (!rrstn ) begin wq_1 <= 'd0;      wq_2 <= 'd0; endelse begin  	   wq_1 <=w_point_g; wq_2 <= wq_1; endend//空满检测assign rempty = (wq_2 == r_point_g) ? 1'b1 : 1'b0;assign wfull = (w_point_g[POINT_WIDTH] != rq_2[POINT_WIDTH] && w_point_g[POINT_WIDTH-1] != rq_2[POINT_WIDTH-1] && w_point_g[POINT_WIDTH-2:0] == rq_2[POINT_WIDTH-2:0]) ? 1'b1: 1'b0;//例化双口RAMdual_port_RAM  #(.DEPTH(DEPTH),.WIDTH(WIDTH))DR (.wclk(wclk),.wenc(wenc),.waddr(w_point_b[POINT_WIDTH-1:0])  //深度对2取对数,得到地址的位宽。,.wdata(wdata)      	//数据写入,.rclk(rclk),.renc(renc),.raddr(r_point_b[POINT_WIDTH-1:0])       //深度对2取对数,得到地址的位宽。,.rdata(rdata) 		//数据输出
);
endmodule//二进制码转换为Gray码
module Bit_To_Gray(input	[4:0] 	Bit_Code,input	clk,input    rst_n,output reg[4:0]   Gray_Code);always @(posedge clk or negedge rst_n) beginif (!rst_n) Gray_Code <= 'd0;else        Gray_Code <= (Bit_Code >> 1) ^ Bit_Code;
end
endmodule

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

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

相关文章

用 LoRA 微调 Stable Diffusion:拆开炼丹炉,动手实现你的第一次 AI 绘画

总得拆开炼丹炉看看是什么样的。这篇文章将带你从代码层面一步步实现 AI 文本生成图像&#xff08;Text-to-Image&#xff09;中的 LoRA 微调过程&#xff0c;你将&#xff1a; 了解 Trigger Words&#xff08;触发词&#xff09;到底是什么&#xff0c;以及它们如何影响生成结…

计组与体系软题1-数据表示与校验码

一、数的编码方式 题1-0的表示 题2-补码的补码原码 1. 这道题涉及到数的编码范围和进制转换2. 题3-采用补码的目的 二、编码范围 题1-补码的表示范围(-2^(n-1)~2 ^(n-1)-1) n是字长/位数&#xff0c;2^7128&#xff0c;范围为-128~127题2-原码范围&#xff08;-2^&#xff0…

LORD-GX5-45 ROS安装

1、驱动安装 https://github.com/LORD-MicroStrain/MSCL 上述下载 x64:C&#xff0c;在下载完的deb文件下执行 sudo dpkg -i <PACKAGE_NAME>.deb #install MSCL sudo apt install -f #install dependencies2、源码安装 #新建工作空间 mkdir -p ~…

【C++】认识匿名对象

文章目录 目录 文章目录前言一、对匿名对象的解读二、匿名对象的对象类型三、匿名对象的使用总结 前言 在C中&#xff0c;匿名对象是指在没有呗命名的情况下创建的临时对象。它们通常在单个语句中执行一系列操作或调用某个函数&#xff0c;并且不需要将结果存放进变量中。 匿名…

【STM32单片机_(HAL库)】4-2-1【定时器TIM】定时器输出PWM实现呼吸灯实验

1.硬件 STM32单片机最小系统LED灯模块 2.软件 pwm驱动文件添加定时器HAL驱动层文件添加GPIO常用函数定时器输出PWM配置步骤main.c程序 #include "sys.h" #include "delay.h" #include "led.h" #include "pwm.h"int main(void) {HA…

音视频入门基础:FLV专题(13)——FFmpeg源码中,解析任意Type值的SCRIPTDATAVALUE类型的实现

一、SCRIPTDATAVALUE类型 从《音视频入门基础&#xff1a;FLV专题&#xff08;9&#xff09;——Script Tag简介》中可以知道&#xff0c;根据《video_file_format_spec_v10_1.pdf》第80到81页&#xff0c;SCRIPTDATAVALUE类型由一个8位&#xff08;1字节&#xff09;的Type和…

动态代理有用吗?一文了解靠谱的动态代理有哪些标准

在当今互联网时代中&#xff0c;从网络安全、隐私保护、市场调研和互联网营销到软件测试、缓存管理和数据库连接&#xff0c;用户为了更好地完成此类工作&#xff0c;往往会使用动态代理&#xff0c;那么进一步了解动态代理、明确动态代理的使用场景和选择标准则是十分有必要的…

OJ在线评测系统 后端微服务架构 注册中心 Nacos入门到启动

注册中心 服务架构中的注册中心是一个关键组件&#xff0c;用于管理和协助微服务之间的通信。注册中心的主要职责是服务的注册和发现&#xff0c;确保各个微服务能够相互找到并进行调用。 主要功能&#xff1a; 服务注册&#xff1a;微服务在启动时&#xff0c;将自身信息&am…

vite学习教程01、vite构建vue2

文章目录 前言一、vite初始化项目二、修改配置文件2.1、修改main.js文件2.2、修改App.vue文件2.3、修改helloworld.vue2.4、修改vite.conf.js2.5、修改vue版本--修改package.json文件 三、安装vue2和vite插件四、启动服务资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝3W&…

常见激活函数总结

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 一. 激活函数的定义 激活函数&#xff08;Activation Function&#xff09;是人工神经网络中对每个神经元的输入进行非线性变换的函数。神经网络中的每个神经元都会接受来自上一层的输入&#xf…

Windows安装HeidiSQL教程(图文)

一、软件简介 HeidiSQL是一款开源的数据库管理工具&#xff0c;主要用于管理MySQL、MariaDB、SQL Server、PostgreSQL和SQLite等数据库系统。它提供了直观的用户界面&#xff0c;使用户可以轻松地连接到数据库服务器、执行SQL查询、浏览和编辑数据、管理数据库结构等操作。 跨…

力扣hot100--链表

链表 1. 2. 两数相加 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff…

【word脚注】双栏设置word脚注,脚注仅位于左栏,右栏不留白

【word脚注】双栏设置word脚注&#xff0c;脚注仅位于左栏&#xff0c;右栏不留白 调整前效果解决方法调整后效果参考文献 调整前效果 调整前&#xff1a;脚注位于左下角&#xff0c;但右栏与左栏内容对其&#xff0c;未填充右下角的空白区域 解决方法 备份源文件复制脚注内…

git创建新分支

git创建新分支 1.先在gitLab上New branch. 2.本地右键git小乌 - /切换/检出-创建新分支&#xff0c;分支名称和上一步创建的一样。 最后记得改个文件提交下&#xff0c;看看gitLab上是否提交成功。

蝶形激光器驱动(温控精度0.002°C 激光电流分辨率5uA)

蝶形半导体激光器驱动电流的稳定性直接决定了其输出波长的稳定性,进而影响检测精度.为了满足气体浓度检测中对激光器输出波长稳定可调的要求,设计了数字与模拟电路混合的恒流驱动电路.STM32为主控芯片数控模块完成扫描AD/DA转换;模拟电路主要由负反馈运算放大、高精度CMOS管和反…

22.第二阶段x86游戏实战2-背包遍历REP指令详解

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

rtmp协议转websocketflv的去队列积压

websocket server的优点 websocket server的好处&#xff1a;WebSocket 服务器能够实现实时的数据推送&#xff0c;服务器可以主动向客户端发送数据 1 不需要客户端不断轮询。 2 不需要实现httpserver跨域。 在需要修改协议的时候比较灵活&#xff0c;我们发送数据的时候比较…

【网络安全】利用XSS、OAuth配置错误实现token窃取及账户接管 (ATO)

未经许可,不得转载。 文章目录 正文正文 目标:target.com 在子域sub1.target.com上,我发现了一个XSS漏洞。由于针对该子域的漏洞悬赏较低,我希望通过此漏洞将攻击升级至app.target.com,因为该子域的悬赏更高。 分析认证机制后,我发现: sub1.target.com:使用基于Cook…

微信小程序——音乐播放器

一、界面设计 播放页面&#xff1a; 显示当前播放歌曲的封面图片、歌曲名称、歌手名称。有播放 / 暂停按钮、上一首、下一首按钮。进度条显示播放进度&#xff0c;可以拖动进度条调整播放位置。音量调节滑块。 歌曲列表页面&#xff1a; 展示歌曲列表&#xff0c;包括歌曲名称、…

C++——STL简介

目录 一、什么是STL 二、STL的版本 三、STL的六大组件 没用的话..... 不知不觉两个月没写博客了&#xff0c;暑假后期因为学校的事情在忙&#xff0c;开学又在准备学校的java免修&#xff0c;再然后才继续开始学C&#xff0c;然后最近打算继续写博客沉淀一下最近学到的几周…