IC基础——同步FIFO

文章详细介绍了同步FIFO的基本概念,强调了在同一时钟域下避免同步问题的关键。讨论了空满判断的两种方法,包括次态判断和地址扩展,并提供了相应的电路代码描述。此外,还对比了组合逻辑和时序逻辑输出full、empty信号的差异。文章适合芯片设计初学者,旨在促进理解和交流。
摘要由CSDN通过智能技术生成

0、同步fifo的基本概念

同步fifo其实就是在同一个时钟域下,实现先进先出的buffer;相比较异步fifo来说整个设计是比较好理解的。

1、同步fifo设计的关键问题

和异步fifo一样,也要考虑空满判断条件,但因为是同一个时钟域,所以不用考虑同步的问题;
满:写指针增加追上读指针;
空:读指针增加追上写指针。
示意图:
判满
判空

上述示意图的意思是为了寄存输出full和empty,所以是以次态来判断指针是否相等,在下1T即可得到full和empty的信号;
不过上述是示意图是以写时不读或者读时不写的情况说明的,以写满为例说明,当T,写指针指向fifo最后的位置,读指针指向fifo起始位置,此时判断写指针次态即+1的指针是否与当T的读指针相等,相等,当写使能的时候,下1T即写满。判空同理;
如果当T同发生读写,除非一开始写1个同时读1个,存在判空的可能即(wptr=rptr=0),其他情况因为同时读写,之前的状态就不会改变,即非空非满,注意满的时候不能写了,所以不存在上1T是满,下1T能够同时读写;
假设深度是4为例(注意这里指针即地址不是扩展1位的)
以画波形图说明:
在这里插入图片描述
从上图我们就可以看到右边红框是只读不写,然后读指针+1等于写指针,判空;特别是左边红框,可以看到描述就是前面描述判满的那个图,此时读写同时发生,所以不会得出判满的结论。

上面的设计相对来说考虑的要多些,如果只是为了寄存输出full和empty还有种简单点的设计:
读写指针是地址扩展1位的;
取读写指针的次态判断空满;
然后直接打拍次态判断结果。
示意图如下:

在这里插入图片描述
同样以深度为4为例,通过时序图来分析:
在这里插入图片描述
在这里插入图片描述

2、设计电路框架图

在这里插入图片描述

3、描述电路代码

确定好输入输出信号,理解了full和empty的设计,剩下的就是描述这个电路的过程:
方法一:

module sync_fifo
	#(parameter DATA_WIDTH = 8,
	   parameter PTR_WIDTH = 4,
	   parameter DEPTH = 2 ** PTR_WIDTH 
		)
	(input clk,
	input rst_n,
	input wen,
	input ren,
	input [DATA_WIDTH-1:0] wdata,
	output logic [DATA_WIDTH-1:0] rdata,
	output logic full,
	output logic empty
	);
logic [PTR_WIDTH-1:0] wptr;
logic [PTR_WIDTH-1:0]rptr;
logic [DATA_WIDTH-1:0] mem [DEPTH-1:0];

// point increment
always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n) begin
		wptr <= 'h0;
	end else if(wen && !full)
		wptr <= wptr +1'b1;
end
always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		rptr <= 'h0;
	end if(ren && !empty)
		rptr <= rptr + 1'b1;
