【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.mzph.cn/news/881286.shtml

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

相关文章

算法知识点————贪心

贪心&#xff1a;只考虑局部最优解&#xff0c;不考虑全部最优解。有时候得不到最优解。 DP&#xff1a;考虑全局最优解。DP的特点&#xff1a;无后效性&#xff08;正在求解的时候不关心前面的解是怎么求的&#xff09;&#xff1b; 二者都是在求最优解的&#xff0c;都有最优…

Springboot 整合 durid

文章目录 Springboot 整合 druiddruid的优势配置参数使用整合 Druid配置数据源配置参数绑定配置参数配置监控页面配置拦截器 Springboot 整合 druid druid的优势 可以很好的监控 DB 池连接 和 SQL 的执行情况可以给数据库密码加密可以很方便的编写JDBC插件 配置参数 使用 整…

算法闭关修炼百题计划(四)

仅供个人复习 1.两数相加2.寻找峰值6.岛屿的最大面积3.最大数4.会议室5.最长连续序列6.寻找两个正序数组的中位数 1.两数相加 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请…

.NET CORE程序发布IIS后报错误 500.19

发布IIS后浏览时报错误500.19&#xff0c;同时配置文件web.config的路径中也存在问号“?”。 可能原因&#xff1a;没有安装运行时

ViT(Vision Transformer详解)

Transformer作为前沿的深度学习框架&#xff0c;带有多模态的特性&#xff0c;对于不同类型的输入数据&#xff0c;不管是文本还是图像均可进行处理&#xff0c;而ViT则是对于Transformer中的视觉方面&#xff08;也就是输入数据为图像&#xff09;的衍生物&#xff08;因Trans…

MATLAB - 浮动基座机器人的逆运动学

系列文章目录 前言 本例演示如何解决以浮动底座为模型的机器人的逆运动学问题。浮动底座机器人可以在空间中自由平移和旋转&#xff0c;具有六个自由度。浮动基座机器人的逆运动学问题适用于空间应用&#xff0c;即使用安装在浮动和致动基座上的机械臂在空间操纵物体&#xff0…

k8s 中的金丝雀发布(灰度发布)

目录 1 什么是金丝雀发布 2 Canary 发布方式 3 Canary 两种发布方式实操 3.1 准备工作 3.1.1 将 nginx 命名两个版本 v1 与 v2 3.1.2 暴露端口并指定微服务类型 3.1.3 进入 pod 修改默认发布文件 3.1.4 测试 service 是否正常 3.2 基于权重的灰度发布 3.2.1 创建 Igress 资源类…

MS SQL Server 实战 统计与汇总重复记录

目录 需求 范例运行环境 数据样本设计 功能实现 上传EXCEL文件到数据库 分组统计 SQL 语句 分组汇总 SQL 语句 having 语句过滤最终统计结果 小结 需求 在日常的数据管理应用中&#xff0c;统计和汇总重复记录的情况是经常遇到的一个问题&#xff0c;然后我们会根据统…

谢希仁计算机网络 (四)—— 网络层

计算机网络&#xff08;四&#xff09;—— 网络层&#xff08;1、2&#xff09;&#xff1a;网络层概述、网络层提供的两种服务 计算机网络&#xff08;四&#xff09;—— 网络层&#xff08;1、2&#xff09;&#xff1a;网络层概述、网络层提供的两种服务_以下属于网络层范…

IntelliJ IDEA 2024.2 新特性概览

文章目录 1、重点特性:1.1 改进的 Spring Data JPA 支持1.2 改进的 cron 表达式支持1.3 使用 GraalJS 作为 HTTP 客户端的执行引擎1.4 更快的编码时间1.5 K2 模式下的 Kotlin 性能和稳定性改进 2、用户体验2.1 改进的全行代码补全2.2 新 UI 成为所有用户的默认界面2.3 Search E…

传感器模块编程实践(二)W5500 SPI转以太网模块简介及驱动源码

