FIFO IP核的使用及一种工程应用案例介绍

1 篇文章 0 订阅
1 篇文章 0 订阅

引言
在数字设计中,利用FIFO进行数据处理是非常普遍的应用,例如,实现时钟域交叉、低延时存储器缓存、总线位宽调整等。下图给出了FIFO生成器支持的一种可能配置。
在这里插入图片描述设计中有两个独立的时钟域并且读数据总线的位宽是写数据总线位宽的2倍。使用FIFO生成器可以快速实现这种配置,从而在Xilinx FPGA芯片上实现特定的设计要求。
实际应用案例:本案例背景是将信号处理系统中ADC采集到的数据写入FPGA芯片外挂的DDR3,完成采样数据的存储。ADC采样率设定为96Mhz,两个采样点(两个16bit数据拼接成一个32bit)为单位,DDR读写时钟速率为150Mhz,总线数据位宽64bit,二者时钟域、位宽均不同,故需在中间加入一级FIFO,从而实现时钟域的交叉以及总线位宽的调整。
下面将从FIFO IP核的创建,模块程序编写,功能仿真验证等三个方面完成本案例的介绍:
1)FIFO IP核的创建:打开Vivado软件(本例程基于Vivado 2018.3版本)IP catalog一栏,输入FIFO,双击进入如下界面,第一个Basic选项卡主要是设置FIFO接口类型,可设置为正常的Native模式或AXI总线接口,一般我们选择Native即可。然后选择FIFO实现的类型:读写使用独立时钟还是同一时钟,实现时使用分布式RAM、Block RAM还是专用的FIFO等等,这里我们选择Independent Clocks Block RAM,即独立时钟块RAM的FIFO。
在这里插入图片描述切换至第二个Native Ports选项卡,这个界面主要是设置读写数据位宽、深度以及一些端口的使能、端口复位值等的设置。结合本案例的应用,设置写位宽为32bit,深度设置为1024,读位宽设置为64bit。使能复位管脚,设置满信号(Full Flags)的复位值为0,读数据(Dout)复位值为0。
在这里插入图片描述然后切换至第三个Status Flags选项卡,本选项卡是设置其余一些可选的标志信号,本案例需使用本界面下的Programmable Flags,即可编程的标志信号,设置满标志门限置位值(Full Threshold Assert Value),可使FIFO写入的数据总数大于等于该值后将prog_full(可编程满标志信号)拉高,相比full信号使用起来更灵活。DDR读写采用Burst方式(突发传输),一次连续写入256个数,这里设置Full Threshold Assert Value为512(256*2,2是FIFO读写位宽的比值),当FIFO写入512个数后,prog_full拉高,进行FIFO读操作,一次连续读256个64bit的数(对应写的512个32bit数)存入DDR。
在这里插入图片描述切换至第四个Data Counts选项卡,本选项卡主要是选择是否使用读写数据计数,本案例不使用计数,此页面保持默认设置。
在这里插入图片描述最后Summary选项卡是FIFO设置后的各项信息,可核对FIFO设置是否正确及设计是否满足要求。
在这里插入图片描述2)模块程序的编写
顶层模块:FIFO_test.v

module FIFO_test(
  input  rst,
  input  wr_clk,
  input  rd_clk,
  input  [31:0]  din,
  input  wr_en,
  input  rd_en,
  output [63:0]  dout,
  output full,
  output empty,
  output prog_full,
  output wr_rst_busy,
  output rd_rst_busy
    );
	
  fifo_generator_0 U_fifo (
    .rst(rst),                  // input wire rst
    .wr_clk(wr_clk),            // input wire wr_clk
    .rd_clk(rd_clk),            // input wire rd_clk
    .din(din),                  // input wire [31 : 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
    .prog_full(prog_full),      // output wire prog_full
    .wr_rst_busy(wr_rst_busy),  // output wire wr_rst_busy
    .rd_rst_busy(rd_rst_busy)  // output wire rd_rst_busy
  );
  
endmodule

TestBench模块:FIFO_sim

module FIFO_sim;

  reg  rst;
  reg  wr_clk;
  reg  rd_clk;
  reg  [31:0]  din;
  reg  wr_en;
  reg  rd_en;
  wire [63:0]  dout;
  wire full;
  wire empty;
  wire prog_full;
  wire wr_rst_busy;
  wire rd_rst_busy;
  
  initial begin
    rst = 1;
	wr_clk = 0;
	wr_en = 0;
	rd_clk = 0;
	rd_en = 0;
	din = 0;
	#1000
	rst = 0;
  end
  
  always #10.4167 wr_clk = ~wr_clk;
  always #3.3333  rd_clk = ~rd_clk;
  
  always @(posedge wr_clk) begin
    if(!wr_rst_busy && !rst) begin
      wr_en <= 1'b1;
	  din <= din + 1'b1;
	end
  end
  
  reg [1:0] RD_state = 2'b01;
  reg [15:0] rd_count = 'd0;
  
  always @(posedge rd_clk) begin
	case(RD_state)
		2'b01: begin
				  if(!rd_rst_busy && prog_full) RD_state <= 2'b10;
	            end
	
		2'b10: begin
				  if(rd_count >= 'd256) begin
				    RD_state <= 2'b01;
					rd_count <= 'd0;
					rd_en <= 1'b0;
				  end
				  else begin
					rd_count <= rd_count + 1'b1;
					rd_en <= 1'b1;			  
				  end
	            end
				
	   default: begin 
				  RD_state <= 2'b01;
				end
			 
	endcase
  end
  
  FIFO_test  U_FIFO_test(
    .rst(rst),
    .wr_clk(wr_clk),
    .rd_clk(rd_clk),
    .din(din),
    .wr_en(wr_en),
    .rd_en(rd_en),
    .dout(dout),
    .full(full),
    .empty(empty),
    .prog_full(prog_full),
    .wr_rst_busy(wr_rst_busy),
    .rd_rst_busy(rd_rst_busy)
  );
	
endmodule

编写TestBench时,写时钟为48Mhz,读时钟为150MHz。写是连续的,使能一直打开,表示AD是一直连续工作的,写入够512个数后,prog_full拉高,进行一次FIFO读操作,连续读出256个数,然后等待下一次prog_full为高的到来,如此周而复始。
3)波形功能仿真
点击Run simulation,启动功能仿真,可以看到FIFO一开始复位结束后,进行写操作,每写够512个数后,prog_full拉高,进行一次读操作,连续读出256个数后,停止读操作,等待下一次prog_full拉高时刻的到来。将读出的数据和写入的数据对比,完全一致,不存在丢数的情况,因此验证了功能的正确性。
在这里插入图片描述总结:通过本案例代码程序的编写以及波形功能仿真,可以熟悉并掌握FIFO的基本功能和常用用法:数据跨时钟域及总线位宽调整。本例程是我自己在一个项目中用到的,结合自己的需求进行编写的,并不具有普适性,写此博客的初衷也是让一些不熟悉FIFO用法的读者能快速入门,可能并不能直接帮助到所有的读者。希望大家可以在此基础上,结合自己的工程应用实例,完成自己相应的设计。

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值