【Verilog】用双口RAM实现同步FIFO

这篇具有很好参考价值的文章主要介绍了【Verilog】用双口RAM实现同步FIFO。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

功能描述

【Verilog】用双口RAM实现同步FIFO
端口说明如下表。

  1. 双口RAM端口说明:
    【Verilog】用双口RAM实现同步FIFO
  2. 同步FIFO端口说明:
    【Verilog】用双口RAM实现同步FIFO

输入描述:
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

双口RAM和代码框架:

`timescale 1ns/1ns
/**********************************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  

/**********************************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
);
endmodule

模块解析

同步FIFO,就是我们学习其他经典计算机语言(如C语言)的数据结构时,常说的“队列”了。FIFO即first in first out,数据向内压入堆叠,读取时读下方先压入的数据。不懂的先去了解“队列”!

1. 读写指针控制块:

需要注意“允许写入”和“允许读取”的条件!

reg	[$clog2(DEPTH)-1:0]		rd_pt;	//读指针rd_pt,指向下一个要读出的数据地址。
reg [$clog2(DEPTH)-1:0] 	wt_pt;  //写指针wt_pt,指向下一个要写入的数据地址。
//长度设置成$clog2(DEPTH)而不是$clog2(DEPTH)-1,是为了后面处理存满溢出。

//读写指针控制块
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)	begin   //initialize
		rd_pt <= 0;
		wt_pt <= 0;
	end
	else	begin
		if(!wfull && winc)			//没有写满,并且写使能:允许写入,写指针+1
			wt_pt <= wt_pt + 1;
		else if(!rempty && rinc)	//没有取空,并且读使能:允许读出,读指针+1
			rd_pt <= rd_pt + 1;
		else	begin
			wt_pt <= wt_pt;
			rd_pt <= rd_pt;
		end
	end
end

2. 存满指示wfull和存空指示rempty控制块:

指示当前队列是否存满,可以用读写指针的大小判断来书写。但如果我们另外用一个计数器cnt来记录当前存入了多少,判断就变得非常简单了。但是

//记录当前存放数据量控制块
reg	[$clog2(DEPTH):0]	data_inside_cnt;	//记录当前存放有多少数据的计数器
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)	data_inside_cnt <= 0;
	else if(!wfull && winc)		data_inside_cnt <= data_inside_cnt + 1;
	else if(!rempty && rinc)	data_inside_cnt <= data_inside_cnt - 1;
	else						data_inside_cnt <= data_inside_cnt;
end
//存满指示wfull和存空指示rempty控制块
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)	begin
		wfull <= 0;
		rempty <= 0;
	end
	else if(data_inside_cnt == DEPTH)	wfull <= 1;
	else if(data_inside_cnt == 0)		rempty <= 1;
	else	begin
		wfull <= 0;
		rempty <= 0;
	end
end

3. 实例化双口RAM:文章来源地址https://www.toymoban.com/news/detail-468884.html

//具体数据存储和读写,交给实例化双向RAM
wire	wen_con;	//写使能连接线
wire	ren_con;	//读使能连接线
assign	wen_con = ~wfull & winc;
assign	ren_con = ~rempty & rinc;
//由于模块间连线只能用wire,现在用wire存储一遍wt_pt和rd_pt
wire	[$clog2(DEPTH)-1:0]wt_pt_con;
wire	[$clog2(DEPTH)-1:0]rd_pt_con;
assign	wt_pt_con = wt_pt;
assign	rd_pt_con = rd_pt;

dual_port_RAM #(
	.DEPTH(DEPTH),
	.WIDTH(WIDTH)
)
u_RAM
(
	.wclk(clk),		   	//同步FIFO:wclk---clk
	.wenc(wen_con),
	.waddr(wt_pt),     	//写指针wt_pt-----写地址
	.wdata(wdata),
	.rclk(clk),			//同步FIFO:rclk---clk
	.renc(ren_con),		
	.raddr(rd_pt),		//读指针rd_pt-----读地址
	.rdata(rdata)
);


完整代码

/**********************************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


/**********************************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)-1:0]		rd_pt;	//读指针rd_pt,指向下一个要读出的数据地址。
reg [$clog2(DEPTH)-1:0] 	wt_pt;  //写指针wt_pt,指向下一个要写入的数据地址。
//长度设置成$clog2(DEPTH)而不是$clog2(DEPTH)-1,是为了后面处理存满溢出。

//读写指针控制块
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)	begin   //initialize
		rd_pt <= 0;
		wt_pt <= 0;
	end
	else	begin
		if(!wfull && winc)			//没有写满,并且写使能:允许写入,写指针+1
			wt_pt <= wt_pt + 1;
		else if(!rempty && rinc)	//没有取空,并且读使能:允许读出,读指针+1
			rd_pt <= rd_pt + 1;
		else	begin
			wt_pt <= wt_pt;
			rd_pt <= rd_pt;
		end
	end
end

//记录当前存放数据量控制块
reg	[$clog2(DEPTH):0]	data_inside_cnt;	//记录当前存放有多少数据的计数器
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)	data_inside_cnt <= 0;
	else if(!wfull && winc)		data_inside_cnt <= data_inside_cnt + 1;
	else if(!rempty && rinc)	data_inside_cnt <= data_inside_cnt - 1;
	else						data_inside_cnt <= data_inside_cnt;
end
//存满指示wfull和存空指示rempty控制块
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)	begin
		wfull <= 0;
		rempty <= 0;
	end
	else if(data_inside_cnt == DEPTH)	wfull <= 1;
	else if(data_inside_cnt == 0)		rempty <= 1;
	else	begin
		wfull <= 0;
		rempty <= 0;
	end
end

//具体数据存储和读写,交给实例化双向RAM
wire	wen_con;	//写使能连接线
wire	ren_con;	//读使能连接线
assign	wen_con = ~wfull & winc;
assign	ren_con = ~rempty & rinc;
//由于模块间连线只能用wire,现在用wire存储一遍wt_pt和rd_pt
wire	[$clog2(DEPTH)-1:0]wt_pt_con;
wire	[$clog2(DEPTH)-1:0]rd_pt_con;
assign	wt_pt_con = wt_pt;
assign	rd_pt_con = rd_pt;

dual_port_RAM #(
	.DEPTH(DEPTH),
	.WIDTH(WIDTH)
)
u_RAM
(
	.wclk(clk),		   	//同步FIFO:wclk---clk
	.wenc(wen_con),
	.waddr(wt_pt),     	//写指针wt_pt-----写地址
	.wdata(wdata),
	.rclk(clk),			//同步FIFO:rclk---clk
	.renc(ren_con),		
	.raddr(rd_pt),		//读指针rd_pt-----读地址
	.rdata(rdata)
);

endmodule

到了这里,关于【Verilog】用双口RAM实现同步FIFO的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【FPGA零基础学习之旅#17】搭建串口收发与储存双口RAM系统

    🎉欢迎来到FPGA专栏~搭建串口收发与储存双口RAM系统 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🥝 输入数据: 🥝

    2024年02月08日
    浏览(45)
  • Verilog基础之十六、RAM实现

    目录 一、前言 二、工程设计 2.1 RAM IP核使用 2.2 设计代码 2.3 仿真代码 2.4 综合结果 2.5 仿真结果     工程设计中除逻辑计算单元外,存储单元也是不可获取的部分,RAM(Random Access Memory)随机存取存储器即可以写入数据,也可读取数据,写入或读取的位置由输入的地址决定。

    2024年02月06日
    浏览(33)
  • Verilog的三种描述方式(结构化描述、数据流描述、行为级描述对电路功能的描述有三种方式:结构化描述、数据流描述、行为级描述

    Verilog的三种描述方式(结构化描述、数据流描述、行为级描述对电路功能的描述有三种方式:结构化描述、数据流描述、行为级描述。三种描述方式抽象级别不同,各有优缺点,相辅相成,需要配合使用。 目录 一、结构化描述 1、概念 2、特点 3、示例 真值表: 电路抽象:

    2024年02月04日
    浏览(64)
  • Vivado:ROM和RAM的verilog代码实现

    本文主要介绍ROM和RAM实现的verilog代码版本,可以借鉴参考下。 Read-only memory(ROM)使用ROM_STYLE属性选择使用寄存器或块RAM资源来实现ROM,示例代码如下: RAM设计方式有很多,可以用BRAM、LUT、分布式RAM、URAM实现,可以使用RAM_STYLE属性强制规定使用的资料类型。 (*rom_style = \\\"bl

    2024年02月09日
    浏览(39)
  • FIFO专题之单口RAM实现FIFO(同步)

    使用单口RAM实现FIFO,其实很简单,其中的重点就是区分出读写, 读写如果同时启动,你肯定会思考单口RAM肯定会出问题,毕竟单口RAM只有一个口,肯定不能实现同时读写,那么怎么解决这个问题呢。 有两种办法: 第一种办法就是采用两个单口RAM,这样就可以了,两个单口

    2024年02月02日
    浏览(39)
  • 全减器---Verilog实现(结构描述,数据流描述,行为描述,层次结构描述)

    全减器真值表—引用知乎:链接: 全减器真值表怎么理解 代码部分 原理图 代码部分 原理图 代码部分 原理图 代码部分 原理图

    2024年02月12日
    浏览(57)
  • Verilog实现FPGA可编程电路中的RAM存储器

    Verilog实现FPGA可编程电路中的RAM存储器 在FPGA可编程电路的设计中,RAM存储器通常被广泛使用。而手写RAM存储器则可以提供更加灵活、高效的设计方案。本文将介绍如何使用Verilog语言来手写FPGA中的RAM存储器。 首先,我们需要确定RAM存储器的大小和宽度。假设我们需要实现一个

    2024年02月04日
    浏览(53)
  • 【Verilog】同步FIFO原理及verilog实现(参数化)

            旨在学习理解,项目中还是用成熟IP靠谱~ 目录 一、FIFO原理 二、同步FIFO设计 2.1 位宽和深度 2.2 空、满标志 2.3 FIFO计数 2.4 ram模型 2.5 读/写操作 三、​​​​​​​verilog代码 四、仿真验证 后记 FIFO( First Input First Output)是指先进先出。模型如下:           F

    2024年02月05日
    浏览(34)
  • Android 9.0 kenel和frameworks中修改ram运行内存的功能实现

    在9.0的系统rom产品开发定制中,在对一些产品开发中的配置需求方面,在产品后续订单中,在某些机型中需要升级下系统内核配置,项目时间比较仓促,所以 来不及对硬件重新定制,就需要软件方面在ram运行内存的容量大小方面作假,修改ram真实的大小容量,所以就需要在

    2024年02月09日
    浏览(40)
  • 同步FIFO的verilog实现(2)——高位扩展法

            在之前的文章中,我们介绍了同步FIFO的verilog的一种实现方法:计数法。其核心在于:在同步FIFO中,我们可以很容易的使用计数来判断FIFO中还剩下多少可读的数据,从而可以判断空、满。         关于计数法实现同步FIFO的详细内容,请参考:同步FIFO的verilog实现(

    2024年02月09日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包