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

news2024/11/20 2:25:01

同步FIFO

描述

请设计带有空满信号的同步FIFO,FIFO的深度和宽度可配置。双口RAM的参考代码和接口信号已给出,请在答案中添加并例化此部分代码。
电路的接口如下图所示。端口说明如下表。

接口电路图如下:

双口RAM端口说明:

端口名

I/O

描述

wclk

input

写数据时钟

wenc

input

写使能

waddr

input

写地址

wdata

input

输入数据

rclk

input

读数据时钟

renc

input

读使能

raddr

input

读地址

rdata

output

输出数据

同步FIFO端口说明:

端口名

I/O

描述

clk

input

时钟

rst_n

input

异步复位

winc

input

写使能

rinc

input

读使能

wdata

input

写数据

wfull

output

写满信号

rempty

output

读空信号

rdata

output

读数据

参考代码如下:

module dual_port_RAM #(parameter DEPTH = 16,
                       parameter WIDTH = 8)(
     input wclk
    ,input wenc
    ,input [$clog2(DEPTH)-1:0] waddr  
    ,input [WIDTH-1:0] wdata        
    ,input rclk
    ,input renc
    ,input [$clog2(DEPTH)-1:0] raddr  
    ,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 clk , 

input rst_n ,

input winc ,

input rinc ,

input                  wdata ,

输出描述:

output reg                wfull    ,
output reg                rempty    ,
output wire               rdata

解题思路:

同步FIFO的相关知识:

主要参考以下博文:

(博客园)数字设计——同步fifo

(知乎)手写同步FIFO

(知乎)同步FIFO笔记

(CSDN)FPGA基础知识极简教程(3)从FIFO设计讲起之同步FIFO篇

FIFO(First-In-Frist-Out)是一种先进先出的数据交互方式,在数字ASIC设计中常常被使用。

FIFO与普通存储器RAM的区别是没有外部读写地址线,使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成。不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。FIFO本质上是由RAM(或者寄存器)加读写控制逻辑构成的一种先进先出的数据缓冲器

同步FIFO的端口
  • FIFO的宽度:即FIFO一次读写操作的数据位;
  • FIFO的深度:FIFO可以存储多少个N位的数据(如果宽度为N)。
  • 满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)
  • 空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的输出(underflow)
  • 读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
  • 写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。
  • 将满标志(almost full):FIFO将要满时由FIFO的状态电路送出的一个信号。
  • 将空信号(almost empty):FIFO将要空时由FIFO的状态电路送出的一个信号。
FIFO指针的工作方式

根据下面一张图我们来了解FIFO读写指针的工作方式;其中WP写指针RP读指针

写指针总是指向下一个时钟要写的地址读指针总是指向下一个时钟要读的地址读指针等于写指针的时候可能为空,有可能为满。(读指针也可以指向当前正在读的地址,但相应的根据地址读取数据的逻辑会有所不同,前面读指针指向下一个时钟要读的地址是用时序逻辑去读,指向当前正在读的地址用组合逻辑去读。)

FIFO没有写满并且写使能拉高时,写指针加一,当FIFO没有读空并且读使能拉高时,读指针加一

FIFO的空满检测

可以通过在FIFO内部设立一个计数器用来计数FIFO内的数据量;

  • 当FIFO没有写满且写使能拉高时(或者写指针加一时),计数器加一
  • 当FIFO没有读空且读使能拉高时(或者读指针加一时),计数器减一
  • 当FIFO既没有读空又没有写满,且读写使能同时拉高有效时,这时的计数器不加也不减

还可以采用在读写地址前增加一位的策略。如果FIFO的深度为16,则地址需要4位二进制数来表示,那么在表示FIFO地址时用5位二进制数来表示。

当有数据进入时,写指针继续增大,当写指针为15(01111)时,继续增大来到了0地址处,这时第五位置为1(10000),继续增大;

当读指针与写指针低四位相同最高为相反时,表示fifo已经写满

当读指针与写指针最高位相反,低四位不同时,使用写指针的低4位减去读指针的低4位(表示当前FIFO空余的位置),在加FIFO的深度,即可表示计数器cnt的值(即FIFO队列中有多少数据)

解题:

输出信号有:写满信号(wfull)、读空信号(rempty)、读数据(rdata)

设计读指针和写指针

指针指向的位置即为当前读数据或写数据的地址

//读指针和写指针部分
reg [$clog2(DEPTH):0] wpoint, rpoint;  //读指针、写指针

