异步FIFO的设计.docx
《异步FIFO的设计.docx》由会员分享,可在线阅读,更多相关《异步FIFO的设计.docx(18页珍藏版)》请在冰点文库上搜索。
异步FIFO的设计
目录
题目要求…………………………………………………………………………………1
实验内容…………………………………………………………………………………1
设计工具…………………………………………………………………………………………....….1
1Quartus2.8…………………………………………………………………………………....….1
1.1Quartus28.的介绍….……………………………………………...……………….……1
1.2Quartus28.的操作流程…………………..………………………………..………….…3
2Modelsim6.0……………………………………………………………………………….…….5
功能设计实现…………………………………………………………………………………..………7
3.1异步FIFO简介…………………..…………………………………………………………..…..7
3.2FIFO的参数…………………..……………………………………………………………..…...8
3.3FIFO的设计原理…………………..………………………………………………………..…...8
3.4FIFO的verlog源码…………………..…………………………………………………………..14
3.5用modelsim仿真FIFO…………………..……………………………………………………...19
结果分析与结论......................................................22
仿真波形…………………..…………………………………………………………………….…..22
仿真结果…………………..…………………………………………………………………….…..23
题目要求:
此异步FIFO的RAM大小为32*8 。
由写使能端控制该数据流的写入FIFO,并由读使能控制FIFO中数据的读出。
写入和读出的操作由时钟的上升沿触发。
当FIFO的数据满和空的时候分别设置相应的高电平加以指示,读和写的时钟域不相同。
实验内容:
1、设计工具
1.Quartus2.8
1、1Quartus28.0的介绍
Max+plus II 作为Altera的上一代PLD设计软件,由于其出色的易用性而得到了广泛的应用。
目前Altera已经停止了对Max+plus II 的更新支持。
Quartus II 是Altera公司继Max+plus II之后开发的一种针对其公司生产的系列CPLD/PGFA器件的综合性开发软件,它的版本不断升级,从4.0版到10.0版,这里介绍的是Quartus II 8.0版,该软件有如下几个显著的特点:
1、1Quartus II 的优点
该软件界面友好,使用便捷,功能强大,是一个完全集成化的可编程逻辑设计环境,是先进的EDA工具软件。
该软件具有开放性、与结构无关、多平台、完全集成化、丰富的设计库、模块化工具等特点,支持原理图、VerilogHDL以及AHDL(Altera Hardware Description Language)等多种设计输入形式,内嵌自有的综合器以及仿真器,可以完成从设计输入到硬件配置的完整PLD设计流程。
Quartus II可以在XP、Linux以及Unix上使用,除了可以使用Tcl脚本完成设计流程外,提供了完善的用户图形界面设计方式。
具有运行速度快,界面统一,功能集中,易学易用等特点。
1、2Quartus II对器件的支持
Quartus II支持Altera公司的MAX 3000A系列、MAX 7000系列、MAX 9000系列、ACEX 1K系列、APEX 20K系列、APEX II系列、FLEX 6000系列、FLEX 10K系列,支持MAX7000/MAX3000等乘积项器件。
支持MAX II CPLD系列、Cyclone系列、Cyclone II、Stratix II系列、Stratix GX系列等。
支持IP核,包含了LPM/MegaFunction宏功能模块库,用户可以充分利用成熟的模块,简化了设计的复杂性、加快了设计速度。
此外,Quartus II 通过和DSP Builder工具与Matlab/Simulink相结合,可以方便地实现各种DSP应用系统;支持Altera的片上可编程系统(SOPC)开发,集系统级设计、嵌入式软件开发、可编程逻辑设计于一体,是一种综合性的开发平台。
3、Quartus II对第三方EDA工具的支持
对第三方EDA工具的良好支持也使用户可以在设计流程的各个阶段使用熟悉的第三放EDA工具。
Altera的Quartus II可编程逻辑软件属于第四代PLD开发平台。
该平台支持一个工作组环境下的设计要求,其中包括支持基于Internet的协作设计。
Quartus平台与Cadence、ExemplarLogic、 MentorGraphics、Synopsys和Synplicity等EDA供应商的开发工具相兼容。
改进了软件的LogicLock模块设计功能,增添 了FastFit编译选项,推进了网络编辑性能,而且提升了调试能力.
1.3操作流程
(1)建立工程
1、在windows桌面上选择quartus||8.0图标,双击打开。
2、选择File→New Project Wizard 新建一项工程。
新建工程向导说明对话框如图所示
QuartusⅡ基本操作流程
一、 打开QuartusⅡ软件并建立工程
1、在Windows桌面上选择“开始”→“程序”→Altera→QuartusⅡ9.0,打开QuartusⅡ9.0软件。
2、选择File→New Project Wizard 新建一项工程。
3、单击Next进入下图所示对话框。
任何一项设计都是一项工程Project,必须首先为此工程建立一个放置与此工程相关的所有文件的文件夹,此文件夹将被QuartusⅡ默认为工作库(Work Library)。
注意文件夹不能用汉字,不要将文件夹设在安装目录中。
4、单击Next进入图示对话框。
由于是新建工程,暂无输入文件。
5、单击Next进入图示对话框。
在该对话框中指定目标器件
6、单击Next进入图示对话框。
本实验利用QuartusⅡ的集成环境进行开发,不使用任何EDA工具,因此这里不做任何改动。
7、单击Next进入图示对话框。
从该对话框中,可以看到工程文件配置信息报告。
单击Finish,完成新建工程的建立。
需要注意的是,建立工程后,还可以根据设计中的实践情况对工程进行重新设置,可选择Assignments→Settings进行设置。
(2)新建文本设计文件
1、在QuartusⅡ主界面中,选择File→New打开如图所示的对话框。
2、选择verilogHDLFile,即建立了文本输入文件
3、在文件中编写verilog程序,并保存在工程下
(3)编译文件
在QuartusⅡ主界面下选择Processing→Start Compilation进行全程编译,若在编译过程中发现错误,则造出并更正错误,直至编译成功为止。
在编译硬件系统时,状态窗口显示整个编译进程及每个编译阶段所用时间。
编译结果显示在Compilaation Report窗口中。
2、modelsim6.0介绍
Modelsim仿真工具是Model公司开发的。
它支持Verilog、VHDL以及他们的混合仿真,它可以将整个程序分步执行,使设计者直接看到他的程序下一步要执行的语句,而且在程序执行的任何步骤任何时刻都可以查看任意变量的当前值,可以在Dataflow窗口查看某一单元或模块的输入输出的连续变化等,比quartus自带的仿真器功能强大的多,是目前业界最通用的仿真器之一。
ModelSim为HDL仿真工具,我们可以利用该软件来实现对所设计的VHDL或Verilog程序进行仿真,支持IEEE常见的各种硬件描述语言标准。
可以进行两种语言的混合仿真,但推荐大家只对一种语言仿真。
ModelSim常见的版本分为ModelSim XE和ModelSim SE两种,ModelSim版本更新很快,目前最新版本为5.8版本,该版本支持VHDL的2002标准以及Verilog的2001标准,此外,在该版本的Linux、HP和SUN工作站等平台支持VHDL、Verilog和SystemC的混合仿真,但在Windows平台上不支持SystemC的仿真。
1、Modelsim仿真方法
Modelsim的仿真分为前仿真和后仿真,下面先具体介绍一下两者的区别。
1) 前仿真
前仿真也称为功能仿真,主旨在于验证电路的功能是否符合设计要求,其特点是不考虑电路门延迟与线延迟,主要是验证电路与理想情况是否一致。
可综合FPGA代码是用RTL级代码语言描述的,其输入为RTL级代码与Testbench.
2) 后仿真
后仿真也称为时序仿真或者布局布线后仿真,是指电路已经映射到特定的工艺环境以后,综合考虑电路的路径延迟与门延迟的影响,验证电路能否在一定时序条件下满足设计构想的过程,是否存在时序违规。
其输入文件为从布局布线结果中抽象出来的门级网表、Testbench和扩展名为SDO或SDF的标准时延文件。
SDO或SDF的标准时延文件不仅包含门延迟,还包括实际布线延迟,能较好地反映芯片的实际工作情况。
一般来说后仿真是必选的,检查设计时序与实际的FPGA运行情况是否一致,确保设计的可靠性和稳定性。
2、 Modelsim仿真的基本步骤
Modelsim的仿真主要有以下几个步骤:
建立库并映射库到物理目录;编译原代码(包括Testbench;执行仿真。
1) 建立工程
2)编写Verilog代码,生成.v文件。
3)编写测试代码
4)编译仿真,生成时序图.
二、功能设计实现
3.1异步FIFO简介
FIFO是英文FirstInFirstOut的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
根均FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。
同步FIFO是指读时钟和写时钟为同一个时钟。
在时钟沿来临时同时发生读写操作。
异步FIFO是指读写时钟不一致,读写时钟是互相独立的。
异步FIFO(AsynchronousFIFO),一般用于不同时钟域之间的数据传输,比如FIFO的一端连接频率较低的AD数据采样信号,另一端与计算机的频率较高的PCI总线相连。
另外,对于不同宽度的数据接口也可以用AFIFO,例如单片机为8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用AFIFO来达到数据匹配的目的。
由于实际中,异步FIFO比较常见。
为了便于描述,在后面的章节中将异步FIFO简称为FIFO.
3.2FIFO的参数
FIFO的宽度:
进行一次读写操作的数据的位宽。
FIFO的深度:
双口存储器中能容纳的数据的总数。
满标志:
FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出。
空标志:
FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出。
读时钟:
读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:
写操作所遵循的时钟,在每个时钟沿来临时写数据。
读指针:
指向下一个读出地址。
读完后自动加1。
写指针:
指向下一个要写入的地址的,写完自动加1。
读写指针其实就是读写memory的地址,只不过这个地址不能任意选择,而是连续的。
3.3FIFO的设计原理
整体的框图如下:
图1.1FIFO的整体电路图
3.3.1FIFO的读写指针
FIFO可以看成是先进新出的缓冲区,它不像普通的存储器那样,有专门的地址信号。
它只能根据地址,顺序地读写缓冲区。
所以需要有两个读写指针。
这里定义如下:
wptr:
写数据的指针
rptr:
读数据的指针
每读/写完一个数据,读/写指针就会加1,指向下一个待读/写的位置。
3.3.2同步器的设计
为了产生空/满标志,需要对2个读/写指针进行比较。
由于FIFO的读/写时钟信号,来自2个不同的时钟域,所以先要将这2个指针同步到一个时钟域。
这里采用两级D触发器级联来构成同步器。
3.3.3格雷码计数器
采用二进制码对地址指针进行计数时,从一个计数值变到下一个计数值时,可能有多位发生跳变,如从78变化时,低位由01111000,这样同步器在采样数据时,可能会发生错误。
由于采用格雷码计数时,每次只有1位发生跳变,这样使亚稳态发生错误的可能性大大减小了。
3.3.4空标志的产生
由于读/写指针,总是指向FIFO的memory中下一个要读/写的位置。
只有在读/写复位的时候,读/写指针才回到0位置。
复位后,随着数据的读出/写入,读/写指针指向的地址逐渐增加。
如果读的速度比较快,当读指针赶上写指针,即读指针与写指针指向同一个位置时,输出的空标志有效。
如下图所示:
图1.2FIFO的空/满标志
3.3.5满标志的产生
满标志的产生,基于这样的原理:
即“写指针比空指针多绕了一圈”后,又指向了空指针所指向的位置。
由上可知,空标志的产生,也是由于读/写指针指向了同一位置。
那怎么来区分,当读/写指针指向同一位置时,FIFO是满,还是空呢?
这里,采用增加一位地址位的方法,来区分满标志和空标志。
假设FIFO的深度为16,那么采用5位的读/写地址指针。
地址的低4位,用来对寻址memory,读/写指针的最高位用来判断FIFO为空还是为满。
当读/写指针的低4位相同时,如果最高位也相同,那么空标志有效,否则满标志有效。
由于格雷码具有一个特性:
关于中间的计数值对称。
如果从格雷码的中间划开,把它分成2段。
分别从上往下看,会发现在对应的位置,只有最高的2位是完全相反,而其余的低位部分则是相同的。
因此,当读/写指针的最高2位完全相反,而其余的低位完全相同时,满标志有效(“读指针比写指针多绕了一圈”)。
具体如下图所示:
图1.3格雷码的对称特性
3.3.6格雷码计数器
如果读/写数据的使能信号(rinc/winc)有效,在下一个读/写时钟的上升沿到来时,会从(对)memory读出/写入一个数据,并且相应的读/写指针会加1。
由于习惯上用二进制码来寻址memory,而且用二进制码能很方便地进行累积操作,所以这里以二进制码为主,并将二进制码转换为格雷码,以比较读/写指针来产生空/满标志位。
二进制码可以通过以下方式转换成格雷码:
gray=(bin>>1)^bin
其中,gray表示格雷码,bin表示二进制码。
如,设一个5位的二进制码为B[4:
0],它对应的格雷码为G[4:
0],则
G[4]=B[4]
G[3]=B[3]^B[3]
G[2]=B[2]^B[2]
G[1]=B[1]^B[1]
G[0]=B[0]^B[0]
具体如下图所示:
图1.4比较指针和寻址指针的产生电路
3.4FIFO的verlog源码
modulefifo1(rdata,wfull,rempty,wdata,winc,wclk,wrst_n,rinc,rclk,rrst_n);
parameterDSIZE=32;
parameterASIZE=8;
output[DSIZE-1:
0]rdata;
outputwfull;
outputrempty;
input[DSIZE-1:
0]wdata;
inputwinc,wclk,wrst_n;
inputrinc,rclk,rrst_n;
regwfull,rempty;
reg[ASIZE:
0]wptr,rptr,wq2_rptr,rq2_wptr,wq1_rptr,rq1_wptr;
reg[ASIZE:
0]rbin,wbin;
reg[DSIZE-1:
0]mem[0:
(1<wire[ASIZE-1:
0]waddr,raddr;
wire[ASIZE:
0]rgraynext,rbinnext,wgraynext,wbinnext;
wirerempty_val,wfull_val;
//-----------------Ë«¿ÚRAM´æ´¢Æ÷--------------------
assignrdata=mem[raddr];
always@(posedgewclk)
if(winc&&!
wfull)mem[waddr]<=wdata;
//-------------ͬ²½rptrÖ¸Õë-------------------------
always@(posedgewclkornegedgewrst_n)
if(!
wrst_n){wq2_rptr,wq1_rptr}<=0;
else{wq2_rptr,wq1_rptr}<={wq1_rptr,rptr};
//-------------ͬ²½wptrÖ¸Õë---------------------------
always@(posedgerclkornegedgerrst_n)
if(!
rrst_n){rq2_wptr,rq1_wptr}<=0;
else{rq2_wptr,rq1_wptr}<={rq1_wptr,wptr};
//-------------rempty²úÉúÓëraddr²úÉú-------------------
//-------------------
//GRAYSTYLE2pointer
//-------------------
always@(posedgerclkornegedgerrst_n)
begin
if(!
rrst_n){rbin,rptr}<=0;
else{rbin,rptr}<={rbinnext,rgraynext};
end
//Memoryread-addresspointer(okaytousebinarytoaddressmemory)
assignraddr=rbin[ASIZE-1:
0];
assignrbinnext=rbin+(rinc&~rempty);
assignrgraynext=(rbinnext>>1)^rbinnext;
//---------------------------------------------------------------
//FIFOemptywhenthenextrptr==synchronizedwptroronreset
//---------------------------------------------------------------
assignrempty_val=(rgraynext==rq2_wptr);
always@(posedgerclkornegedgerrst_n)
begin
if(!
rrst_n)rempty<=1'b1;
elserempty<=rempty_val;
end
//---------------wfull²úÉúÓëwaddr²úÉú------------------------------
//GRAYSTYLE2pointer
always@(posedgewclkornegedgewrst_n)
if(!
wrst_n){wbin,wptr}<=0;
else{wbin,wptr}<={wbinnext,wgraynext};
//Memorywrite-addresspointer(okaytousebinarytoaddressmemory)
assignwaddr=wbin[ASIZE-1:
0];
assignwbinnext=wbin+(winc&~wfull);
assignwgraynext=(wbinnext>>1)^wbinnext;
//------------------------------------------------------------------
//Simplifiedversionofthethreenecessaryfull-tests:
//assignwfull_val=((wgnext[ADDRSIZE]!
=wq2_rptr[ADDRSIZE])&&
//(wgnext[ADDRSIZE-1]!
=wq2_rptr[ADDRSIZE-1])&&
//(wgnext[ADDRSIZE-2:
0]==wq2_rptr[ADDRSIZE-2:
0]));
//------------------------------------------------------------------
assignwfull_val=(wgraynext=={~wq2_rptr[ASIZE:
ASIZE-1],
wq2_rptr[ASIZE-2:
0]});
always@(posedgewclkornegedgewrst_n)
if(!
wrst_n)wfull<=1'b0;
elsewfull<=wfull_val;
endmodule
3.5用modelsim仿真FIFO
3.5.1编写测试代码
根据前面的顶层模块afifo,编写测试代码如下:
`timescale1ns/1ns
moduletest;
reg[7:
0]wdata;
regwinc;
regwclk;
regwrst_n;
regrinc;
regrclk;
regrrst_n;
wire[7:
0]rdata;
wirewfull;
wirerempty;
integeri;
always
begin
#50wclk=1;
#50wclk=0;
end
always
begin
#100rclk=1;
#100rclk=0;
end
initial
begin
wrst_n=0;
rrst_n=0;
rinc=0;
winc=0;
wclk=0;
rclk=0;
wdata=0;
i=0;
#400;
wrst_n=1;
rrst_n=1;
for(i=0;i<16;i=i