Verilog:同步FIFO使用计数器的写法

文章描述了一个同步FIFO(先进先出)的实现,包括其设计规格,如输入输出信号、时序逻辑以及内存管理。RTL代码展示了如何处理写入和读取操作,以及如何利用计数器来跟踪内存状态。TB测试模块用于验证FIFO的功能。
摘要由CSDN通过智能技术生成

同步FIFO(First in first out),先入先出。

Deign Spec:

  • 输入信号:clk;
  • 输入信号:异步复位信号:rstn;
  • 输入信号:写使能:wr_en;
  • 输入信号:写数据:wr_data;//时序逻辑,先判断写使能 wr_en 是否有效,有效情况下如果没有写满,则写入数据,如果满了,判断读使能 rd_en ,如果读使能有效能可以继续写数据。
  • 输入信号:读使能:rd_en;
  • 输出信号:读数据:rd_data;//时序逻辑,先判断读使能 rd_en 是否有效,有效情况下如果内存非空,则取上一个周期指针位置的数据作为读数据,如果内存为空,则判断写使能,如果写使能有效则直接将写数据 wr_data 作为读数据输出,无效时输出0。
  • 输出信号:内存满信号:full;//如果计数器 cnt 等于内存深度,则 full 为1
  • 输出信号:内存空信号:empty;//如果计数器 cnt 为0,则 empty 为
  • 读指针:rd_ptr;//时序逻辑,先判断写使能 rd_en 是否有效,有效情况如果内存非空则+1,如果内存空了,判断 wr_en 是否有效,如果有效则+1,否则不变。
  • 写指针:wr_ptr;//时序逻辑,先判断写使能 wr_en 是否有效,有效情况如果内存非满则+1,如果内存满了,判断 rd_en 是否有效,如果有效则+1,否则不变。
  • 内存:mem;//内存深度要为 2^n 大小,即指针可以通过+1自动循环。
  • 计数器:cnt;//如果 wr_en 和 rd_en 同时有效,则无论内存空满,cnt不变。如果单纯是 wr_en 有效且非满的情况下,cnt+1,如果单纯是 rd_en 有效且非空的情况下 cnt-1

RTL代码:

module sync_fifo#(
	parameter DEPTH = 16,	//DEPTH = 2^n
	parameter WIDTH = 8
)(
	input				clk,
	input				rstn,
	
	//write
	input				wr_en,		//write enable
	input [WIDTH-1:0]	wr_data,	//write data
	output				full,
	
	//read
	input				rd_en,		//read enable
	output reg [WIDTH-1:0]	rd_data,	//read data
	output				empty,
	
	output reg [$clog2(DEPTH):0] cnt
);

	reg	[$clog2(DEPTH)-1:0] rd_ptr, wr_ptr;
	reg	[WIDTH-1:0]	mem	[0:DEPTH-1];

	//********** read start **********//
	always@(posedge clk, negedge rstn) begin
		if(~rstn) begin
			rd_ptr <= 0;
		end
		else if(rd_en && ~empty) begin
			rd_ptr <= rd_ptr + 1'b1;
		end
		else if(rd_en && empty && wr_en) begin
			rd_ptr <= rd_ptr + 1'b1;
		end
	end
	
	always@(posedge clk, negedge rstn) begin
		if(~rstn) begin
			rd_data <= 0;
		end
		else if(rd_en && ~empty) begin
			rd_data <= mem[rd_ptr];
		end
		else if(rd_en && empty && wr_en) begin
			rd_data <= wr_data;
		end
		else begin
			rd_data <= 0;
		end
	end
	//********** read end **********//
	
	//********** write start **********//
	always@(posedge clk, negedge rstn) begin
		if(~rstn) begin
			wr_ptr <= 0;
		end
		else if(wr_en && ~full) begin
			wr_ptr <= wr_ptr + 1'b1;
		end
		else if(wr_en && full && rd_en) begin
			wr_ptr <= wr_ptr + 1'b1;
		end
	end
	
	always@(posedge clk) begin
		if(wr_en && ~full) begin
			mem[wr_ptr] <= wr_data;
		end
		else if(wr_en && full && rd_en) begin
			mem[wr_ptr] <= wr_data;
		end
	end
	//********** write end **********//
	
	//********** cnt **********//
	always@(posedge clk, negedge rstn) begin
		if(~rstn) begin
			cnt <= 0;
		end
		else if(wr_en && rd_en) begin
			cnt <= cnt;
		end
		else if(wr_en && ~full) begin
			cnt <= cnt + 1'b1;
		end
		else if(rd_en && ~empty) begin
			cnt <= cnt - 1'b1;
		end
	end
	
	assign full = (cnt == DEPTH);
	assign empty = (cnt == 0);

endmodule

TB代码:

module test#(
	parameter DEPTH = 16,
	parameter WIDTH = 8
);

	reg		clk;
	reg 	rstn;
	reg 	wr_en;
	reg 	[WIDTH-1:0] wr_data;
	wire	full;
	reg 	rd_en;
	wire	[WIDTH-1:0]	rd_data;
	wire	empty;
	wire	[$clog2(DEPTH):0]	cnt;
	
	sync_fifo 	u0(
		.clk(clk),
		.rstn(rstn),
		.wr_en(wr_en),
		.wr_data(wr_data),
		.full(full),
		.rd_en(rd_en),
		.rd_data(rd_data),
		.empty(empty),
		.cnt(cnt)
	);
	
	initial begin
		clk = 0;
		rstn = 0;
		wr_en = 0;
		wr_data = 0;
		rd_en = 0;
		#30	rstn = 1;
	end
	
	always #10 clk = ~clk;
	
	always@(posedge clk) begin
		if(({$random()}%16)<10) wr_en <= 1;
		else wr_en <= 0;
		if(({$random()}%16)<7) rd_en <= 1;
		else rd_en <= 0;
	end
 	
	always@(posedge clk) begin
		wr_data <= {$random()} & 8'hff;
	end
	
	initial begin
		#4000 $finish;
	end
	
endmodule

波形:

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
异步FIFO同步FIFO是两种不同的FIFO(First-In-First-Out)设计方式。 异步FIFO是指读写时钟为不同时钟,读写时钟彼此相互独立。异步FIFO的设计关键点是区分读空和写满这两种不同的状态,即FIFO在被写满后不能再写入,从而覆盖原有数据;再被读空后不能再进行读操作,防止读取无效数据。异步FIFO的设计方法包括计数器法、高位扩展法和单端口/双端口RAM等。\[1\] 同步FIFO是指读时钟与写时钟为同一时钟,在时钟上升沿同时发生读写操作。同步FIFO的设计方法包括使用计数器和RAM实现同步FIFO同步FIFO的读写判断存在漏洞,不是真空或真满,因为写指针和读指针需要通过两级寄存器同步到对应的时钟域,同步后的指针可能小于或等于当前实际的指针,所以判断FIFO为空或满不一定是真空或真满。这种设计保守但不会出错。\[2\] 异步FIFO同步FIFO在设计和工作原理上有所不同,具体选择哪种方式取决于具体的应用需求和设计要求。 #### 引用[.reference_title] - *1* [同步FIFO与异步FIFO](https://blog.csdn.net/buzhiquxiang/article/details/103287220)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [同步FIFO、异步FIFO详细介绍、verilog代码实现、FIFO最小深度计算、简答题](https://blog.csdn.net/qq_42135020/article/details/129994364)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王bf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值