FIFO用法详解(附有代码)

FIFO用法详解(附有代码)

本次讲解以V7芯片为例,主要讲解同步fifo如何使用,以及其中的一些flag的含义和使用方法。

生成IP核

1.首先打开IP Catalog,在查询栏中输入fifo,双击打开FIFO Generator,打开如下所示界面,1中命名规范:尽量写出写、读宽度及其深度,让人一目了然;2中选择native,一般设计都选择这个,这里不详细解释;3中选择同步时钟的RAM,这里的同步时钟和异步时钟表示读写时钟是否同步,一般情况下,读时钟和写时钟一致,或数据没有跨时钟那就选择同步时钟即可,否则选择异步时钟。
在这里插入图片描述
2.在native ports选项中主要区分下图中红框1的选项,前者的读数据相比于读使能延时一个周期,后者(FWFT)的读使能和读数据在时序上同步(这一点在仿真模块进一步说明)。这个在数据通信的发送端关系很大,必须选择后者,才能正确发送数据,在通信过程中的接收端则没关系,选哪个都一样。图中的2红框表示选择FIFO的复位信号,可选读写端同步或异步,如果是同步FIFO可选同步复位,否则应该选择异步复位,且读写端的复位应各自在所在的时钟域中,才能保证不出现亚稳态。高有效或低有效可自选。界面的中间是读位宽写位宽和数据深度设置,数据深度表示这个FIFO能容纳多少个这样位宽的数据。
在这里插入图片描述
3.在status flags界面中主要是设置一些标志位,红框1可设置将满和将空,一般可用可不用,因为用空满信号就可以;红框2表示读出数据有效信号,这个标志位与读出数据同步,有数据读出就有效,否则无效,可用来判断从FIFO中是否有数据读出;红框3表示可编程满和可编程空,即空满的值可由用户设定,比如这里设置了可编程满的值为56,且是常数(还有一种是在代码模块中通过引脚输入),意思是FIFO中有55个数时,就表示满了而不是到64个才满,这能更好的避免数据溢出,可编程空原理一样,这里没有设置。
在这里插入图片描述
4.data counts一般不用设置,用来累计读写数据个数的,与空满信号功能重复,不用也可以。然后点击OK和generate生成IP。。
!
5.打开工程Sources中的IP Sources如下图所示,双击.veo文件,找到ip例化程序端口,便于调用。
在这里插入图片描述
例化程序模块如下:

fifo_64w64d_d64 your_instance_name (
  .clk(clk),              // input wire clk
  .srst(srst),            // input wire srst
  .din(din),              // input wire [63 : 0] din
  .wr_en(wr_en),          // input wire wr_en
  .rd_en(rd_en),          // input wire rd_en
  .dout(dout),            // output wire [63 : 0] dout
  .full(full),            // output wire full
  .empty(empty),          // output wire empty
  .valid(valid),          // output wire valid
  .prog_full(prog_full)  // output wire prog_full
);

例程讲解

本次例程主要目的是教大家如何使用fifo,包括写数据、写使能、读数据、读使能、空信号、满信号等的控制。其中的fifo_din可来自外部,例如从adc端口、ddr3端口、aurora端口等获取的数据;fifo_dout可用于某些通信的发送端口,或直接获取信号进行检验、观察等。在这只是抛砖引玉。
1.在顶层模块中调用IP核例化模块:

`timescale 1ns / 1ps

module fifo_test_top(
	input		clk,
	input		rstn
    );
	
	wire				locked			;
	reg		[7:0]		rst_50m_cnt 	;
	reg					rst_50m 		;
	wire				clk_50m		    ;
		
	wire	[63:0]		fifo_din		;
	wire				fifo_din_ena	;
	wire				fifo_dout_ena	;
	wire	[63:0]		fifo_dout		;
	wire				full			;
	wire				empty			;
	wire				fifo_dout_vad	;
	wire				prog_full		;
	
	//板上时钟转到全局时钟,并分频(mmcm IP核)
	clk_50m u_clk_50m(
		.clk_out1	(clk_50m), 
		.reset		(1'b0	), 
		.locked		(locked	),  
		.clk_in1	(clk	)
	); 
	
	//板上复位同步到clk_50m时钟域
	always@( posedge clk_50m or negedge rstn ) begin 
		if(~rstn) begin 
			rst_50m_cnt <= 8'b0;
			rst_50m 	<= 1'b1;
		end 
		else if(rst_50m_cnt == 8'hff)  begin 
			rst_50m_cnt <= rst_50m_cnt;
			rst_50m 	<= 1'b0;
		end 
		else begin 
			rst_50m_cnt <= rst_50m_cnt + 8'b1;
			rst_50m 	<= 1'b1;
		end 
			
	end 
	//FIFO IP核
	fifo_64w64d_d64 u_fifo_64w64d_d64 (
		.clk		(clk_50m					),
		.srst		(rst_50m					),
		.din		(fifo_din					),
		.wr_en		(fifo_din_ena				),
		.rd_en		(fifo_dout_ena				),
		.dout		(fifo_dout					),
		.full		(full						),
		.empty		(empty						),
		.valid		(fifo_dout_vad				),
		.prog_full	(prog_full					) 
	);
	//FIFO信号发生模块
	fifo_dat_gen u_fifo_dat_gen(
		.clk			(clk_50m				),
		.rst			(rst_50m				),
		.prog_full		(prog_full				),
		.fifo_din		(fifo_din				),
		.fifo_din_ena   (fifo_din_ena   		)
    );
	//FIFO接收信号检验模块
	fifo_dat_che u_fifo_dat_che(
	.clk				(clk_50m				),
	.rst				(rst_50m				),
	.empty				(empty					),
	.fifo_dout_vad		(fifo_dout_vad			),
	.fifo_dout			(fifo_dout				),
	.fifo_dout_ena		(fifo_dout_ena			)
    );
	
endmodule

clk_50m的IP核设置如下:
在这里插入图片描述
在这里插入图片描述
FIFO写入数据生成模块如下:

`timescale 1ns / 1ps

