5.1 实例十 FIFO(基于Robei的EDA工具实验案例)

5.1.1. 本章导读

FIFO(First in First out)使用在需要产生数据接口的部分,用来存储、缓冲在两个异步时钟之间的数据传输。在异步电路中,由于时钟之间周期和相位完全独立,因此数据丢失概率不为零。使用FIFO可以在两个不同时钟域系统之间快速而方便地传输实时数据。这次的设计我们就来学习一下如何用Robei和Verilog设计一个8位8深度的FIFO,并通过VIVADO设计平台进行板级验证。
设计准备
FIFO的原理框图如下图5-1-1所示:

通过分析,我们看到图5-1-1中有一个具有独立的读端口和独立的写端口的 RAM存储器。这样选择是为了分析方便。如果是一个单端口的存储器,还应包含一个仲裁器,保证同一时刻只能进行一项操作(读或写),我们选择双口RAM(无需真正的双口RAM,因为我们只是希望有一个简单的相互独立的读写端口)是因为这些实例非常接近实际情况。读、写端口拥有两个计数器(wr_ptr、rd_ptr)产生的互相独立的读、写地址。计数器的值在读写使能信号来临时传递给“读指针”(rd)和“写指针”(wr)。写指针指向下一个将要写入的位置,读指针指向下一个将要读取的位置。每次写操作使写指针加1,读操作使读指针加1。左右两侧的模块为读写指针与满空信号产生模块。这两个模块的任务是给 FIFO提供“空”(empty)和“满”(full)信号。这些信号告诉外部电路FIFO已经达到了临界条件:如果出现“满”信号,那么FIFO为写操作的临界状态,如果出现“空”信号,则FIFO为读操作的临界状态。写操作的临界状态表示FIFO已经没有空间来存储更多的数据,读操作的临界表示FIFO没有更多的数据可以读出。读写指针与满空信号产生模块还可告诉FIFO中“满”或“空”位置的数值。这是由指针的算术运算来完成了。实际的“满”或“空”位置计算并不是为FIFO自身提供的。它是作为一个报告机构给外部电路用的。但是,“满”和“空”信号在FIFO中却扮演着非常重要的角色,它为了能实现读与写操作各自的独立运行而阻塞性的管理数据的存取。这种阻塞性管理的重要性不是将数据复写(或重读),而是指针位置可以控制整个FIFO,并且使读、写操作改变着指针数值。如果我们不阻止指针在临界状态下改变状态,FIFO还能都一边“吃”着数据一边“产生”数据,这简直是不可能的。
从功能上看,FIFO的工作原理如下所述:复位时,读、写指针均为0。这是FIFO的空状态,空标志(empty)为高电平,此时满标志(full)为低电平。当FIFO出现空标志(empty)时,不允许读操作,只能允许写操作。写操作写入到位置0,并使写指针加1。此时,空标志(empty)变为低电平。假设没有发生读操作且随后的一段时间中FIFO只有写操作,一定时间后,写指针的值等于7。这就意味着在存储器中,要写入数据的最后一个位置就是下一个位置。在这种情况下,写操作将写指针变为0,并将输出满标志(full)。
为了更好地判断空状态和满状态,这里设置一个四位的计数器(fifo_cnt),代表存储器(mem)中写入但还未读取的数据个数。当FIFO未进行任何读写操作时,计数器保持不变;当进行写操作时,计数器加1;当进行读操作时,计数器减1;当同时进行写操作和读操作时,计数器值保持不变。这样就可以根据计数器中的值来判断状态的空与满,即:当计时器fifo_cnt=0时,表示存储器处于空状态,输出空标志(empty);当计数器fifo_cnt=8时,表示存储器处于满状态,输出满标志(full)。
设计要求
读写指针都指向一个内存的初始位置,每进行一次读写操作,相应的指针就递增一次,指向下一个内存位置。当指针移动到了内存的最后一个位置时,它又重新跳回初始位置。在FIFO非满或非空的情况下,这个过程将随着读写控制信号的变化一直进行下去。如果FIFO处于空的状态,下一个读动作将会导致向下溢(underflow),一个无效的数据被读入;同样,对于一个满了的FIFO,进行写动作将会导致向上溢出(overflow),一个有用的数据被新写入的数据覆盖。这两种情况都属于误动作,因此需要设置满和空两个信号,对满信号置位表示FIFO处于满状态,对满信号复位表示FIFO非满,还有空间可以写入数据;对空信号置位表示FIFO处于空状态,对空信号复位表示FIFO非空,还有有效的数据可以读出。设计波形如图5-1-2所示。

