【小月电子】ALTERA FPGA开发板系统学习教程-LESSON12 IPCORE核之FIFO详细教程

ALTERA FPGA IPCORE核之FIFO详细教程

若要观看该博客配套的视频教程,可点击此链接

一. FIFO简介

FIFO: 是英文first in first out的缩写,即先进先出,指的是对数据的存储具有先进先出特性的缓存器。从字面意思上就可以大致看出和RAM和ROM的区别,即没有地址线,无法像RAM和ROM一样写入或读出指定地址的数据,而必须按顺序读出。
根据读写操作是否使用同一个时钟,可以将FIFO分为两类:

  • 同步FIFO

    读写操作使用同一个时钟,一般用于数据缓存

  • 异步FIFO

    读写操作使用不同的时钟,一般用于跨时钟域处理,比如我们在做视频相关项目时,假如我们的摄像头的像素时钟是25MHZ,SDRAM的读写时钟是100MHZ,那我们要把采集到的视频数据写入SDRAM,那么就必须要用到异步FIFO,进行跨时钟域处理。还有一种应用场景,读写数据的位宽不一致时,比如写入的数据是16位,读出的数据需要8位,这时候使用异步FIFO,只需要分别选择写数据位宽和读数据位宽,非常方便,值得注意的是QuartusII中的同步FIFO,读数据位宽是无法进行更改,默认和写数据位宽一致。

二. FIFO IPCORE生成步骤及参数介绍

不同公司的FPGA,生成的FIFO大同小异,本篇我们以一个实例来对ALTERA的IPCORE来进行介绍。我们要生成一个写数据位宽8,读数据位宽16的异步FIFO,利用Modelsim仿真来观察FIFO的时序波形。

2.1 首先打开QuartusII软件,新建一个工程,命令为async_fifo_test

新建QuartusII工程的步骤就不一一说明,为了方便上板验证,选用我们开发板上的器件:EP4CE6F17C8

2.2 FIFO IPCORE配置
2.2.1 生成IPCORE,命名为async_fifo_w8r16_d1024
我们在对IPCORE命名时,最好能体现出该IPCORE的一些主要特性,比如我们上面的命令,我们知道是一个异步FIFO,写数据位宽8,读数据位宽16,深度1024。说到这,就有必要说一下非对称读写位宽。读写数据的位宽可以不一致,但是必须满足比例关系:1:8,1:4,1:2,1:1,那么读写位宽不一致,数据的排序关系是怎么样的呢?我们分两种情况做一下说明:

  1. 写位宽大于读位宽,直截了当我做了一个简单的测试程序仿真出的波形如下:
    在这里插入图片描述

    通过仿真可以看出,写入16’h0102,先读出的是8’h02,接着读出的是8’h01,是不是和我们想的不一样,所以这个地方一定要注意噢

  2. 写位宽小于读位宽,直截了当我做了一个简单的测试程序仿真出的波形如下:
    在这里插入图片描述

    通过仿真可以看出,写入8’h01,8’h02两个数,读出的是16’h0201,是不是和我们想的不一样,所以这个地方一定要注意噢
    2.2.2 生成FIFO的步骤如下图所示:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

当我们生成好后可以看到左边FIFO框图上显示了FIFO的输入输出接口,左下角是FIFO使用的FPGA内部资源。

2.2.2 FIFO各接口定义如下:

1. wrfull:选用写时钟域,写满是指写得快读得慢,FIFO里面的存储数据超过了FIFO的深度,如果这时候再继续写,数据就会溢出丢失,所以这时需要禁止再往FIFO 中写入数据,防止数据溢出丢失。高电平表示FIFO写入数据量达到 FIFO 设置的最大空间
2. rdempty:选用读时钟域,高电平表示 FIFO 中已经没有数据了,此时应该通过该信号控制读请求信号(也称为读使能信号),禁止FIFO 继续再读出数据,否则读出的将是无效数据。
3. rdusedw:为FIFO里面存存储的数据个数。在某些应用场景下,我们需要用到usedw时钟监测FIFO存储的数据个数,但是需要注意,同步FIFO的数据计数是准确的,因为读写时钟相同,不需要做跨时钟域处理;但是异步FIFO的计数就不准确了,只能粗略的进行判断,比如半空,半满等。
4. wrreq:写使能,高电平有效
5. wrclk:写时钟
6. data:写数据,位宽8
7. rdreq:读使能,高电平有效
8. rdclk:读时钟
9. aclr:异步复位信号,用于清空 FIFO
10. almost full:几乎满标志信号,我们可以控制 FIFO 快要被写满的时候和 full 信号的作用一样。
11. almost empty:几乎空标志信号,我们可以控制 FIFO 快要被读空的时候和 empty 信号的作用一样。
12. Synchronous clear:同步复位信号,用于清空 FIFO。
10~12的信号,本例程的FIFO没有生成,大家可根据具体需求选择是否生成这些信号。

