FIFO(原理、框图、代码、深度计算)

Fifo分为同步fifo和异步fifo。同步fifo是指读写时钟是同一个时钟,异步fifo是指读写时钟不是同一个时钟。不管事同步fifo还是异步fifo都能起到数据缓存的作用。Fifo有一个特征:地址是顺序+1的。
1、异步框图

图片来源于《FPGA深度解析》
2、原理:
异步fifo的设计思想:核心是状态信号的产生和跨时钟域的转换及同步
异步fifo如上图所示,主要包含写控制逻辑、写地址、状态产生、读控制逻辑产生、读地址、格雷码同步。其中状态产生分为空信号、将空信号、满信号、将满信号。格雷码同步分为写地址格雷码从写时钟域到读时钟域的同步、读地址格雷码从读时钟域到写时钟域的同步。
(1)格雷码同步
格雷码同步在异步fifo中的作用:用于状态产生。
格雷码实现多比特跨时钟域转换的原理:因为fifo中地址是逐次+1的,而格雷码相邻两位数据一次只有一位数据发生变化。因此,将写地址(读地址)变换成格雷码,虽然地址是多比特的,但是每次变化只有1bit发生变化。这就是将二进制的地址转换成格雷码的好处了。
如果是将写地址变成格雷码,转换完以后再进行垮时钟域到读时钟域去就能最大限度的降低垮时钟域带来的风险(亚稳态)。(敲黑板:先转换成格雷码再跨时钟域)

二进制到格雷码:
二进制右移一位后与原来的二进制按位异或=格雷码
格雷码转二进制:
格雷码的最高位作为二进制的最高位,然后将二进制的最高位和格雷码的次高位异或作为二进制的次高位,依次类推。
(2)空满状态的判断
要判断fifo的状态,就需要知道读写地址。通过判断读写地址的差值来判断状态。其中存在一直特殊情况:读写地址指针指向同一个地址,但是可能是满,也可能是空。
具体分析:因为fifo是回卷式的写和读,这也就是说如果fifo深度为1023,如果写地址在1023,写地址指针会重新回到0地址,如果此时读地址还在地址0,就会存在读写地址都在地址0。而空的时候,读写地址也存在都在0地址的问题。

这就带来了一个问题,当读地址和写地址都在0的时候,可能是空,也可能是满。怎么区分是满和空呢?
那就是将读写地址扩展一位,当读写地址的值相等时,为空;读写地址除最高位不同,其余相同为满。
3、关键部分代码
关键部分的代码也主要来源于《FPGA深度解析》,我最开始不能理解的就是gap计算部分,这部分我附图进行说明了。


//写地址使能
assign wen=wr_en&&(!full);

//写地址二进制到格雷码的转换
always@(posedge wr_clk or negedge wr_reset)
	if(wr_reset)
		waddr_gray<={(ADDR_WIDTH+1){1'b0}};
	else waddr_gray<=waddr^{1'b0,[waddr[ADDR_WIDTH:1]]};//相当于右移一位后与原来的二进制异或
	
//读地址格雷码转换为二进制码
always@(*)
		begin
			raddr_gray2bin={raddr_gray_sync_d[4],
			raddr_gray_sync_d[4]^raddr_gray_sync_d[3],
			raddr_gray_sync_d[4]^raddr_gray_sync_d[3]^raddr_gray_sync_d[2],
			raddr_gray_sync_d[4]^raddr_gray_sync_d[3]^raddr_gray_sync_d[2]^raddr_gray_sync_d[1],
			raddr_gray_sync_d[4]^raddr_gray_sync_d[3]^raddr_gray_sync_d[2]^raddr_gray_sync_d[1]^raddr_gray_sync_d[0]
			};
	
		End



这个图片可以帮助理解rd_gap和wr_gap计算的原因:

/状态生成/
//写指针与读指针间隔计算,在写时钟域的情况,判断满信号full和将满信号almost full的产生
always@(*)//地址宽度为4bit,扩展一位后为5bit
	begin
		if(waddr[4]^raddr_gray2bin[4])//相同为0,相异为1;需要判断还有多少空格,看看啥时候写满
			wr_gap=raddr_gray2bin[3:0]-waddr[3:0];//最高位不相同的情况
		else 
			wr_gap=FIFO_DEEP+raddr_gray2bin-waddr;//最高位相同的情况
			
	end
//almost_full信号的产生
always@(posedge wr_clk or wr_reset)
	begin
		if(wr_reset)
			almost_full<=1'b0;
		else if(wr_gap<ALMOST_FULL_GAP)//空格子比规定的格子少了
			almost_full<=1'b1;
		else almost_full<=1'b0;
	
	end
	
	//full信号的产生
always@(posedge wr_clk or wr_reset)
	begin
		if(wr_reset)
			full<=1'b0;
		else if(wr_gap==1&&wen)
			full<=1'b1;
		else full<=1'b0;
		
	end
	
	
	
//读指针和写指针的间隔,在读时钟域,读空,计算的是还有几个格子不是空的
always@(posedge rd_clk or negedge rd_reset)
begin
	if(rd_reset)
		ra_gap<=0;
	else ra_gap<=waddr_gray2bin-raddr;
	


end

//almost_empty信号的产生
always@(posedge rd_clk or negedge rd_reset)
begin
	if(rd_reset)
		almost_empty<=0;
	else if(ra_gap<ALMOST_EMPTY_GAP)//
		almost_empty<=1;
	else almost_empty<=0;
		
end
//empty信号的产生
always@(posedge rd_clk or negedge rd_reset)
begin
	if(rd_reset)
		empty<=0;
	else if(rd_en&&rd_gap==1)
		empty<=1;
	else empty<=0;

4、Fifo深度
Fifo的最小深度是指写入数据的个数减去读出数据后得到的fifo需要暂存的数据个数。
讨论fifo深度有一个隐含的条件:fifo写和读的吞吐量要相同。

每X个时钟读出Y个数据。

FIFO深度可以去看《FPGA深度解析》上面详细有具体例子讲解fifo深度的计算。

全部评论

相关推荐

搜索部&nbsp;首先说下timeline8.18,投递8.19,约一面8.21,晚上一面call约二面8.22,上午二面下午oc周末等待(8.23,8.24)8.25,offer一年前,我还是懵懵懂懂,高考完的暑假,只会提前学学高数,未来的画像是什么?我或许无法预测。开学后,自学Python,接单,无数个客户的ddl,偷偷摸摸一个人找自习的地方,这一步步竟然为后来的我,搭建工程能力的基础。大一上,我也要感谢我的第一位老板,让我接触到了实习,师兄带着我一步步入门,看他们写的飞书文档。大一下,导师带我参与企业项目,这让我渐渐发现,应该去实践,增长见识,而非局限当下,盯着自己的小新pro。不久后,第一波投递开始,结果当然是约面极少。盯着简历上的文字和ssob,我开始思考,确实很多可以去提升。带着些许不甘心,继续沉淀,慢慢的约面也越来越多,有的时候两天7场,准备完就接着下一个日程。这一次,也许是刚好到位吧,比较match,面试答的流利,关关难关关过,成为度孝子展望未来,依然是重重挑战,果然只有收到offer的那一刻是开心的。愿在百度星海拆解的每一段代码,都能成为丈量宇宙的诗行;此志终赴星河,而今迈步重铸天阶。屏幕前的你们,在无数个向星海奔赴的日夜,一定一定,会在未来化作群星回响的征程——请永远相信此刻埋首耕耘的自己!!!
一天三顿半:???百度提前批发 offer了?不是统一和正式批排序完再发吗我靠
百度求职进展汇总
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务