5.1.2. 设计流程

1. 模型设计

(1)新建一个模型。点击软件工具栏上面的图标,或者点击“File”下拉菜单中的“New”,会有一个对话框弹出来(如图5-1-3所示)。在弹出的对话框中设置你所设计的模型。

参数填写完成后点击“OK”按钮,Robei就会生成一个新的模块,名字就是 fifo,如图 5-1-4 所示:

(2)修改模型。在自动生成的界面图上进行名称的修改,输入引脚为clk,rst,wr,rd和data_in,输出引脚修改成full,empty,data_out。为了区分每个引脚,我们可以修改每个引脚的Color值,并点回车保存。如果选中模块,按“F1”键,就会自动生成一个Datasheet,如图5-1-5所示。

(3)输入算法。点击模型下方的 Code,进入代码设计区。
在代码设计区内输入以下 Verilog 代码:
reg [7:0] fifo_ram[0:7];
reg [2:0] rd_ptr, wr_ptr;
assign empty = (fifo_cnt0);
assign full = (fifo_cnt8);
always @( posedge clk )
begin: write
if(wr && !full)
fifo_ram[wr_ptr] <= data_in;
else if(wr && rd)
fifo_ram[wr_ptr] <= data_in;
end

always @( posedge clk )
begin: read
if( rst )
data_out<=0;
else
begin
if(rd && !empty)
data_out <= fifo_ram[rd_ptr];
else if(rd && wr)
data_out <= fifo_ram[rd_ptr];
end
end

always @( posedge clk )
begin: pointer
if( rst )
begin
wr_ptr <= 0;
rd_ptr <= 0;
end
else
begin
wr_ptr <= ((wr && !full) || (wr && rd)) ? wr_ptr+1 : wr_ptr;
rd_ptr <= ((rd && !empty) || (wr && rd)) ? rd_ptr+1 : rd_ptr;
end
end

always @( posedge clk )
begin: count
if( rst )
fifo_cnt <= 0;
else
begin
case ({wr,rd})
2’b00 : fifo_cnt <= fifo_cnt;
2’b01 : fifo_cnt <= (fifo_cnt0) ? 0 : fifo_cnt-1;
2’b10 : fifo_cnt <= (fifo_cnt8) ? 8 : fifo_cnt+1;
2’b11 : fifo_cnt<=fifo_cnt;
default: fifo_cnt <= fifo_cnt;
endcase
end
end
(4)保存。点击工具栏图标,或者点击菜单“File”中的下拉菜单“Save as”,将模型保存到一个文件夹中。(文件夹路径不能有中文或空格)
(5) 运行。在工具栏点击或者点击菜单“Build”的下拉菜单“Run”,执行代码检查,如有错误,会在输出窗口中显示。如果没有错误提示,则模型fifo设计完成。

2. 测试模块设计

(1)新建一个模块。点击工具栏上的图标,在弹出的对话框中参照图5-1-8进行设计。

(2)修改各个引脚的属性。选中每个引脚,在属性栏中对照图5-1-7进行修改引脚属性,同时可以修改其颜色,方便区分不同的引脚信号。
(3)另存为测试文件。点击工具栏图标,将测试文件保存到fifo模型所在的文件夹下。
(4)加入模型。在Toolbox工具箱的Current栏里,会出现之前设计的fifo模型,单击该模型并在fifo_test上添加。
(5) 连接引脚。 点击工具栏中的图标, 或者选择菜单“Tool”中的“connect”,如图5-1-8 所示连接引脚。完成连接的模块如图5-1-8所示。这个时候,注意查看连接线的颜色。如果鼠标要变回选择模式,点击图标