三. Verilog代码设计

	`timescale 1ns / 100ps
    module async_fifo_test(
    	input	clk			,//50MHZ
    	input	rst_n		,
    	output	[15:0]	dout
    	);
    	reg	[ 7:0]	fifo_wdata	;
    	reg			fifo_wren	;
    	reg			fifo_rden	;
    	wire[15:0]	fifo_rdata	;
    	wire		fifo_wclk	;
    	wire		fifo_rclk	;
    	wire		locked		;
    	reg	[9:0]	wr_cnt		;
    	reg	[8:0]	rd_cnt		;
    	assign	dout=fifo_rdata	;
    	//注意需要在fifo_wclk时钟域下,因为fifo写使能和写数据都是在该计数器(wr_cnt)下生成
    	always@(posedge fifo_wclk or negedge locked)begin
    		if(!locked)
    			wr_cnt<=0;
    		else 
    			wr_cnt<=wr_cnt+1;
    	end
    	//注意需要在fifo_rclk时钟域下,因为fifo读使能是在该计数器(rd_cnt)下生成
    	always@(posedge fifo_rclk or negedge locked)begin
    		if(!locked)
    			rd_cnt<=0;
    		else 
    			rd_cnt<=rd_cnt+1;
    	end
    	//在fifo_wclk时钟域下生成FIFO写数据和写使能,位宽8位,写100个数据
    	always@(posedge fifo_wclk or negedge locked)begin
    		if(!locked)begin
    			fifo_wren<=0;
    			fifo_wdata<=0;
    		end else if(wr_cnt>0&&wr_cnt<=100)begin
    			fifo_wren<=1;
    			fifo_wdata<=fifo_wdata+1;
    		end else begin
    			fifo_wren<=0;
    		end
    	end
    	//在fifo_rclk时钟域下生成FIFO读使能,读数据的位宽是16位,所以读50个数据就将FIFo读空
    	always@(posedge fifo_rclk or negedge locked)begin
    		if(!locked)
    			fifo_rden<=0;
    		else if(rd_cnt>100&&rd_cnt<=150)
    			fifo_rden<=1;
    		else
    			fifo_rden<=0;
    	end
    	//利用PLL生成FIFO的读写时钟,写时钟25MHZ,读时钟50MHZ
    	pll Upll(
    	.areset		(~rst_n		),
    	.inclk0		(clk		),
    	.c0			(fifo_wclk	),
    	.c1			(fifo_rclk	),
    	.locked 	(locked		)
    	);
    	//例化FIFO IPCORE
    	async_fifo_w8r16_d1024 Uasync_fifo_w8r16_d1024(
    	.aclr		(~rst_n		),//复位,高电平复位
    	.data		(fifo_wdata	),//写数据
    	.rdclk		(fifo_rclk	),//读时钟
    	.rdreq		(fifo_rden	),//读使能
    	.wrclk		(fifo_wclk	),//写时钟
    	.wrreq		(fifo_wren	),//写使能
    	.q			(fifo_rdata	),//读数据
    	.rdempty	(),//读空标志
    	.rdusedw	(),//在读时钟域下,FIFO中当前存储的数据个数,数据位宽16位
    	.wrfull ()//写满标志
    	);
    endmodule

四. Verilog测试代码设计

    `timescale 1ns / 100ps
    module async_fifo_test_tb;
    	reg					clk			=1;
    	reg					rst_n		=0;
    initial
    	begin
    		#1000
    		rst_n=1;
    	end
    //生成激励时钟
    always #10 clk<=~clk;
    //例化被测试模块
    async_fifo_test Uasync_fifo_test(
    	.clk	(clk	),//50MHZ
    	.rst_n	(rst_n	),
    	.dout   (		)
    	);
    endmodule

五. 仿真波形分析

在这里插入图片描述
1.aclr :fifo复位信号,高电平复位
2.wrclk :fifo写时钟
3.wrreq :fifo写使能,高电平时表示写入数据。
4.rdclk :fifO读时钟
5.rdreq :fifo读使能,高电平表示读数据,由于我们选择是正常模式,所以在rdreq有效时,会延时一个时钟周期才会出有效数据。
6.q:fifo读数据
7.rdempty:空标志,高电平表示fifo为空,在仿真波形中可以看出在fifo复位时且未写入数据时,rdempty为高电平,当前fifo为空。
8.rdusedw:FIFO里面存存储的数据个数,由于我们用的是异步fifO,这个数据并不能精确的反应fifo里面的数据个数,只能做一个参考。通过上面的仿真图也可以看出,rdusedw并没有精确的反应fifo中的数据个数。
9.wrfull:满标志,当fifo中存储的数据个数超过fifo自身的深度时,便会溢出,wrful置高。
通过上面的仿真图,我们可以看到wrfull一直为低,所以fifo数据未溢出,不会造成数据丢失。同时,fifo在进行读操作时,rdempty一直为低,说明在读数据时,fifo中一直有数据,不会读出无效数据。一般来说,只要fifo操作满足以上两个条件,便可进行正常的数据写入和读取。

如果大家想要该工程的源码和仿真测试激励文件用来学习,可以直接联系工程师,谢谢大家的阅读!

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值