verilog FPGA 同步FIFO设计及仿真

本文详细介绍了使用Verilog进行FPGA同步FIFO的设计过程,包括核心思想、时序控制、存储结构和代码实现。在设计中,重点讨论了计数器的特殊处理和寄存器数组的初始化。通过实例展示了读写地址的更新逻辑,并提供了完整的FIFO模块代码。同时,还给出了测试平台fifo_sync_tb.v用于验证设计的正确性。
摘要由CSDN通过智能技术生成

verilog FPGA 同步FIFO设计及仿真

一、核心思想

FIFO即First In First Out,是一种数据缓冲方式。同步FIFO的读写端在同一时钟下

二、时序

1、写操作

当写入一个数据,写有效拉高,写地址加一,数据存量加一

2、读数据

当读出一个数据,读有效拉高,读地址加一,数据存量减一

3、存数据

利用寄存器组来实现数据的存储

四、设计难点

1、计数器与一般的计数器不同,在这里没有用add_cnt 和end_cnt,因为计数器本身会有减的情况
2、寄存器数组置零,在这里首次使用for循环来对其循环置零

五、代码实现

fifo_sync.v

module fifo_sync#(parameter dwidth = 8,awidth = 8)(//fifo 宽度为8,深度为2^8=256
	input 				 		clk		,
	input 				 		rst_n	,
	input   			 		wr_req	,
	input 		[dwidth-1:0] 	wr_data	,
	input				 		rd_req	,
	output		[dwidth-1:0] 	rd_data	,
	output 	reg[awidth-1:0] 	cnt		,//数据量
	output  			 		full	,
	output  			 		empty
);
	
	reg	 [awidth-1:0]	wr_addr;//写地址
	wire				add_wr_addr;
	wire				end_wr_addr;
	reg	 [awidth-1:0]	rd_addr;//读地址
	wire				add_rd_addr;
	wire				end_rd_addr;
	reg  [dwidth-1:0]	fifo_ram[{(awidth){1'b1}}:0];//寄存器组
	
	integer				i;

	//cnt 当读信号有效,cnt-1,当写信号有效,cnt+1
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			cnt <= 1'b0;
		end
		else if(rd_req &&wr_req)begin//当同时读写cnt不变
			cnt <= cnt;
		end
		else if(wr_req && cnt<{(awidth){1'b1}})begin//当写信号有效且非满cnt加一
			cnt <= cnt+1;
		end
		else if(rd_req && cnt>0)begin//当读信号有效且非空cnt减一
			cnt <= cnt-1;
		end
		else 
			cnt <= cnt;
	end
	
	//wr_addr
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			wr_addr <= 0;
		end
		else if(add_wr_addr)begin
			if(end_wr_addr)
				wr_addr <= 0;
			else
				wr_addr <= wr_addr+1;
		end
	end
	assign add_wr_addr = wr_req;
	assign end_wr_addr = add_wr_addr && wr_addr == {(awidth){1'b1}};
	
	//rd_addr
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			rd_addr <= 0;
		end
		else if(add_rd_addr)begin
			if(end_rd_addr)
				rd_addr <= 0;
			else
				rd_addr <= rd_addr+1;
		end
	end
	assign add_rd_addr = rd_req;
	assign end_rd_addr = add_rd_addr && rd_addr == {(awidth){1'b1}};
	
	//empty
	assign empty=(cnt!=0)?0:1;
	
	//full
	assign full = (cnt == {(awidth){1'b1}})?1:0;
	
	//wr_data
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
				for(i=0;i<={(awidth){1'b1}};i=i+1)begin
					fifo_ram[i] <= {(dwidth){1'b0}};
				end
		end
		else begin
			fifo_ram[wr_addr] <= wr_data;
		end
	end
	//rd_data
	assign rd_data = fifo_ram[rd_addr];
endmodule

fifo_sync_tb.v

`timescale 1ns/1ps
module fifo_sync_tb();
	reg 			 tb_clk		;
	reg 			 tb_rst_n	;
	reg   			 tb_wr_req	;
	reg 	[7:0] 	 tb_wr_data	;
	reg				 tb_rd_req	;
	wire	[7:0] 	 tb_rd_data	;
	wire 	[4:0] 	 tb_cnt		;
	wire  			 tb_full	;
	wire  			 tb_empty  	;
	
	
	fifo_sync u_fifo_sync(
	.clk					(tb_clk		),
	.rst_n					(tb_rst_n	),
	.wr_req					(tb_wr_req	),
	.wr_data				(tb_wr_data	),
	.rd_req					(tb_rd_req	),
	.rd_data				(tb_rd_data	),
	.cnt					(tb_cnt		),//数据量
	.full					(tb_full	),
	.empty					(tb_empty  	)
);
	defparam u_fifo_sync.dwidth = 8,
			 u_fifo_sync.awidth = 8;
	
	parameter CLOCK_CYCLE=20;
	
	initial tb_clk = 1'b0;//初始化时钟
	always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;
	integer i=0,j=0;
	initial begin
		tb_rst_n = 1'b1;
		tb_wr_req = 1'b0;
		tb_rd_req = 1'b0;
		tb_wr_data = 8'd0;
		#(20*CLOCK_CYCLE);
		tb_rst_n = 1'b0;
		#(20*CLOCK_CYCLE);
		tb_rst_n = 1'b1;
		
		repeat(40)begin
			for(j=0;j<20;j = j+1)begin
				i = {$random}%30;
				#2;
				tb_wr_req = {$random};
				tb_rd_req = {$random};
				tb_wr_data = {$random}%255;
				#(CLOCK_CYCLE*i);
			end
		end
		
	$stop;
	end
endmodule
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值