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

news2024/10/8 9:53:30

异步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) begin
		if (!wrstn)	w_point_b <= 'b0;
		else begin
			if (wenc)	w_point_b <= w_point_b + 1'b1;  //同步FIFO写法
			else		w_point_b <= w_point_b; 
		end
	end
	//读指针
	always @(posedge rclk or negedge rrstn) begin
		if (!rrstn) r_point_b <= 'b0;
		else begin
			if (renc) r_point_b <= r_point_b + 1'b1; //同步FIFO写法
			else	  r_point_b <= r_point_b;
		end
	end
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 @(*) begin
		w_point_g <= w_point_g_w;
		r_point_g <= r_point_g_w;
	end

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) begin
	if (!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) begin
		if (!wrstn ) begin rq_1 <= 'd0;      rq_2 <= 'd0; end
		else begin  	   rq_1 <=r_point_g; rq_2 <= rq_1; end
	end

	reg [POINT_WIDTH: 0] wq_1, wq_2;
	always @(posedge rclk or negedge rrstn) begin
		if (!rrstn ) begin wq_1 <= 'd0;      wq_2 <= 'd0; end
		else begin  	   wq_1 <=w_point_g; wq_2 <= wq_1; end
	end
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) begin
		if (!wrstn)	w_point_b <= 'b0;
		else begin
			if (wenc)	w_point_b <= w_point_b + 1'b1;  //同步FIFO写法
			else		w_point_b <= w_point_b; 
		end
	end
	//读指针
	always @(posedge rclk or negedge rrstn) begin
		if (!rrstn) r_point_b <= 'b0;
		else begin
			if (renc) r_point_b <= r_point_b + 1'b1; //同步FIFO写法
			else	  r_point_b <= r_point_b;
		end
	end
	//读写指针的二进制码转换为格雷码
	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) begin
		if (!wrstn) w_point_g <= 'd0;
		else		w_point_g <= w_point_g_w;
	end

	always @(posedge rclk or negedge rrstn) begin
		if (!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 @(*) begin
		w_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) begin
		if (!wrstn ) begin rq_1 <= 'd0;      rq_2 <= 'd0; end
		else begin  	   rq_1 <=r_point_g; rq_2 <= rq_1; end
	end

	reg [POINT_WIDTH: 0] wq_1, wq_2;
	always @(posedge rclk or negedge rrstn) begin
		if (!rrstn ) begin wq_1 <= 'd0;      wq_2 <= 'd0; end
		else begin  	   wq_1 <=w_point_g; wq_2 <= wq_1; end
	end

	//空满检测
	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;
	//例化双口RAM
	dual_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) begin
	if (!rst_n) Gray_Code <= 'd0;
	else        Gray_Code <= (Bit_Code >> 1) ^ Bit_Code;
end
endmodule

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

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

相关文章

Qt程序国际化

目录 程序的国际化 第一步&#xff1a;生成ts文件 第二步&#xff1a;生成并加载qm文件 程序的国际化 第一步&#xff1a;生成ts文件 Ts文件格式上实际是xml&#xff0c;记录界面的字符和代码中tr包含的字符的具体位置&#xff08;文件位置&#xff0c;行号列号等&#xff0…

QT 实现图片查看工具