module fifo_dat_gen(
	input			clk,
	input			rst,
	input			prog_full,
	output	[63:0]	fifo_din,
	output			fifo_din_ena
    );
	
	reg		[63:0]	fifo_din;
	reg				fifo_din_ena;
	reg		[63:0]	fifo_din_cnt;
	
	always@( posedge clk or negedge rst ) begin 
		if(rst) begin 
			fifo_din		<= 64'b0;
			fifo_din_cnt	<= 64'b0;
			fifo_din_ena	<= 1'b0;
		end 
		else if(~prog_full)  begin 
			fifo_din		<= fifo_din_cnt;
			fifo_din_cnt	<= fifo_din_cnt + 64'b1;
			fifo_din_ena	<= 1'b1;
		end 
		else begin 
			fifo_din		<= 64'b0;
			fifo_din_cnt	<= fifo_din_cnt;
			fifo_din_ena	<= 1'b0;
		end 			
	end 
endmodule

读数据检验模块如下:

`timescale 1ns / 1ps

module fifo_dat_che(
	input			clk,
	input			rst,
	input			empty,
	input			fifo_dout_vad,
	input	[63:0]	fifo_dout,
	output			fifo_dout_ena
    );
	
(* mark_debug = "true" *)
	reg		[63:0]	fifo_dout_cmp;
(* mark_debug = "true" *)
	reg				err;//数据检验标志位,为1表示FIFO读出数据与valid不同步
	
	assign	fifo_dout_ena = ~empty;
	always@( posedge clk or negedge rst ) begin 
		if(rst) begin 
			fifo_dout_cmp	<= 64'b0;
		end 
		else if(fifo_dout_vad)  begin 
			fifo_dout_cmp	<= fifo_dout_cmp + 64'b1;
		end 
		else begin 
			fifo_dout_cmp		<= fifo_dout_cmp;
		end 
	end 
	
	always@( posedge clk or negedge rst ) begin 
		if(rst) begin 
			err				<= 1'b0;
		end 
		else if(fifo_dout_vad)  begin 
				if(fifo_dout_cmp != fifo_dout) begin 
					err	<= 1'b1;
				end
				else begin 
					err	<= 1'b0;
				end 
		end 
		else begin 
			err	<= err;
		end 
	end 
endmodule

仿真模块如下:

`timescale 1ns / 1ps

module fifo_test_top_tb;
	reg		clk;
	reg		rstn;
	
	initial begin 
			  clk = 0;
	          rstn = 1;
		#100  rstn = 0;
		#500  rstn = 1;
	end 
	
	always #8 clk = ~clk;
	
	fifo_test_top u_fifo_test_top(
		.clk	(clk	),
		.rstn   (rstn   )
    );
	
endmodule

仿真结果如下:
在这里插入图片描述
err的结果显示无误,仿真正确,详细的可以对照着每一个标志位和对应的数据,查看变化过程。

为了更清晰的查看FIFO IP核中的standard fifo 和first word fall through的区别,特截取了信号产生的初始端如下图所示,standard fifo模式的读使能fifo_dout_ena高有效之后的下一个时钟,读数据接口fifo_dout才产生数据;而另一种的读使能和读数据同时产生,这就是区别之处。这个区别在数据通信的时候影响很大,尤其是在不间断的数据发送端必须设置为first word fall through,保证信号立即反应,避免丢失,在接收端没关系(读者可以想想为什么没关系)。
standard fifo仿真信号:
在这里插入图片描述

first word fall through仿真信号:
在这里插入图片描述

  • 14
    点赞
  • 155
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FIFO(First In First Out)算法是一种内存页面置换算法,它的基本思想是把最先进入内存的页面先换出去,即选择最久未使用的页面进行置换。 FIFO算法的实现非常简单,只需要使用一个队列来保存当前在内存中的页面,每当新的页面需要进入内存时,将其加入队列尾部,如果发现内存已满,就将队列头部的页面置换出去。这里需要注意的是,队列中的页面顺序是按照进入内存的顺序排列的,因此最先进入内存的页面会最先被置换出去。 下面是FIFO算法的代码演示: ```python class FIFO: def __init__(self, capacity): self.capacity = capacity # 内存容量 self.page_queue = [] # 页面队列 def page_fault(self, page): if page not in self.page_queue: # 页面不在内存中 if len(self.page_queue) == self.capacity: # 内存已满 self.page_queue.pop(0) # 弹出队列头部的页面 self.page_queue.append(page) # 将新页面加入队列尾部 return True else: return False ``` 在上面的代码中,我们定义了一个FIFO类,它有一个capacity属性表示内存容量,一个page_queue属性表示当前在内存中的页面队列。page_fault方法用于处理页面缺页中断,如果发现页面不在内存中,就将其加入到队列尾部,并返回True表示有缺页中断发生;否则返回False表示没有缺页中断发生。 下面是一个简单的测试代码: ```python fifo = FIFO(3) pages = [1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5] page_fault_count = 0 for page in pages: if fifo.page_fault(page): page_fault_count += 1 print("FIFO Algorithm: {} page faults".format(page_fault_count)) ``` 在上面的代码中,我们定义了一个FIFO对象,内存容量为3,然后将一个页面序列依次加入到FIFO对象中,并统计发生的缺页中断次数。运行结果如下: ``` FIFO Algorithm: 9 page faults ``` 可以看到,在这个页面序列中,FIFO算法一共发生了9次缺页中断。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值