wire wenc, renc;
assign wenc = winc && (!wfull); //当写使能为1且FIFO未满时
assign renc = rinc && (!rempty);//当读使能为1且FIFO未空时
//读指针
always @(posedge clk or negedge rst_n) begin
	if (!rst_n)	wpoint <= 'd0; 
	else begin 
		if (wenc)	wpoint <= wpoint + 1'd1;
	end
end
//写指针
always @(posedge clk or negedge rst_n) begin
	if (!rst_n)	rpoint <= 'd0;
	else begin 
		if (renc)	rpoint <= rpoint + 1'd1;
	end
end
②计数器cnt部分设置(难点)

判断WP指针的最高位与RP指针的最高位是否完全相等;当最高位为1时,说明指针已经经过了FIFO的最后一位数并且回到了最初;

①当WP [4]= RP[4]时,说明此时FIFO队列还未写满,cnt等于写指针地址-读指针地址;

例如:WP = '01011',RP = '00011',cnt = WP-RP = '01000'=8; \\ WP = '11011',RP = '10011',cnt = WP-RP = '01000'=8; \\ WP = '01111',RP = '01111',cnt = WP-RP = '00000'=0

②当WP[4]!=RP[4]时,说明此时FIFO队列中写指针比读指针先循环了一个FIFO周期

例如:WP = '10010', RP = '01100',表明写指针已经经过了最后一个地址01111,返回到0010地址,并将最高位标为1

cnt = DEPTH+WP[3:0]-RP[3:0]=16+(-10)=6

当读指针与写指针的后四位相同,但是最高位相反时,说明FIFO已满

例如:WP = '10010', RP = '00010'\\ cnt = DEPTH+WP[3:0]-RP[3:0]=16

//cnt部分
wire [$clog2(DEPTH) : 0]    cnt;
 
assign cnt = (wpoint[$clog2(DEPTH)] == rpoint[$clog2(DEPTH)]) ? 
			 (wpoint[$clog2(DEPTH):0] - rpoint[$clog2(DEPTH):0]) :
             (DEPTH + wpoint[$clog2(DEPTH)-1:0] - rpoint[$clog2(DEPTH)-1:0]);
②判断写满信号(wfull)

当计数器cnt计数达到FIFO深度值(DEPTH)时,则wfull = 1'b1,否则wfull = 1'b0;

//判断是否写满
always @(posedge clk or negedge rst_n) begin
	if (!rst_n)	wfull = 1'b0;
	else begin
		if (cnt == DEPTH)	wfull = 1'b1;
		else wfull = 1'b0;
	end
end
③判断读空信号(rempty):

当计数器cnt计数为0时rempty = 1’b1,否则rempty = 1’b0;

//判断当前是否为空
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) rempty = 1'b0;
	else begin
		if (cnt == 4'd0)	 rempty = 1'b1;
		else	rempty = 1'b0;
	end
end
④RAM例化部分
//例化RAM
dual_port_RAM #(.DEPTH(DEPTH),
				.WIDTH (WIDTH))
	RR(
	.wclk(clk),                       //写数据时钟
	.wenc(wenc),                      //写使能
	.waddr(wpoint[$clog2(DEPTH)-1:0]),//写地址
	.wdata(wdata),          		  //输入数据 	
	.rclk(clk),						  //读数据时钟
	.renc(renc),                      //读使能
	.raddr(rpoint[$clog2(DEPTH)-1:0]), //读地址
	.rdata(rdata)   				  //输出数据	
);
代码如下
/**********************************SFIFO************************************/
module sfifo#(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16
)(
	input 					clk		, 
	input 					rst_n	,
	input 					winc	,//写使能
	input 			 		rinc	,//读使能
	input 		[WIDTH-1:0]	wdata	, //写数据

	output reg				wfull	, //写满信号
	output reg				rempty	, //读空信号
	output wire [WIDTH-1:0]	rdata      //读数据
);

//读指针和写指针部分
reg [$clog2(DEPTH):0] wpoint, rpoint;  //读指针、写指针

wire wenc, renc;
assign wenc = winc && (!wfull); //当写使能为1且FIFO未满时
assign renc = rinc && (!rempty);//当读使能为1且FIFO未空时
//读指针
always @(posedge clk or negedge rst_n) begin
	if (!rst_n)	wpoint <= 'd0; 
	else begin 
		if (wenc)	wpoint <= wpoint + 1'd1;
	end
end
//写指针
always @(posedge clk or negedge rst_n) begin
	if (!rst_n)	rpoint <= 'd0;
	else begin 
		if (renc)	rpoint <= rpoint + 1'd1;
	end