end
//full
always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		full <= 'h0;
	end else
		full <= ((wen&&!ren) && (rptr == wptr + 1'b1));
end

//empty
always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		empty <= 'h1;
	end else if(!wen)  //only read not write
		empty <= (ren && (wptr == rptr + 1'b1));
	else  // write and read 
	    empty <= (ren && (wptr==rptr));
end
//memory
always_ff @(posedge clk)begin
	 if(wen && !full)
		mem[wptr] <= wdata;
end
always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		rdata <= 'h0;
	end if(ren && !full)
		rdata <= mem[rptr];
end

endmodule // sync_fifo

	

方法二:相比较方法一的设计,方法二使用扩展1位的指针,同样为了寄存输出,需要通过指针次态来判断空满。这里可以联想下前面异步FIFO的关于空满判断的思路。

module sync_fifo
#(parameter DATA_WIDTH = 8,
	   parameter PTR_WIDTH = 4,
	   parameter DEPTH = 2 ** PTR_WIDTH 
		)
	(input clk,
	input rst_n,
	input wen,
	input ren,
	input [DATA_WIDTH-1:0] wdata,
	output logic [DATA_WIDTH-1:0] rdata,
	output logic full,
	output logic empty
	);
	logic [DATA_WIDTH-1:0] mem [DEPTH-1:0];
	logic [PTR_WIDTH-1:0] wptr;
	logic [PTR_WIDTH-1:0] rptr;
	logic [PTR_WIDTH-1:0] wptr_nxt;
	logic [PTR_WIDTH-1:0] rptr_nxt;
    logic full_s;
    logic empty_s;

//next ptr
assign wptr_nxt = wptr + (wen && (!full));
assign rptr_nxt = rptr + (ren && (!empty));

//current ptr
always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		wptr <= 'h0;
	else
		wptr <= wptr_nxt;
end

always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		rptr <= 'h0;
	else
		rptr <= rptr_nxt;
end

//judge full and empty
assign full_s = (rptr_nxt==({~wptr_nxt[PTR_WIDTH-1],wptr_nxt[PTR_WIDTH-2:0]}));
assign empty_s = (wptr_nxt==rptr_nxt);

always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		full <= 'h0;
	else 
		full <= full_s;
end

always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		empty <= 'h1;
	else 
		empty <= empty_s;
end

//RAM
logic [PTR_WIDTH-2:0] waddr;
logic [PTR_WIDTH-2:0] raddr;

assign waddr = wptr[PTR_WIDTH-1:0];
assign raddr = rptr[PTR_WIDTH-1:0];

always_ff @(posedge clk)begin
	if(wen && !full)
		mem[waddr] <= wdata;
end
always_ff @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		rdata <= 'h0;
	else if(ren && !empty)
		rdata <= mem[raddr];
end

endmodule //sync_fifo

4、波形图分析

相同的tb下,两种方法的波形图:
方法1:
在这里插入图片描述
方法2:
在这里插入图片描述

这个tb写的不好,但也能验证设计功能的正确性;两种方法都实现正确读空。

5、关于full和empty的组合逻辑输出和时序逻辑输出比较

上述是寄存输出full和empty,还有一种就是组合逻辑输出full和empty信号的,这两种写法,要根据实际的需求来设计,比如考虑面积,比如这个full信号被其他模块采用,那就最好寄存输出。关于组合逻辑输出full和empt信号的设计已经有很多了,这里不再赘述。

后言

其实这个同步FiFO,没有那么复杂,只是在实际设计中要灵活变通,什么时候需要寄存输出还是组合逻辑输出需要考量;我自认为上面也算写的不错了,但肯定还有不足,作为芯片设计的新人,希望更多人的看到,并提出意见,互相进步吧!

SV小项目-异步FIFO是一个简单的项目,旨在让学生理解FIFO缓存的原理和实现方式。 FIFO缓存是一种常用的数据存储方式,可以用于解决数据传输时的不匹配问题。在异步FIFO中,数据的写入和读取是异步的,意味着数据可以在任何时候写入或读取。这种异步的方式可以增加FIFO的灵活性,并且允许数据的写入和读取在不同的时钟域上应用。 这个小项目的主要目标是实现一个基于Verilog的异步FIFO模块,包括以下功能: 1. 内部缓存的储存和检索 2. 空和满指示器的生成 3. 数据的写入和读取 对于写入操作,当FIFO未满时,它将数据存储在内部缓存中,并更新其指针以指向下一个空位置。当缓存已满时,写入操作将被忽略,并且FIFO满指示器将被设置为高电平。同样,读取操作从内部缓存中检索数据,并将其指针更新以指向下一个位置。当缓存为空时,读操作将被忽略,并且FIFO空指示器将被设置为高电平。 在设计过程中,需要考虑解决的问题包括时序和异步信号的同步。时序问题可以通过FIFO指针和状态机解决,而异步信号可以通过信号同步器进行同步。此外,还需要考虑FIFO的读写顺序和存储器的尺寸,并确保FIFO模块的有效性和可靠性。 总之,通过实现SV异步FIFO项目,学生可以加深对FIFO缓存的理解,并学习基于Verilog的设计和实现。此外,学生还可以通过在项目中遇到的挑战来提高他们的编程和设计技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值