QT 实现图片查看工具 1、选择图像文件 单文件选择 QFileDialog::getOpenFileName多文件选择 QFileDialog::getOpenFileNamesQList<QString> imageNames = QFileDialog::getOpenFileNames(this,tr("打开图片"),"",tr("图片文件 (*.png *.jpg *.b…

【STM32 Blue Pill编程实例】-OLED显示DHT22传感器数据

OLED显示DHT22传感器数据 文章目录 OLED显示DHT22传感器数据1、DHT22介绍2、硬件准备与接线3、模块配置3.1 定时器配置3.2 DHT22引脚配置3.3 OLED配置4、代码实现在本文中,我们将介绍如何将 DHT22 温度和湿度传感器与 STM32 Blue Pill 开发板连接,并使用 HAL 库在 STM32CubeI…

车载音频焦点(二)

目录 1 可延迟的音频焦点 2 多音频区焦点管理 3 HAL 音频焦点 4 OEM 车载音频焦点服务 1 可延迟的音频焦点 在 Android 11 中,AAOS 开始支持请求获得可延迟的音频焦点。 当非瞬态焦点请求 与 当前焦点持有者交互 遭到拒绝时,前者可以延迟。 一旦焦点的变化导致延迟的请…

各省份自然灾害损失造成的直接经济损失数据(2009-2022年)

自然灾害是自然演变过程中不可避免的现象&#xff0c;它们对人类社会构成了巨大的威胁。中国作为一个自然灾害频发的国家&#xff0c;面临着种类繁多的灾害挑战&#xff0c;包括气象灾害、地质灾害、海洋灾害、生物灾害和森林草原火灾等。 数据来源&#xff1a;《中国环境统计…

数据分布过于集中 怎么办,python 人工智能 ,数据分析,机器学习pytorch tensorflow ,

数据分布过于集中&#xff0c;意味着数据的大部分值都聚集在某个特定区间内&#xff0c;这可能会导致统计分析的结果不够稳健&#xff0c;或者模型训练时出现过拟合等问题。针对这种情况&#xff0c;可以考虑以下几种方法来处理&#xff1a; 变换成 1. **数据转换**&#xff1…

笔记-stm32移植ucos

文章目录 一、UCOS的基础知识1.1 前后台系统:1.2 RTOS系统可剥夺型内核:前后台系统和RTOS系统 1.3 UCOS系统简介学习方法 二、ucossii移植Step1&#xff1a;在工程中建立存放UCOSS代码的文件夹UCOSIIStep2:向CORE文件夹添加文件Step3:向Config文件夹添加文件Step4:向port文件夹…

Knife4j-SpringBoot3-OpenAPI3:基本使用、生产环境关闭接口文档、配置文件、配置接口文档描述信息、OpenAPI3注解

版本&#xff1a; SpringBoot&#xff1a;3.3.3 Knife4j&#xff1a;4.5.0 创建时间&#xff1a;2024-10-08 一、官网 Knife4j 的 SpringBoot3 官方说明文档&#xff1a; https://doc.xiaominfo.com/docs/quick-start#spring-boot-3 springdoc官网&#xff1a;https://spring…

笔试强训day33

跳台阶扩展问题 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶(n为正整数)总共有多少种跳法。 数据范围&#xff1a;1≤n≤201≤n≤20 进阶&#xff1a;空间复杂度 O(1)O(1) &#xff0c; 时间复杂度 O(1)O(1) 输入…

【EXCEL数据处理】000017 案例 保姆级教程,附多个操作案例。EXCEL Match和Index函数。

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【EXCEL数据处理】000017 案例 保姆级教程&#xff0c;附多个操作案例。…

MYSQL 事物隔离级别的区别与现象

事物的ACID属性本章不再赘述&#xff0c;本章主要描述事物的隔离级别及隔离级别导致的现象&#xff0c;日常工作中该如何选择MYSQL的隔离级别。 MYSQL事物的隔离级别及各隔离级别存在的问题如下&#xff1a; 隔离级别/问题脏读不可重复读幻读读未提交(Read-Uncommitted)✅✅✅…

JS 入门

文章目录 JS 入门一、JS 概述1、JS 特点2、JS 组成3、JS 初体验4、HTML引入JS 二、JS 基础语法1、变量声明2、基本数据类型3、引用数据类型1&#xff09;数组2&#xff09;对象3&#xff09;函数4&#xff09;null 4、运算符5、条件判断6、循环语句 三、JS 函数0、JS 函数特点1…

知识图谱入门——11:构建动态图谱渲染应用:Vue3与Neo4j的集成与实践

在知识图谱与大数据技术领域&#xff0c;构建动态图谱是一项非常重要的任务。这篇博客将带你深入了解如何利用Vue.js、D3.js以及Neo4j&#xff0c;开发一个能够实时渲染图谱节点和关系的应用。我们将从零开始&#xff0c;介绍如何搭建开发环境、安装依赖、与Neo4j数据库交互、到…

获取yolov8自带的数据集并开始训练

今天小编带大家学习一下YOLOv8 配置文件&#xff0c;用来定义不同数据集的参数和配置。这些文件包含了关于每个数据集的路径、类别数、类别标签等信息&#xff0c;帮助模型正确地加载和解析数据集&#xff0c;以便进行训练和推理。 具体来说&#xff0c;这些 YAML 文件的作用如…

各省份技术市场成交额数据(2001-2022年)

数据名称&#xff1a;各省份技术市场成交额数据数据年份&#xff1a;2001-2022年数据来源&#xff1a;《中国统计年鉴》字段说明&#xff1a; id&#xff1a;数据条目编号省份&#xff1a;中国各省份年份&#xff1a;2001-2022年技术市场成交额(万元)&#xff1a;表示该省份在特…

基于Springboot vue的流浪狗领养管理系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm 等开发框架&#xff09; vue .net php python(flask Django) 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找…

Win10 IDEA连接虚拟机中的Hadoop(HDFS)

获取虚拟机的ip 虚拟机终端输入 ip a关闭虚拟机防火墙 sudo ufw disable修改Hadoop的core-site.xml文件 将localhost修改为虚拟机局域网IP # 位置可能不一样&#xff0c;和Hadoop安装位置有关 cd /usr/local/hadoop/etc/hadoop vim core-site.xmlIDEA 连接 创建Maven项目…

软考系统分析师知识点四:操作系统基本原理

前言 今年报考了11月份的软考高级&#xff1a;系统分析师。 考试时间为&#xff1a;11月9日。 倒计时&#xff1a;33天。 目标&#xff1a;优先应试&#xff0c;其次学习&#xff0c;再次实践。 复习计划第一阶段&#xff1a;扫平基础知识点&#xff0c;仅抽取有用信息&am…

如何删除或减少pagefile.sys?

您是否曾在计算机上遇到过一个名为 pagefile.sys 的超大文件&#xff1f; 许多 Windows 用户想知道 pagefile.sys 的用途以及如何在不影响系统性能的情况下有效地管理它。 本文将帮助您了解 pagefile.sys 是什么、它为什么会变大以及如何安全地管理它的大小。 什么是 pagefi…

基于UDP协议的网络通信

和TCP协议不同的是&#xff0c;UDP协议不需要进行稳定的连接即可直接对数据进行收发&#xff0c;即面向非连接的。所以UDP的应用场景在音视频流传输、在线游戏以及网络聊天室等实时传输需求大的背景。因为不需要建立连接&#xff0c;UDP的网络编程模型就比TCP简单许多。 接收端…