(6)输入激励。点击模块下方的“Code”,输入激励算法。激励代码在结束的时候要记得用$finish结束。
激励代码:
initial begin
rst=0;
clk=0;
wr=0;
rd=0;
data_in=0;
#1 rst=1;
#5 rst=0;
#3 wr=1;
#5 rd=1;
#5 rd=0;
#5 wr=0;
#5 wr=1;
#10 rd=1;
#10 rd=0;
#14 KaTeX parse error: Expected 'EOF', got '#' at position 28: …always begin #̲2 clk=~clk; end…random;
end
(7)执行仿真并查看波形。点击工具栏,查看输出信息,检查没有错误之后点击进行仿真,再点击或者菜单“View”中的“Waveview”,波形查看器就会打开。点击右侧 Workspace 中的信号,进行添加并查看。点击波形查看器工具栏上的图标进行自动缩放。如图5-1-9所示。分析仿真结果并对照真值表,查看设计波形与设计要求是否一致。

3. 约束模块设计

在设计约束文件之前,我们还是要考虑到开发板硬件资源的限制,需要把设计中数据的位数修改为4位。
(1)打开之前设计的fifo模块,把输入data_in,输出data_out的长度修改为4位,保存并执行。执行后模块的Verilog代码中数据长度也会被更新,便于之后的操作。
(2)新建一个模块,命名为fifo_constrain,模块类型选择为constrain,并将其保存到和之前设计的fifo模块的同一目录下。

(3)连线并修改端口名称。其中的data_in,data_out,fifo_cnt需要对应4个约束模块的端口,并且4根连线的名称分别为0,1,2,3。本设计中使用的开发板引脚如下:
clk对应开发板上按键开关R18;
rst对应开发板上按键开关P16;
data_in[0],data_in[1],data_in[2],data_in[3]对应拨码开关G15,P15,W13,T16;
wr对应开发板上按键开关Y16;
rd对应开发板上按键开关V16;
data_out[0],data_out[1],data_out[2],data_out[3]对应LED灯M14,M15,G14,D18;
fifo_cnt[0],fifo_cnt[1],fifo_cnt[2],fifo_cnt[3]对应U17,V13,H15,J15;
full和empty分别对应W16,V12;
完成后的约束模块如图5-1-11所示。

(4)保存并执行,如果软件显示“Generate constrain file complete”,则说明已经成功生成fifo_constrain.xdc文件。

5.1.3. 板级验证

为了测试所设计FIFO的工作特性,选择搭载XILINX公司的Z-7010芯片的开发板,所以选用VIVADO设计平台进行Synthesis、Implementation和Generate Bitstream,最终将生成的数据流文件下载到开发板内,并进行验证。

1. VIVADO设计平台进行后端设计

1.1启动Vivado软件并选择设备XC7Z010CLG400-1作为硬件对象,设计语言选用Verilog,建立新的工程,添加通过Robei设计的文件fifo.v。
(1)打开Vivado,选择开始>所有程序>Xilinx Design Tools> Vivado2013.4> Vivado2013.4;
(2)单击创建新项目Create New Project启动向导。你将看到创建一个新的Vivado项目对话框如图5-1-15所示,单击Next;