end

//cnt部分
wire [$clog2(DEPTH) : 0]    cnt;
 
assign cnt = (wpoint[$clog2(DEPTH)] == rpoint[$clog2(DEPTH)]) ? 
			 (wpoint[$clog2(DEPTH):0] - rpoint[$clog2(DEPTH):0]) :
             (DEPTH + wpoint[$clog2(DEPTH)-1:0] - rpoint[$clog2(DEPTH)-1:0]);

//判断是否写满
always @(posedge clk or negedge rst_n) begin
	if (!rst_n)	wfull = 1'b0;
	else begin
		if (cnt == DEPTH)	wfull = 1'b1;
		else wfull = 1'b0;
	end
end

//判断当前是否为空
always @(posedge clk or negedge rst_n) begin
	if (!rst_n) rempty = 1'b0;
	else begin
		if (cnt == 4'd0)	 rempty = 1'b1;
		else	rempty = 1'b0;
	end
end


//例化RAM
dual_port_RAM #(.DEPTH(DEPTH),
				.WIDTH (WIDTH))
	RR(
	.wclk(clk),                       //写数据时钟
	.wenc(wenc),                      //写使能
	.waddr(wpoint[$clog2(DEPTH)-1:0]),//写地址
	.wdata(wdata),          		  //输入数据 	
	.rclk(clk),						  //读数据时钟
	.renc(renc),                      //读使能
	.raddr(rpoint[$clog2(DEPTH)-1:0]), //读地址
	.rdata(rdata)   				  //输出数据	
);

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

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

相关文章

828华为云征文|使用Flexus X实例集成ES搜索引擎

目录 一、应用场景 1.1 Flexus X实例概述 1.2 ES搜索引擎 二、安装相关服务 2.1 安装Elasticsearch7.17.0 2.2 安装kibana7.17.0 三、开通安全组规则 四、整体感受 4.1 Flexus X实例 4.2 使用感觉 一、应用场景 1.1 Flexus X实例概述 Flexus X实例是华为云推出的一款…

Windows内核编程基础(2)

上下文环境 应用层应用程序工作在用户模式&#xff0c;内核驱动程序工作在内核模式。这里的用户模式和内核模式是基于CPU的特权环来定义的&#xff0c;CPU提供了0环~3环(ring 0 ~ ring 3)共四个特权环&#xff0c;Windows操作系统使用了其中的0环和3环&#xff0c;0环为内核模…

【深度学习】(7)--保存最优模型

文章目录 保存最优模型一、两种保存方法1. 保存模型参数2. 保存完整模型 二、迭代模型 总结 保存最优模型 我们在迭代模型训练时&#xff0c;随着次数初始的增多&#xff0c;模型的准确率会逐渐的上升&#xff0c;但是同时也随着迭代次数越来越多&#xff0c;由于模型会开始学…

大数据-148 Apache Kudu 从 Flink 下沉数据到 Kudu

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

Spring Boot房屋租赁平台:现代化解决方案

1 绪论 1.1 研究背景 中国的科技的不断进步&#xff0c;计算机发展也慢慢的越来越成熟&#xff0c;人们对计算机也是越来越更加的依赖&#xff0c;科研、教育慢慢用于计算机进行管理。从第一台计算机的产生&#xff0c;到现在计算机已经发展到我们无法想象。给我们的生活改变很…

Recaptcha2 图像识别 API 对接说明

Recaptcha2 图像识别 API 对接说明 本文将介绍一种 Recaptcha2 图像识别2 API 对接说明&#xff0c;它可以通过用户输入识别的内容和 Recaptcha2验证码图像&#xff0c;最后返回需要点击的小图像的坐标&#xff0c;完成验证。 接下来介绍下 Recaptcha2 图像识别 API 的对接说…

8.12DoG (Difference of Gaussians)

基本概念 不同尺度的高斯模糊图像之间的差异&#xff08;DoG&#xff09;&#xff0c;用于边缘检测。函数: cv::GaussianBlur() 结合 cv::Laplacian() 或者自定义DoG实现。 在OpenCV中并没有直接提供一个名为“DoG”&#xff08;Difference of Gaussians&#xff09;的函数&a…

【学术会议征稿】第四届人工智能、机器人和通信国际会议(ICAIRC 2024)

第四届人工智能、机器人和通信国际会议&#xff08;ICAIRC 2024&#xff09; 2024 4th International Conference on Artificial Intelligence, Robotics, and Communication 第四届人工智能、机器人和通信国际会议&#xff08;ICAIRC 2024&#xff09;定于2024年12月27-29日…

