8.3 一个完整的设计过程
本节不详细讲解语法、代码编写和思想结构,主要目的是测试软件安装激活后能否正常使用以及软件的基本操作步骤,通过第一个实例介绍后面所有设计实例的规范流程和方法(软件基本操作后面不再单独讲解,直接按照标准的开发流程重点讲解设计思想)。
8.3.1 功能简介
拿到一个项目后首先进行项目分析,分析实现的功能是什么、如何进行系统的结构和层次划分,每一部分用什么方法实现,由于我们是进行学习,不是开发产品,所以不考虑芯片选型的问题。
这里我们要通过按键控制一个LED灯的亮灭,按键未被按下时LED灯处于熄灭状态,按键被按下时LED灯处于点亮状态,实现一个最简单的有输入、输出的小工程项目。
8.3.2 硬件资源
明确工程要实现的功能后,就要了解工程设计中用到的硬件资源。在“点亮LED灯”的实验工程中,我们需要用到开发板上的按键和LED灯,要使用按键KEY1点亮LED灯D6,如图8-3所示。
图8-3 硬件资源
由图8-4和图8-5可知,征途Pro开发板的按键未按下时为高电平,按下后为低电平;LED灯则为低电平点亮。
图8-4 按键部分原理图
图8-5 LED灯原理图
8.3.3 新建一个Visio文件及其配置
接下来就是在doc文件夹中新建一个名为led的Visio图,用于绘制设计过程中的结构框图和时序波形图,如图8-6所示。
图8-6 新建Visio图
双击打开新建的Visio文件,不用选择绘图类型,直接点击“取消”按钮,如图8-7所示。
图8-7 保持“选择绘图类型”对话框中默认设置
如图8-8所示,我们添加和FPGA设计相关的工具组件,先依次点击图8-8中①、②、③处的按钮,再依次点击④中的三个工具组件,即可将FPGA相关的三个工具组件添加进来。
图8-8 添加FPGA设计相关组件
如图8-9所示,我们可以看到显示了已经添加的组件。
图8-9 显示已添加的组件
点击图8-10所示的“>”按钮将其展开。
图8-10 展开组件栏
展开后如图8-11所示,三个设计好的专门用于FPGA设计的插件已经添加完毕(也可以修改该插件,或者重新设计符合自己习惯的插件)。
图8-11 工具插件添加成功
为了画图时更好地对齐,我们选中“视图”下的“网格”选项,如图8-12所示。
图8-12 显示网格
做好上面的基本设置后就可以进行FPGA框图和时序波形图的设计了,更多细节上的操作可以在网上查询获取,这里不再一一讲解。
8.3.4 模块和端口信号划分
接下来我们要对该项目的系统结构和层次进行设计,即要实现该功能需要设计哪些独立的模块,以及分析每一个模块的输入输出信号应该有哪些,这部分的设计往往是系统架构设计,非常重要。在实际运用中我们会设计一些功能较为复杂的项目,往往具有多种功能,为了简化设计,我们要把复杂的功能进行拆分,划分成相对独立的小功能,这些小功能的实现由一个个独立的模块来完成,每个小模块的功能和运转都是独立的,这样就可以让多个人同时进行设计和验证,提高了开发效率,当每个人所分配的模块都设计好了以后,再将每个人设计的模块根据各自的功能和关系连接到一起,实现整体功能。但是如何进行模块的划分和整体的布局以及信号的端口设计,都是需要我们在日后的学习中不断积累的,通过做项目、多了解各种方案才能够使我们在对整体的设计结构和层次上有一个很好的把握。
此处设计的工程比较简单,只有一个独立的功能,只需要一个模块就可以实现。我们将模块命名为led,然后再分析模块的输入输出信号应该有哪些。将一个1bit的输入信号连接到按键上,命名为key_in,一个1bit输出信号连接到LED灯上,命名为led_out。
根据上面的分析设计出的Visio框图如图8-13所示,在此设计中我们并不关心输入和输出之间通过什么方式来实现这种关系(可能是通过线连接、寄存器连接或者更复杂的逻辑连接实现),而只关心最后的输出是不是实现了我们期望的结果。
图8-13 框图设计
为了使端口信号和功能更加清晰,我们将其整理为如表8-1所示的表格。
表8-1 端口信号描述
8.3.5 波形设计
设计完框图结构和端口信号后就需要设计框图结构下的模块功能,也就是输入和输出之间的关系。输入和输出满足信号与系统的关系,这种关系是一种时序的、逻辑的关系,即既有时间上的关系又有逻辑上的关系,而不再是结构上的关系。对于这种关系,我们用波形图来表达最为清晰、直观。因为FPGA本身就是并行执行的,当信号较多时,仅靠人脑的记忆和联想,众多信号的并行时序关系的效果可能并不是非常好,所以我们要通过绘制波形图的方法来将这种关系表达出来。波形画出来后,一切时序和逻辑关系就清晰了,无论是代码实现,还是日后再次用来分析代码,有波形图作为辅助参照,一切变得如此简单。但是如何根据数据手册、设计要求来绘制波形图,也是设计中的重点,需要多练习并加以总结,才能够熟练掌握并运用自如。
为了使绘制的波形图更加直观,在绘制波形图前我们先统一约定信号的表示方式:输入信号用绿色标注,输出信号用红色标注,中间变量信号用黄色标注(本章不涉及中间变量,后面的章节会有体现),本书中所有波形设计均是按照这个规范作图的。当然,如果学习者有自己的喜好,也可以自定义配置,只要能够有所区分即可。绘制波形图时,首先要设计完善的测试激励以模拟最接近真实情况的输入信号,然后根据输入信号的波形画出相应的输出信号的波形。在画波形的过程中,你会了解到各信号之间的关系。先画波形的好处是能够在写代码之前对一些细节问题做到预先了解,以便在编写和调试代码时做到胸有成竹,在大型复杂的项目中,这样做的优点更为明显。我们还有一个写代码的诀窍,就是根据波形图快速编写出代码,如果波形图正确,编写代码时会又快又准确,如果你的基本功扎实,画图认真准确,那么可以说根据波形图编写的代码直接就是正确的,几乎不用调试,大大提升项目开发效率。
本章实例的具体功能为:按键按下时(即key_in为低电平),控制LED灯的引脚为低电平,板卡硬件电路设计的LED灯为低电平点亮,所以此时LED灯为点亮状态。对于组合逻辑,我们常用真值表来列出输入与输出的这种对应关系,这样最为直接、明确,列出的真值表如表8-2所示,然后再根据真值表的输入与输出的对应关系画波形图。其波形如图8-14所示,与真值表的关系一一对应。
表8-2 输入输出信号真值表
图8-14 用Visio绘制波形图
如果最后通过仿真得到的结果和Visio波形的输入输出的逻辑关系一致(因为是最简单的组合逻辑,所以还不考虑时序之间的关系),那么我们设计的代码一定是正确的。
8.3.6 新建工程
首先点击图标打开Quartus II_13.0软件,如图8-15所示。
图8-15 打开Quartus II_13.0软件
紧接着弹出如图8-16所示界面。
图8-16 Quartus II_13.0启动界面
软件完全打开后如图8-17所示。
图8-17 Quartus II_13.0打开效果
软件完全打开后会显示一个快捷向导,如图8-18所示。其中,①是创建一个新的工程,②是打开已经存在的工程,③是最近打开过的工程列表,用户可以根据自己的需求进行选择,也可以不选择,不选择时可以直接点击界面右上角的按钮退出。这里我们选择直接退出。
图8-18 软件快捷向导
使用新工程向导创建工程,可以选择图8-19中①处的“New...”命令,也可以选择②处的“New Project Wizard...”命令直接打开新工程向导界面。这里我们选择“New...”命令。
图8-19 用“New...”命令新建工程
在弹出的对话框中选择“New Quartus II Project”选项后点击“OK”按钮,如图8-20所示。
图8-20 选择“New Quartus II Project”选项
打开新工程向导首页,即“New Project Wizard”对话框,直接点击“Next”按钮,如图8-21所示。
图8-21 打开“New Project Wizard”对话框
如图8-22所示,①处是这个新建的工程的位置,选择到led文件夹下的quartus_prj文件夹;②处是这个工程的名字,也命名为led;③处是整个工程设计顶层的文件名,让这个名字保持和②中的命名一致即可。然后点击“Next”按钮。
图8-22 设置“New Project Wizard”对话框
在“File name”栏中选择添加已经写好的.v文件,如果有多个文件,可以一次性全部添加进工程。因为我们还没有写好的.v文件,所以此处不进行添加,直接点击“Next”按钮,如图8-23所示。
图8-23 “File name”栏可用于添加.v文件
如图8-24所示,其中:
① 处用于选择使用哪个系列的芯片,此处使用的是Cyclone IV系类的芯片;
② 处用于选择该芯片的封装类型,此处选择FBGA封装;
③ 处用于设置引脚数量,此处选择256;
④ 处用于设置速度等级,此处选择8。
这4个选项设置好以后,就得到了⑤处所示的筛选结果,可以看到我们使用的芯片的具体型号为EP4CE10F17C8。全部选择好之后,点击“Next”按钮。
图8-24 筛选芯片
如图8-25所示,其中:
① 处是器件的名称;
② 处是内核电压,我们所使用的芯片的内核电压是1.2V;
③ 处是Logic Elements(每个逻辑单元主要由一个四输出的查找表和一个寄存器构成,还包括其他的必要电路)的数量,逻辑单元数越多说明资源越多,能够实现更多的逻辑设计,芯片的价格也就越贵,设计逻辑代码时主要使用这部分资源;
④ 处是用户可配置的I/O,共有180个,虽然该芯片有256个引脚,但是有一些引脚是不可以随意配置的,如电源引脚、固定功能的引脚,除去具有固定功能的引脚,留给用户可任意配置的引脚只有180个,设计中使用比较多的内存时就可以使用这部分专用资源;
⑤ 处是存储器的容量,共423 936bit,主要是指Block RAM(块RAM),423 936bit即46个M9K(每一块中包含8192个存储位,加上校验位共9216位,故称M9K);
⑥ 处是嵌入式乘法器数目,共有46个,在进行数学运算时可以调用该部分资源,以节省逻辑资源的开销;
⑦ 处是锁相环的数量,共有2个,主要用于调制分频、倍频和时钟相位;
⑧ 处是全局时钟引脚,共有10个,全局时钟引脚是连接到全局时钟树上的,能够保证连接到全局时钟树上的时钟信号到达每个寄存器的时间都是相同的。
图8-25 查看器件信息
如图8-26所示,在此界面中可以选择一些三方的开发工具,我们暂时不选,直接点击“Next”按钮。
图8-26 设置第三方工具
最后生成整个新工程向导的总结,可以验证是否和最初的选择一致,如果没有问题,则点击“Finish”按钮,如图8-27所示。
图8-27 新建工程总结
新建工程完毕后,界面左上角会显示器件名和顶层设计文件名,如图8-28所示。
图8-28 新建工程完毕
此时再打开quartus_prj文件夹,可以发现里面生成了一些文件夹和文件,led.qpf就是这个工程的工程文件,led.qsf就是工程的配置文件,如图8-29所示。
图8-29 工程文件
8.3.7 RTL代码的编写
在rtl文件夹下新建一个名为led的文本文件,然后重命名为led.v,如图8-30所示。
图8-30 新建代码文本文件
使用Notepad++打开该文件,准备编写RTL代码,如图8-31所示。
图8-31 打开代码文件
开始编写RTL代码,用RTL代码编写出的模块叫作RTL模块(后文中也称为“功能模块”或“可综合模块”)。命名为RTL代码,是因为用Verilog HDL在寄存器传输级逻辑(Resistances Transistors Logic)中来描述硬件电路,RTL代码能够综合出真实的电路以实现我们设计的功能,区别于不可综合的仿真代码(本章的重点是熟悉整个开发流程和软件工具的使用,不详细讲解代码)。我们前面讲过,根据波形写代码,这种方法在组合逻辑中表达得不够明显,而且刚开始的例子都很简单,后面我们会专门讲解如何根据波形图来实现代码,并在视频中着重讲述这种方法。
此处直接编写LED模块参考代码,具体参见代码清单8-1。
代码清单8-1 led模块代码(led.v)
1 module led 2 ( 3 input wire key_in , //输入按键 4 5 output wire led_out //输出控制LED灯 6 ); 7 8 //********************************************************************// 9 //***************************** Main Code ****************************// 10 //********************************************************************// 11 //led_out:LED灯输出的结果为key_in按键的输入值 12 assign led_out = key_in; 13 14 endmodule
代码编写好后,需要将led.v文件添加到工程中。点击“Files”标签切换到文件模式,在该模式下可以看到所有属于该工程下的文件,如图8-32所示。
图8-32 切换到文件模式
右击“Files”,并选择“Add/Remove Files in Project...”命令,如图8-33所示。
图8-33 选择Add/Remove Files in Project...命令
如图8-34所示,在“File name:”栏选择已经写好的.v文件,此处找到“led\rtl”路径下的“led.v”。
图8-34 添加.v文件
选择“led.v”文件后界面如图8-35所示,点击“Add”按钮将其添加到工程中。
图8-35 选择“led.v”文件并添加至工程
点击“OK”按钮完成添加,如图8-36所示。
图8-36 点击“OK”按钮完成添加
添加成功后如图8-37所示。
图8-37 添加文件成功
8.3.8 代码的分析和综合
点击如图8-38所示的图标进行代码的分析和综合,进行该步骤的目的,首先是检查语法是否有错,其次是让综合器将代码解释为电路的形式。
图8-38 进行代码的分析和综合
如图8-39所示,只有方框内的信息显示为“”,说明分析与综合完成,并没有语法错误产生。
图8-39 完成代码的分析和综合
8.3.9 查看RTL视图
双击“Netlist Viewers”下的“RTL Viewer”选项,如图8-40所示。
图8-40 查看RTL视图
打开后的界面如图8-41所示,这就是我们设计的硬件电路结构,可见输入是key_in,然后通过一根线连接到输出led_out,和我们的设计所表达的意思相同。
图8-41 RTL视图
8.3.10 Testbench的原理
Testbench是测试脚本,测试谁?当然是测试我们用硬件描述语言(HDL)设计的电路,测试设计电路的整体功能、部分性能是否与预期的目标相符。有些初学者没有养成编写Testbench的习惯,总以为这是烦琐的、无用的,或者他们习惯用在线逻辑分析仪器来调试,其实不然,当你在编写大型工程代码的时候,综合一次所用的时间少则十几分钟,多则几个小时,这种无用时间的消耗是我们所不允许的,在线逻辑分析仪虽然好用,但是每修改一次代码,结果就要综合一次,并不能节省时间,但使用Testbench做仿真的速度很快,修改后即可马上看到结果,从而节省了大量的开发时间,所以大家学习FPGA时务必养成编写Testbench的好习惯。
编写Testbench进行测试的过程如下:
1)产生模拟激励(输入波形)。
2)将产生的激励加入被测试模块并观察其输出响应。
3)将输出响应与期望进行比较,从而判断设计的正确性。
接下来就是仿真激励Testbench的编写,首先给大家介绍一下Testbench的原理。
我们通常给Testbench命名,是在被测试的模块名前加一个tb_(也可以在被测试的模块名后面加_tb),这样容易识别出具体验证的是哪个模块。如图8-42所示,周围灰色的区域就表示一个测试系统,我们要写的Testbench就是用代码实现该区域的功能,这个功能只针对待测试的led模块,如果换成其他模块,需要单独设计专门针对其他待测试系统的Testbench。
图8-42 测试系统
第二步是将待测试的led模块放到tb_led模块框架中,如图8-43所示。
图8-43 将led模块放入tb_led框架
第三步是将两个模块进行连线,如图8-44所示。
图8-44 将两个模块连线
tb_led模块和led模块的关系就是上面这样,但是我们需要如何设计tb_led模块呢?我们希望tb_led模块能够产生key_in信号,然后这个信号通过led模块从led_out输出,观察led_out输出的信号是不是和最初设计的波形一致,如果严格一致,则说明设计正确,代码综合布局布线后下载到板上,能够正常工作的可能性越高。为什么说是“越高”而不是100%能够正常工作呢?这是因为有时在高速系统中逻辑仿真是对的,但是下载到板上依然不可以正常工作,其原因是逻辑并没有问题,真正的问题是在高速系统中往往需要进行时序约束,否则会由于系统工作太快导致时序违例,同样不能正常工作。
可能大家还听说过后仿真(也称为时序仿真),我们为什么没做这个呢?这样做能保证下板后功能是100%正确的呢?答案依然是不能,虽然这样做的正确率相比于只做了逻辑仿真提高了,但是下板后还是可能存在问题,而且后仿真的速度特别慢,所以我们就不做这一步了。如果做了逻辑仿真后下板后仍有问题,那么可以使用在线逻辑分析仪实时抓取信号,确定是不是时序的问题,如果是时序的问题,则还要对系统进行静态时序分析(SAT),针对具体违例的时序加以约束。那后仿真是不是没有用了呢?当然也不是,前面我们讲过FPGA可以用在数字IC领域中,在数字IC的设计和验证中,往往要加入各种仿真延时文件,进行后仿真,但是本书不涉及数字IC的内容,因为数字IC虽然和FPGA相关,但又是一个全新的世界,如果想了解数字IC设计和验证或者想从事数字IC相关行业的工作,可以在学习本书后再继续深入学习。
8.3.11 Testbench代码的编写
先在sim文件夹下新建一个名为tb_led的文本文件,然后重命名为tb_led.v,如图8-45所示。
图8-45 新建仿真文件
使用Notepad++打开该文件,准备Testbench代码的编写,如图8-46所示。
图8-46 仿真文件的编写
开始Testbench代码的编写(本章的重点是熟悉整个开发流程和软件工具的使用,不进行代码的详细讲解),此编写技巧和方法我们也会在后面的章节和视频中详细讲解。此处直接编写LED模块仿真代码,具体参见代码清单8-2。
代码清单8-2 LED模块仿真参考代码(tb_led.v)
1 `timescale 1ns/1ns 2 module tb_led(); 3 4 //********************************************************************// 5 //****************** Parameter and Internal Signal *******************// 6 //********************************************************************// 7 //wire define 8 wire led_out ; 9 10 //reg define 11 reg key_in ; 12 13 //********************************************************************// 14 //***************************** Main Code ****************************// 15 //********************************************************************// 16 //初始化输入信号 17 initial key_in <= 1'b0; 18 19 //key_in:产生输入随机数,模拟按键的输入情况 20 always #10 key_in <= {$random} % 2; /*取模求余数,产生非负随机数0、1, 21 每隔10ns产生一次随机数*/ 22 23 //********************************************************************// 24 //**************************** Instantiate ***************************// 25 //********************************************************************// 26 //------------- led_inst ------------- 27 led led_inst 28 ( 29 .key_in (key_in ), //input key_in 30 31 .led_out(led_out) //output led_out 32 ); 33 34 endmodule
代码编写好后,需要将tb_led.v文件添加到工程中。点击“File”标签切换到文件模式,在该模式下可以看到所有属于该工程下的文件,如图8-47所示。
图8-47 切换文件模式
右击“File”,并选择“Add/Remove Files in Project...”命令,如图8-48所示。
图8-48 选择“Add/Remove Files in Project...”命令
如图8-49所示,在“File name:”栏选择已经写好的.v文件,找到“led\sim”路径下的“tb_led.v”文件。
图8-49 选择.v文件
打开“tb_led.v”文件后如图8-50所示,点击“Add”按钮将其添加到工程中。
图8-50 打开“tb_led.v”文件
点击“OK”按钮完成添加,如图8-51所示。
图8-51 添加文件
添加完成后如图8-52所示。
图8-52 添加文件成功
8.3.12 仿真设置
首先选择“Assignments”下的“Settings...”命令,如图8-53所示。
图8-53 选择“Settings...”命令
然后选择“EDA Tool Settings”下的“Simulation”选项,如图8-54所示。
图8-54 选择“Simulation”选项
如图8-55所示:①框中“Tool name:”栏选择“ModelSim”,“ModelSim”就是独立的ModelSim,而“ModelSim-Altera”是安装Quartus II时自带的ModelSim;②框中“Format for output netlist:”栏是选择输出网表的语言格式,该网表主要用于后仿真,但因为在逻辑设计中往往不做后仿真,所以这里保持默认值即可;③框中“Time scale:”栏是选择输出网表的时间单位,所以也保持默认值即可;④框中的“Output direction:”表示选择输出网表的位置,这里保持默认值即可。设置完成后即可在工程目录下产生一个名为simulation的文件夹,里面还有一个名为modelsim的子文件夹,这里不仅存放输出的网表文件,还存放了后面当ModelSim运行仿真后所产生的相关文件。
图8-55 设置Simulation参数
8.3.13 设置NativeLink
基于NativeLink的设计就是在Quartus II中设置好一些参数后,直接打开ModelSim软件可以立刻看到仿真的结果,可谓一键操作式的仿真,十分方便。
先选择“NativeLink settings”中的“Compile test bench:”选项(如果设计了多个Testbench可以在该栏进行选择),然后点击后面的“Test Benches...”按钮,如图8-56所示。
图8-56 点击“Test Benches...”按钮
直接点击“New...”按钮,如图8-57所示。
图8-57 点击“New...”按钮
如图8-58所示:①框处“Test bench name:”就是前面“Compile test bench:”框中的名字,也就是图8-57中新建的这个Test Benches的名字(一般情况下框①和框②的名字保持一致即可);②框处“Top level module in test bench:”是Testbench顶层的名字,这里只有一个层次,那就是图8-59中所示的名字tb_led;③框处是“End simulation at:”,用于设置打开ModelSim时波形运行多久后停止,如果这里不设置,就需要在仿真代码中仿真完毕处添加“$stop”代码暂停仿真,或者在弹出的ModelSim界面中按暂停按钮,否则ModelSim会一直运行。我们设置的是1μs,这个时间刚刚好,即打开ModelSim后运行1μs后波形停止运行,如果需要观察信号运行1μs后的波形,可以在ModelSim中再设置运行时间后继续运行;④框处“File name:”选择sim文件夹下的tb_led.v文件。都设置好后点击“Add”按钮将“tb_led.v”文件添加进来。
图8-58 设置“New Test Bench Settings”对话框
图8-59 Testbench顶层名
设置好后点击“OK”按钮,如图8-60所示。
图8-60 点击“OK”按钮
继续点击“OK”按钮,如图8-61所示。
图8-61 继续点击“OK”按钮
最后点击“OK”按钮,完成NativeLink的设置,如图8-62所示。
图8-62 NativeLink设置完成
8.3.14 打开ModelSim观察波形
因为第一个led工程实例相对简单,用到的也是ModelSim中的一些基本操作,所以本节只会对ModelSim软件的部分功能的使用进行讲解。但随着工程实例复杂度的提高,我们将会用到ModelSim中更高级的功能,那时再做详细讲解。
点击“Tools”→“Run Simulation Tool”→“RTL Simulation”打开ModelSim进行功能仿真(因为主要是验证逻辑的正确性,所以也称逻辑仿真),如图8-63所示。
图8-63 打开ModelSim
如果能够成功打开如下界面,则说明ModelSim破解和关联Quartus II都正确,如图8-64所示。
图8-64 成功打开ModelSim
完全打开后的界面如图8-65所示,会发现在Wave窗口有波形显示出来。
图8-65 Wave窗口显示波形
点击箭头处,把显示波形的界面单独打开,如图8-66所示。
图8-66 单独打开波形界面
点击图8-67中的放大镜图标,显示如图8-68所示的全部仿真时间的波形,波形最后结束的位置对应的时间如图8-69所示,在1000ns处,也就是1μs,和图8-58中设置的结果是一致的。
图8-67 点击放大镜图标
图8-68 全部仿真时间模型
图8-69 波形结束位置对应的时间
如图8-70所示,点击框中第一个按钮即添加参考线(图8-71中方框框出的线即参考线),点击第二个按钮可去掉参考线。当在波形界面中点击时,参考线也会指定到该位置,如果有两条参考线,会在两条参考线之间显示时间差,如图8-72所示。
图8-70 添加参考线
图8-71 已添加的参考线
图8-72 显示两条参考线间的时间差
点击图8-73左下角处的图标即可固定参考线,被固定的参考线显示为红色(添加和删减参考线也可以通过图标旁边的“+”“-”号实现)。
图8-73 固定参考线
为了更好地观察分析ModelSim仿真出的波形,会用到如图8-74所示的几个按钮:其中①框中的按钮用于复位波形,点击后会出现如图8-75所示的对话框,我们直接点击“OK”按钮即可清空界面中的全部波形。
图8-74 常用按钮
图8-75 波形复位对话框
② 框处用于设置运行一次仿真的时间,根据实际观察波形的需要填写相应的时间。但仿真的时间越久,所需要等待的时间也会越长,所生成的仿真文件越大。
③ 框中的第一个图标是运行左边设置的时间值,图8-74中显示的是100ps,那么点击一次就运行100ps,运行完100ps后就会自动停止,也可以手动输入其他的时间单位和时间值,③框中的第二个和第三个图标,点击一次后波形会一直运行下去,直到点击第四个和第五个图标时才会停止。
④ 框中的图标分别是波形的下降沿定位和上升沿定位,当选中要观察的信号时,再点击这两个按钮时,参考线就可以立刻定位到该信号的下降沿或上升沿,再次点击即跳到下一个下降沿或上升沿。
⑤ 框中的第一个和第二个图标分别是波形放大和缩小(波形的放大缩小也可以按住键盘上的“Ctrl”键,同时滚动鼠标滚轮来实现),第三个图标是全局波形显示,第四个图标的作用是将参考线位置处的波形进行放大,第五个图标的作用是将参考线处的波形移动到波形显示窗口的最开头处。
从图8-76可以看出在参考线处key_in的值为十六进制表示的1'h0,根据需要我们还可以设置为其他格式。如图8-77所示,右击信号名“key_in”,选择“Radix”命令后会看到各种不同进制格式的显示方式,可以根据需要任意选择。
图8-76 查key_in的值
图8-77 选择显示方式
8.3.15 仿真波形分析
我们使用ModelSim仿真出波形后可以直接观察波形和预期效果的正确性,因为这个项目工程比较简单,只有两个信号,也没有内部信号,不容易出错,所以可以直接分析得出。但是试想一下,如果有上百个信号,但最后的输出结果还是出现了错误,那你凭着自己的理解和观察就很难进行判断了,所以我们一开始就要养成良好的学习习惯,将ModelSim仿真出来的波形图和之前根据自己理解用Visio画出的波形图进行对比,既可以发现之前对整体设计的理解偏差,又能够方便地改错。
通过对比图8-78和图8-79发现两个图的输入输出之间的关系是一模一样的(这里的一样不是指Visio波形中的key_in信号和ModelSim波形中的key_in信号都是先高后低的关系,而是指Visio波形中的key_in信号和led_out之间的关系对应与ModelSim波形中的key_in信号和led_out之间的关系是否一致),都是输入信号key_in与输出信号led_out相同,说明代码的设计结果符合预期,可以进行下一步操作了。
图8-78 用Visio画的波形图
图8-79 ModelSim仿真信号
8.3.16 引脚约束
仿真结束后即验证了代码设计的正确性,可以上板验证了,但是在上板之前还需要进行引脚约束,就是根据硬件原理图确定按键和LED灯分别与FPGA芯片的哪个引脚对应。由原理图可知,板上共有四个普通按键和四个LED灯,我们选择其中一对按键和LED灯,按键选择连接的FPGA引脚为M2,LED灯选择连接的FPGA引脚为L7。
点击如图8-80所示按钮,打开引脚绑定界面。
图8-80 打开引脚绑定界面
打开后的界面如图8-81所示。
图8-81 引脚分配图
在数目比较少的情况下,有两种绑定引脚的方法(引脚数目特别多的时候用其他方法,后面会单独介绍),一种是在的“Location”列“key_in”行输入“M2”,在“led_out”行输入“L7”然后按Enter键确定,如图8-82所示。
图8-82 通过“Location”列绑定引脚
另一种方法是直接将图8-83所示的信号的名称拖动到图8-84所示的需要绑定的引脚上即可。
图8-83 选中信号名称
图8-84 将信号名称拖动到要绑定的引脚
绑定完后的引脚状态如图8-85所示,其中:
▪ Node Name:RTL代码中定义的端口名称。
▪ Direction:引脚的输入输出方向。
▪ Location:引脚绑定的位置。
▪ I/O Bank:用于支持对应不同的电平标准,即VCCIO。每个Bank只能有一种电压标准,一般情况下选择默认值即可。一种颜色下的I/O端口代表一组Bank。当引脚的Location约束完成以后,I/O Bank会自动进行填充。
▪ VREF Group:Bank内部的细分区域,非修改属性,会自动填充。
▪ I/O Standard:对引脚内部的I/O进行不同的电平约束。FPGA I/O的电压由I/O Bank上的VCC引入,一个Bank上如果引入了3.3V的TTL电平,那么此时整个Bank上输出3.3V的TTL电平。设置好以后,可以结合Current Strength一起计算功率。如果没有特殊要求,保持默认设置即可。
▪ Reserved:用于对引脚内部I/O端的输入输出区域的逻辑进行约束,无特殊要求时可以为空。
▪ Current Strength:驱动电流强度,一般选择默认值。如果需要驱动大功率的电路,可以在FPGA外围加驱动电路。
▪ Slew Rate:电压转换速率,表示单位时间内电压升高的幅值,与信号跳变时间有关,一般选择默认值。
▪ Differential Pair:差分引脚。
▪ Filter:通过过滤选项显示指定种类的引脚。
所有引脚配置完成后,就可以关闭当前界面了。
图8-85 引脚状态
8.3.17 全编译
全编译(Start Compilation)与分析综合(Start Analysis & Synthesis)是有区别的,分析与综合是全编译的一部分,全编译是在分析与综合的基础再进行布局布线操作。要注意在上板验证之前一定要进行全编译,否则无法将RTL代码设计的电路映射到FPGA芯片中。点击如图8-86所示的按钮进行全编译。
图8-86 点击按钮进行布局布线
如图8-87所示:
① 框是综合后的资源使用率报告。
② 框是综合后提示的错误警告数,这里没有错误,只有警告和严重警告,共有7个。
③ 框是编译时每一步的详细过程,包括执行每一个部分所使用的具体时间,从上到下顺序执行,第一个是之前进行过的分析与综合,第二个是布局和布线,第三个是生成程序文件,第四个是静态时序分析,第五个是写入网表,这五个步骤编译后都是自动完成的,不需要进行干涉,如果自动完成的不能满足后期需求,则需要进行手动设置以实现优化。
④ 框中从左向右依次是“错误”“严重警告”“警告”按钮,只要不出现错误,就暂时不用管,当警告或者严重警告影响功能时再去分析。
图8-87 编译界面说明
⑤ 框是编译的总进度。
⑥ 框是在编译过程中实时显示的时间,该时间随着工程量的增大而增大,硬件编译一次的时间是非常慢的,不像软件那样瞬间就完成了,这也是需要进行仿真的原因之一。
我们故意设置一个错误:将第8行key_in后面的分号去掉,如图8-88所示,再进行综合。
图8-88 设置一个错误
编译后的结果如图8-89所示:
图8-89 分析错误提示
① 框中提示有三个错误,但事实上我们只修改了一处,提示的错误数与实际存在的错误数并不一定一致,所以当提示有很多错误时不要担心,很可能你修改了一处后错误就会减少很多,经验再多的工程师写代码时也难免会出现语法错误,初学者犯语法错误的更是常见的事情,凡是这种由语法导致的错误都是最容易修改的。
② 框处前面会有一个“×”,因为有语法错误,所以分析和综合失败。
③ 框处是具体的错误提示,此处提示第9行附近有错误,双击该错误提示语句就会立刻定位到错误位置附近,但我们发现第9行没有问题,那就是第9行之前有问题,我们在第8行发现key_in后面缺少一个分号,所以添加上分号再重新编译即可。
8.3.18 通过JTAG将网表下载到开发板
如图8-90所示,开发板连接12V直流电源,USB-Blaster下载器JTAG端连接开发板JTAG接口,另一端连接计算机的USB接口。线路连接正确后,打开开关为板卡上电。
图8-90 程序下载连线图
点击图8-91所示的图标,打开下载界面,如图8-92所示:
图8-91 打开下载界面
图8-92 下载界面说明
①框表示硬件连接设置,当前显示的是“No Hardware”,即没有连接到硬件,我们需要选择连接的硬件是USB-Blaster,点击“Hardware Setup...”,在弹出的界面(见图8-93)中的“Currently selected hardware:”中选择“USB-Blaster[USB-0]”,然后点击“Close”按钮,此时会发现①框处发生变化,如图8-94所示,“Hardware Setup...”处已经变成了“USB-Blaster[USB-0]”;②框用于选择下载的方式,我们选择“JTAG”下载模式;③框为下载进度表,下载成功后会在框内显示绿色并出现“100%(Successful)”;④框是下载的文件,这里是“led.sof”文件。
图8-93 选择连接的硬件
图8-94 成功选择“USB-Blaster[USB-0]”
如图8-95所示,若没有“.sof”文件,点击“Add File...”按钮,选择“led\quartus_prj\output_files”路径下的“led.sof”后点击“Open”按钮,如图8-96所示。
图8-95 点击“Add File...”按钮
图8-96 添加“led.sof”文件
当设置完所有下载项后,即可点击图8-97所示的“Start”按钮,然后等待下载完成,这一过程所用时间很短,下载完成后发现“Progress:”处显示为绿色,并出现如图8-98所示的“100%(Successful)”提示,说明下载成功。
图8-97 点击“Start”按钮开始下载文件
图8-98 文件下载成功
下载完成后即可按下引脚绑定的按键,会发现同时被绑定的LED灯随着按键的按下会被点亮,而按键松开时又熄灭,实现了我们最初预想的设计,如图8-99所示。
图8-99 上板效果图
注意:尽量不要带电插拔JTAG口,否则容易烧坏FPGA的JTAG口。如果用万用表测到JTAG口TDI、TDO、TMS、TCK中的任意一个与地短路了,那你的FPGA可能已经被烧坏了。并不是每次进行热插拔都一定会烧坏JTAG端口,但是至少会有烧坏的可能性,为了能让开发板陪伴我们完成对本书的学习,所以要谨慎行事!
8.3.19 未使用引脚的默认设置
我们使用的开发板有很多功能,在实现一个个例子的时候不可能同时用到所有的FPGA引脚,而在Quartus软件中默认未使用引脚的状态为弱上拉输入,所以未用到的引脚上也是有电压的,只是驱动能力很弱,这往往会导致一些不安全的隐患,所以我们需要将未使用引脚的状态设置为三态输入。具体操作如下:
如图8-100所示,右击“Cyclone IV E: EP4CE10F17C8”,选择“Device...”命令打开Device对话框。
图8-100 选择“Device...”命令打开Device对话框
在打开的对话框(见图8-101)中点击“Device and Pin Options...”按钮。
图8-101 点击“Device and Pin Options...”按钮
在打开的对话框(见图8-102)中选择“Unused Pins”选项,在“Reserve all unused pins:”框中发现默认的设置是“As input tri-stated weak pull-up”,即弱上拉输入,意思是所有没有被定义的引脚都可以作为输入引脚,并附加弱上拉电阻。
图8-102 设置“Unused Pins”选项
在“Reserve all unused pins:”框中选择“As input tri-stated”,即三态输入,然后点击“OK”按钮完成设置,如图8-103和图8-104所示。在本例中,默认选项“As input tri-stated with week pull-up”是一个安全的选项,除此之外,“As input tri-stated”等也是安全选项,但是“As output driving ground”是一个危险选项,意思是未用到的FPGA引脚会被下拉到地。危险之处在于如果这些引脚在被PCB上的外围电路上拉到高电位,则可能会产生一个强烈的灌入电流,烧毁FPGA的引脚。因此为了避免经济损失,无论如何,请你注意这里的选择,不要莫名其妙地把FPGA烧坏了。
图8-103 选择“As input tri-stated”选项
图8-104 设置成功
未使用的引脚状态设置完成后需要重新编译才能够进行映射。点击全编译按钮会弹出一个对话框,当下载界面被修改(见图8-105)或者关闭时(见图8-106)会提示是否保存原下载界面的设置,这里我们不保存,所以点击“No”按钮,如果需要保存,则点击“Yes”按钮后重命名并备注好即可。
图8-105 下载界面被修改时的提示框
图8-106 下载界面被关闭时的提示框
8.3.20 程序的固化
为什么下载网表后还要再进行固化呢?当你把下载网表的上板断电后再重新上电,发现之前的功能已经不存在了,也就是说下载后的网表消失了。为什么会这样呢?其实我们使用的这款FPGA芯片是基于SRAM结构的,即下载后的网表存储在FPGA内部的SRAM中,我们也知道SRAM有掉电易失的特性,这也是掉电后功能就消失的原因。所以要想使网表重新上电后仍然存在,就需要将网表存储到片外的flash中,flash芯片的型号为WinBond 25Q16,存储容量为16Mbit(2MB),采用SPI协议和FPGA进行通信,可作为FPGA的配置芯片(完全兼容EPCS16芯片),以保证FPGA在重新上电后仍能继续工作。具体操作如下:
选择“File”下的“Convert Programming Files...”命令,如图8-107所示。
图8-107 选择“File→Convert Programming Files...”命令
打开后的界面如图8-108所示。
图8-108 打开的界面
“Programming file type:”栏用于选择输出文件的类型,我们选择“JTAG Indirect Configuration File(.jic)”,如图8-109所示。
图8-109 设置“Programming file type:”栏
“Configuration device:”栏是flash的型号,我们选择“EPCS16”,如图8-110所示。
图8-110 设置“Configuration device:”栏
如图8-111所示,“File name:”栏用于选择输出.jic文件的位置,此处选择“led\quartus_ prj\output_files”,并将文件重命名为“led.jic”。
图8-111 设置“File name:”栏
如图8-112所示,点击“Input files to convert”框中的“Flash Loader”后,会发现“Add Device...”从不能被选择的状态变为可以被选择,点击“Add Device...”按钮。
图8-112 点击“Add Device...”按钮
如图8-113所示,选择我们使用的FPGA芯片所属的型号,在“Device family”框中勾选“Cyclone IV E”复选框,在“Device name”框中勾选“EP4CE10”复选框,然后点击“OK”按钮。添加后如图8-114所示。
图8-113 选择FPGA芯片型号
图8-114 添加FPGA芯片型号成功
如图8-115所示,点击“Input files to convert”框中的“Sof Data”后,会发现“Add File...”可以被选择,点击“Add File...”按钮。
图8-115 点击“Add File...”按钮
因为“led.jic”文件的生成需要“led.sof”文件的参与,所以选择路径“led\quaruts_prj\output_files”下的“led.sof”文件后点击“Open”按钮,如图8-116所示。
图8-116 添加“led.sof”文件
选择“led.sof”文件后如图8-117所示,然后点击“Generate”按钮生成“led.jic”文件。
图8-117 生成“led.jic”文件
如图8-118所示,“led.jic”文件生成成功,点击“OK”按钮。
图8-118 “led.jic”文件生成成功
点击“Close”按钮关闭该窗口,如图8-119所示。
图8-119 关闭窗口
回到下载界面,右击“led.sof”,选择“Delete”命令将其删除,如图8-120所示。
图8-120 删除“led.sof”
点击“Add File...”按钮,将“led.jic”文件添加进来,如图8-121所示。
图8-121 准备添加“led.jic”文件
如图8-122所示,选择“led\quartus_prj\output_files”路径下的“led.jic”文件,然后点击“OK”按钮。
图8-122 添加“led.jic”文件
如图8-123所示,先勾选“Program/Configure”下的方框,然后点击“Start”按钮进行程序的固化。
图8-123 进行程序固化
如图8-124所示,下载的进度较之前明显慢很多,所以我们在平时调试的时候可以不固化程序,等所有的工作都完成后,再把完成的程序固化到开发板中即可。
图8-124 显示固化进展