(3)在弹出的对话框中输入工程名fifo及工程保存的位置,并确保Create project subdirectory复选框被选中,单击Next;
(4)选择项目类型表单的RTL Project选项,不勾选Do not specify sources at this time复选框,然后单击Next;
(5)使用下拉按钮,选中Verilog作为目标文件和仿真语言;
(6)点击添加Add Files按钮,浏览到刚刚我们Robei项目的目录下打开Verilog文件夹,选择fifo.v,单击Open,然后单击Next去添加现有的IP模型;
(7)由于我们没有任何的IP添加,跳过这一步,单击Next去添加约束形成;
(8)点击添加Add Files按钮,浏览到刚刚设计fifo模块目录下的constrain文件夹,选中其中的fifo_constrain.xdc文件,单击Open进行添加。
(9)在默认窗口中,按照图5-1-19所示设置Filer中的选项,然后在Parts中选择XC7Z010CLG400-1,单击Next;
(10)单击Finish,本Vivado项目创建成功。

1.2打开fifo_constrain.xdc文件,查看引脚约束源代码。

(1)在资源窗口sources中,可以通过双击查看设计文件fifo.v。
(2)在资源窗口sources中,展开约束文件夹,如图5-1-18所示,然后双击打开fifo_constrain.xdc进入文本编辑模式;

(3)Xilinx设计约束文件分配FPGA位于主板上的开关和指示灯的物理IO地址,这些信息可以通过主板的原理图或电路板的用户手册来获得。
本次设计的约束文件代码是通过Robei软件自动生成,但是,Robei软件目前生成的约束代码只有对输入输出端口的分配,在这个设计中,我们使用了一个通过开关控制的模拟时钟clk,而非系统时钟,这种电路在综合的时候一般都会报错,所以,在约束文件最后,我们需要手动添加一句命令:
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF]
来保证流程中不会出错。
完整的约束代码如下:
#This file is generated by Robei!
#Pin Assignment for Xilinx FPGA with Software Vivado.
set_property PACKAGE_PIN R18 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN P16 [get_ports rst]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property PACKAGE_PIN G15 [get_ports data_in[0]]
set_property IOSTANDARD LVCMOS33 [get_ports data_in[0]]
set_property PACKAGE_PIN P15 [get_ports data_in[1]]
set_property IOSTANDARD LVCMOS33 [get_ports data_in[1]]
set_property PACKAGE_PIN W13 [get_ports data_in[2]]
set_property IOSTANDARD LVCMOS33 [get_ports data_in[2]]
set_property PACKAGE_PIN T16 [get_ports data_in[3]]
set_property IOSTANDARD LVCMOS33 [get_ports data_in[3]]
set_property PACKAGE_PIN Y16 [get_ports wr]
set_property IOSTANDARD LVCMOS33 [get_ports wr]
set_property PACKAGE_PIN V16 [get_ports rd]
set_property IOSTANDARD LVCMOS33 [get_ports rd]
set_property PACKAGE_PIN W16 [get_ports full]
set_property IOSTANDARD LVCMOS33 [get_ports full]
set_property PACKAGE_PIN V12 [get_ports empty]
set_property IOSTANDARD LVCMOS33 [get_ports empty]
set_property PACKAGE_PIN M14 [get_ports data_out[0]]
set_property IOSTANDARD LVCMOS33 [get_ports data_out[0]]
set_property PACKAGE_PIN M15 [get_ports data_out[1]]
set_property IOSTANDARD LVCMOS33 [get_ports data_out[1]]
set_property PACKAGE_PIN G14 [get_ports data_out[2]]
set_property IOSTANDARD LVCMOS33 [get_ports data_out[2]]
set_property PACKAGE_PIN D18 [get_ports data_out[3]]
set_property IOSTANDARD LVCMOS33 [get_ports data_out[3]]
set_property PACKAGE_PIN U17 [get_ports fifo_cnt[0]]
set_property IOSTANDARD LVCMOS33 [get_ports fifo_cnt[0]]
set_property PACKAGE_PIN V13 [get_ports fifo_cnt[1]]
set_property IOSTANDARD LVCMOS33 [get_ports fifo_cnt[1]]
set_property PACKAGE_PIN H15 [get_ports fifo_cnt[2]]
set_property IOSTANDARD LVCMOS33 [get_ports fifo_cnt[2]]
set_property PACKAGE_PIN J15 [get_ports fifo_cnt[3]]
set_property IOSTANDARD LVCMOS33 [get_ports fifo_cnt[3]]
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF]