css 自定义滚动条样式

* { scrollbar-color: auto !important; scrollbar-width: auto; } //滚动条宽高 ::-webkit-scrollbar { width: 4px; height: 4px; background: transparent; } ::-webkit-scrollbar-thumb { //滑块部分 border-radius: 5px; background-color: rgba(32, 224, 254, 1); } ::-…

【Python报错已解决】TypeError: can only concatenate str (not “float“) to str

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

docker compose的使用

docker compose 1.概述 是 Docker 官方提供的一款开源工具&#xff0c;主要用于简化在单个主机上定义和运行多容器 Docker 应用的过程。它的核心作用是容器编排&#xff0c;使得开发者能够在一个统一的环境中以声明式的方式管理多容器应用的服务及其依赖关系。 也就是说Docker…

用 Django 5 快速生成一个简单 进销存 系统 添加 个打印 按钮

一、前置条件&#xff1a; 1.安装好python 【关联网址】 2. 安装好vscode 【关联网址】 插件 3. 登陆海螺AI【关联网址】 4. 安装好 pip install django 【关联网址】 pip install django -i https://mirrors.aliyun.com/pypi/simple/ 二、开始生成 1. 打开vscode 打开…

[数据库实验五] 审计及触发器

一、实验目的与要求&#xff1a; 1.了解MySQL审计功能及实现方式 2.掌握触发器的工作原理、定义及操作方法 二、实验内容&#xff1a; 注&#xff1a; 在同一个触发器内编写多行代码&#xff0c;需要用结构begin ……end 函数current_user()获得当前登录用户名 1.自动保存…

Linux 应用层自定义协议与序列化

文章目录 一、应用层1、协议2、序列化 && 反序列化3、通过Json库进行数据的序列化 && 反序列化Json::Value类Json::Reader类Json::Writer类 二、为什么read、write、recv、send和Tcp支持全双工&#xff1f;发数据的本质&#xff1a;tcp支持全双工通信的原因&am…

gitlab-runner集成CI/CD完整项目部署

目录 1.环境安装 2.gitlab代码仓库搭建 3.gitlab-runner-安装以及注册 4..gitlab-ci.yml脚本 5.脚本说明 6.build.sh 7.test.sh 8. deploy.sh 9.运行流水线 10.选择流水线分支 11.查看运行阶段 12.查看运行日志 13.查看服务器真实日志 1.环境安装 确保服务器的Java环…

Python_异常机制

软件程序在运行过程中&#xff0c;非常可能遇到刚刚提到的这些问题&#xff0c;我们称之为异常&#xff0c;英文是&#xff1a;Exception&#xff0c;意思是例外。遇到这些例外情况&#xff0c;或者叫异常&#xff0c;我们怎么让写的程序做出合理的处理&#xff0c;安全的退出&…

Footprint Growthly Quest 工具:赋能 Telegram 社区实现 Web3 飞速增长

作者&#xff1a;Stella L (stellafootprint.network) 在 Web3 的快节奏世界里&#xff0c;社区互动是关键。而众多 Web3 社区之所以能够蓬勃发展&#xff0c;很大程度上得益于 Telegram 平台。正因如此&#xff0c;Footprint Analytics 精心打造了 Growthly —— 一款专为 Tel…

Tkinter制作登录界面以及登陆后页面切换

Tkinter制作登录界面以及登陆后页面切换 前言序言1. 由来2. 思路3. 项目结构描述4. 项目实战1. 登录界面实现&#xff08;代码&#xff09;2. 首页界面实现&#xff08;代码&#xff09;3. 打包build.py&#xff08;与main.py同级目录&#xff09;4. 打包安装包 前言 本帖子&a…

【nrm】npm 注册表管理器

nrm是什么 nrm&#xff08;NPM Registry Manager&#xff09;是一个用于管理 Node.js 包管理器&#xff08;如 npm 和 Yarn&#xff09;的注册表工具。它可以帮助用户快速切换不同的 npm 源&#xff0c;以便于提高包安装的速度和效率&#xff0c;特别是在中国大陆地区&#xf…

Ubuntu23.10下处理libncurses5-dev包的安装问题

Ubuntu23.10下处理libncurses5-dev包的安装问题 导语环境准备问题和解决方案总结参考文献 导语 使用Ubuntu23.10的时候&#xff0c;遇到需要termios的场景&#xff0c;结果发现无论是codeblocks还是系统本身的gcc都无法找到term.h和curse.h&#xff0c;网上找了很多解决方案都…