文章目录 一.概要二.W5500芯片介绍W5500通讯协议介绍 三.W5500模块介绍四.W5500模块原理图五.W5500以太网模通讯实验六.CubeMX工程源代码下载七.小结 一.概要 我们介绍过单片机的以太网系统一般是由&#xff1a;单片机MACPHYRJ45。有些单片机比如STM32F407VET6芯片内部自带MAC…

深度学习:GAN图像生成

GAN的诞生背景 诞生&#xff1a; 2014年由Ian Goodfellow提出 创新性&#xff1a; 无监督学习&#xff1a;GAN 提供了一种新的方法来进行无监督学习&#xff0c;即不需要对训练数据进行标注就可以学习到数据的潜在分布。对抗训练&#xff1a;通过引入对抗机制&#xff0c;G…

pygame--超级马里奥(万字详细版)

超级马里奥点我下载https://github.com/marblexu/PythonSuperMario 1.游戏介绍 小时候的经典游戏&#xff0c;代码参考了github上的项目Mario-Level-1&#xff0c;使用pygame来实现&#xff0c;从中学习到了横版过关游戏实现中的一些处理方法。原项目实现了超级玛丽的第一个小…

iSTFT 完美重构的条件详解

目录 引言1. 短时傅里叶变换&#xff08;STFT&#xff09;与逆变换&#xff08;iSTFT&#xff09;概述2. 完美重构的条件3. 数学推导4. 实现要点5. 示例代码6. 总结 引言 在数字信号处理领域&#xff0c;短时傅里叶变换&#xff08;Short-Time Fourier Transform&#xff0c;简…

鸿蒙next开发者第一课02.DevEcoStudio的使用-习题

【习题】DevEco Studio的使用 通过/及格分80/ 满分100 判断题 1. 如果代码中涉及到一些网络、数据库、传感器等功能的开发&#xff0c;均可使用预览器进行预览。F 正确(True)错误(False) 预览器不能进行传感器等特殊功能的开发,需要使用真机开发 2. module.json5文件中的…

栈与队列面试题(Java数据结构)

前言&#xff1a; 这里举两个典型的例子&#xff0c;实际上该类型的面试题是不确定的&#xff01; 用栈实现队列&#xff1a; 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 方法一&#xff1a;双栈 思路 将一个栈当作输入栈&#xff0c;用于压入 push 传入的数…

初始爬虫12(反爬与反反爬)

学到这里&#xff0c;已经可以开始实战项目了&#xff0c;多去爬虫&#xff0c;了解熟悉反爬&#xff0c;然后自己总结出一套方法怎么做。 1.服务器反爬的原因 服务器反爬的原因 总结&#xff1a; 1.爬虫占总PV较高&#xff0c;浪费资源 2.资源被批量抓走&#xff0c;丧失竞争力…

动态规划10:174. 地下城游戏

动态规划解题步骤&#xff1a; 1.确定状态表示&#xff1a;dp[i]是什么 2.确定状态转移方程&#xff1a;dp[i]等于什么 3.初始化&#xff1a;确保状态转移方程不越界 4.确定填表顺序&#xff1a;根据状态转移方程即可确定填表顺序 5.确定返回值 题目链接&#xff1a;174.…

小米路由器ax1500+DDNS+公网IP+花生壳实现远程访问

有远程办公的需求&#xff0c;以及一些其他东西。 为什么写&#xff1f; ax1500路由器好像没搜到相关信息。以及其中有一点坑。 前置 公网ip Xiaomi路由器 AX1500 MiWiFi 稳定版 1.0.54 实现流程 花生壳申请壳域名https://console.hsk.oray.com/ 这里需要为域名实名认证 …

Linux:进程调度算法和进程地址空间

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一 进程调度算法 1.1 进程队列数据结构 1.2 优先级 ​编辑 1.3 活动队列 ​编辑 1.4 过期队列 1.5 active指针和expired指针 1.6 进程连接 二 进程地址空间 2.1 …