(4)点击File->Save File保存文件。
1.3使用Vivado综合工具来综合设计,并进行Implementation任务实现。
(1)单击综合任务下拉菜单中的Run Synthesis,综合过程将会分析fifo.v文件并生成网表文件。当综合过程完成了,且没有错误信息,将会弹出带有三个选项的完成对话框;
(2)如果有错误,根据错误信息提示修改,直至综合没有错误。然后选择Run Implementation选项,执行任务实现,然后单击OK;
(3)任务实现过程将在综合后的设计上运行。当这个过程完成,且没有错误信息,将会弹出带有三个选项的任务实现完成对话框;
(4)如果有错误,根据错误信息提示修改,直至综合没有错误。
1.4将开发板上的电源开关拨到ON,生成比特流并打开硬件会话,对FPGA进行编程。
(1)确保微型USB电缆连接到PROG UART接口(在电源开关的旁边);
(2)确保JP7设置为USB提供电源;
(3)接通电源板上的开关;
(4)点击任务实现完成弹出的对话框中Generate Bitstream或者点击导航窗口中编程和调试任务中的Generate Bitstream。比特流生成过程将在任务实现设计后运行。当完成比特流生成后会弹出有三个选项的完成对话框;
(5)这一过程将已经生成的fifo.bit文件放在fifo.runs目录下的impl_1目录下;
(6)选择打开硬件管理器Open Hardware Manager选项,然后单击确定。硬件管理器窗口将打开并显示“未连接”状态;
(7)点击Open a new hardware target。如果之前已经配置过开发板你也可以点击最近打开目标链接Open recent target;


(8)单击Next看Vivado自定义搜索引擎服务器名称的形式;
(9)单击Next以选择本地主机端口;
(10)单击两次Next,然后单击Finish。未连接硬件会话状态更改为服务器名称并且器件被高亮显示。还要注意,该状态表明它还没有被编程;

(11)在器件上单击鼠标右键,选择Program device或单击窗口上方弹出的Program device-> XC7z010_1链接到目标FPGA器件进行编程;

(12)单击确定对FPGA进行编程。开发板上Done指示灯亮时,器件编程结束;
(13)通过控制拨动和按键开关的开闭来观察LED(请参考前面的逻辑图)验证输出结果。

2. 开发板验证

首先,按住res(BTN1)键不放,再按一次至两次clk(BTN0)键进行复位;
其次,data_in先输入0001,即将拨动开关SW0拨到1,然后按住wr(BTN3)按键不放,再按一下clk按键将数据写进FIFO存储器,同理分别将data_in的0011、0111、1111、1110、1100、1000、0000数据写进存储器中;
最后,按住rd(BTN2)键不放,再按clk键,每按一次clk,就会从FIFO存储器中读出一个数据,并显示在LED灯上,验证读出数据是否正确。


由上述结果可验证本次设计的FIFO功能正常,达到了设计的目的。

5.1.4. 问题与思考

(1)使用 Robei 设计一个8位4深度的FILO。
(2)使用 Robei 设计一个SPI总线。

实例十 — FIFO相关推荐

  1. C语言库函数大全及应用实例十四

    原文:C语言库函数大全及应用实例十四                                       [编程资料]C语言库函数大全及应用实例十四 函数名: strset 功 能: 将一个串 ...

  2. Vue+Echarts监控大屏实例十五:智慧物流监控模板实例下

    接上一篇:Vue+Echarts监控大屏实例十四:智慧物流监控模板实例上 源码下载地址:   Vue+Echarts监控大屏实例十二:智慧物流监控模板实例下载 4.8 员工监控界面   展示数量分布. ...

  3. ENSP配置 实例十 ACL配置

    ENSP配置 实例十 ACL配置 R1 [R1]int g0/0/0 [R1-GigabitEthernet0/0/0]ip add 192.168.1.254 24 [R1-GigabitEther ...

  4. Spring Boot Ajax实例(十六)

    这篇博文主要用于新手学习Spring Boot,同时也记录自己学习的过程- 文章内容主要来源于易百教程 本文将展示如何使用jQuery.ajax将HTML表单请求发送到Spring REST API并 ...

  5. 关联规则应用场景实例十则

    本文整理了10个天池.DataCastle.DataFountain等中出现的,可使用聚类算法处理的问题场景实例. 1 基于用户位置信息的商业选址 随着信息技术的快速发展,移动设备和移动互联网已经普及 ...

  6. 聚类算法应用场景实例十则

    本文整理了10个天池.DataCastle.DataFountain等中出现的,可使用聚类算法处理的问题场景实例. 1 基于用户位置信息的商业选址 随着信息技术的快速发展,移动设备和移动互联网已经普及 ...

  7. opengl绘制长方体线框_OpenGL绘图实例十之绘制3D机器人

    综述 通过上一节说的绘制3D图形基础,我们应该对绘制3D图形有了基本的认识,接下来我们就进行一个实例,绘制一个3D机器人. 本节我们要完成的任务有: 1.绘制一个仿真3D机器人(样式自选,参考例图), ...

  8. 微信小程序(看文档写实例十)微信小程序课堂宝APP实现我的模块相关界面及逻辑

    继上篇博文,这篇完成最后一个模块,即我的模块. 一.页面效果 这个模块是和用户类型相关的,因此老师账号和学生账号能看的功能不一样,老师端效果如下: 点击头像到达个人信息如下: 点击后可以做相应的修改. ...

  9. SpringBoot+Mybaits搭建通用管理系统实例十四:找回密码功能实现

    一.本章内容   本章实现已注册用户通过短信验证码或邮箱验证码找回登录密码相关接口. 完整课程地址 源码下载地址 二.开发视频 SpringBoot+Mybaits搭建通用管理系统实例六:找回密码接口 ...

最新文章

  1. 4G EPS 中的随机接入
  2. CodeForces - 1553E Permutation Shift(暴力+置换群求环)
  3. (转)CentOS分区操作详解
  4. linux 中kafka发送数据,C++ 向kafka中发送数据
  5. Deep Learning快速学习方法
  6. angular.isString()
  7. 93.复原IP地址(力扣leetcode) 博主可答疑该问题
  8. AppBox v6.0中实现子页面和父页面的复杂交互
  9. Windows7下UEFI开发EDK2环境搭建(VS2013+UDK2015+IASL+patch+Openssl)
  10. pc机收集信息cpu\配置\网络信息
  11. linux glibc升级
  12. 如何实时捕捉社会热点?微博热搜数据监测系统-API接口
  13. MTK76X8最新Openwrt固件下载
  14. html展开阅读全文代码,一个简单的html点击展开/关闭代码
  15. Navigating to current location (/user) is not allowed
  16. (一)关于POE供电定义以及级别划分,如何测试网线是否满足相关标准?
  17. Python中uniform的用法
  18. 计算机课件制作教程ppt,电脑制作ppt详细步骤_新手制作ppt详细步骤图文教程
  19. You have enabled checking of packages via GPG keys. This is a good thing.  However, you do not have
  20. 城市建筑类毕业论文文献都有哪些?

热门文章

  1. 书读百遍其义自见 - 六大原则 23种设计模式
  2. python 多线程
  3. 面试高频,一条sql语句查询成绩,显示'优秀' ,'及格' ,'不及格'
  4. 【Gatsby】Gatsby模式以及基本操作
  5. 完美解决Visio中MathType公式变形的问题以及visio图转pdf之后公式不显示的问题
  6. 【Arduino自动配网+微信Airkiss配网】
  7. 数据可视化—初识Gitee
  8. 一种基于深度学习的视频编码方案
  9. 什么是sys文件系统
  10. 驻足思考:瞬间整理思路并有力表达(先设个坑,不断学习整理)