“quick start — create project” 或者 “file—project—new”
根据自己的需要选择一款FPGA开发板:
进入开发界面,最左侧为流程导航栏(flow navigator),完整的开发工作可按照该栏中的个步骤执行。这里先略过IP部分。右侧为工程管理界面。
在流程导航(flow navigator)中点击“Adding Sources”,可添加三种源文件——设计源文件、仿真源文件、约束文件。
设计源文件是实现特定功能的代码,像一个“函数”,有输入和输出。代码负责对输入进行运算和分析(算术运算和逻辑运算),得到输出,如:y=f(x),其中x是输入,y是输出。同一个工程项目可以有多个源文件,源文件之间可以相互调用,这一点和C语言类似,这里不作具体介绍。
我们首先添加一个设计源文件,这里命名为d_latch是因为要实现的功能为一个锁存器。暂时不设置I/O端口。添加后可以在下面的Sources窗格中看到多了一个设计源文件d_latch.v
双击设计源文件d_latch.v,输入如下代码(第一行在文件生成时已经给出):
`timescale 1ns / 1ps
module d_latch(d, clk, q); // 定义模型d_latch
input d; // 输入:控制信号d
input clk; // 输入:时钟信号clk
output q; // 输出:q
reg q; // 声明q为寄存器类型(表示可修改)
always @ (d, clk) // 时序电路,反复执行
if(clk) // 如果时钟信号为高
q <= d; // 将 d 阻塞赋值给 q
endmodule
上述代码的功能是:当时钟信号为高时,输出q的值与输入d的值相等,否则输出q的值保持不变,这便是基本的锁存器功能。
用于验证“设计源文件”的正确性的代码,即判断“设计源文件”能否实现所需要的功能。给出一系列具体的x的值,调用“设计源文件”中的module,查看输出的y是否满足y=f(x)。
添加仿真源文件d_latch_tb.v(这里后缀tb表示test bench,可以令取任意符合语法要求的文件名),添加如下代码:
`timescale 1ns / 1ns
module d_latch_tb;
reg clk, d;
wire q;
d_latch u1(.d(d), .clk(clk), .q(q));
initial
begin
clk = 1;
d <= 0;
forever
begin
# 60 d <= 1; // 人为生成毛刺
# 22 d <= 0;
# 2 d <= 1;
# 2 d <= 0;
# 16 d <= 0; // 维持16ns的低电平,然后让它作周期性的循环
end
end
always #20 clk <= ~clk; // 时钟半周期为20ns,全周期为40ns
endmodule
在实际应用中,需要将上面的module放到FPGA硬件中(即烧写),由于实现module的功能需要以实际的端口作为基础,故应当在烧写之前根据FPGA的端口信息设定好程序的x和y对应的物理接口。实现这一点一般需要知道FPGA的IO引脚功能信息,但是Vivado提供了“自动设置”的功能,初学者可以借此快速设置,方便学习使用。(这一部分后面再添加)
在添加仿真源文件之后,就可通过仿真行为来检验源文件是否存在问题。
可以在工作区看到仿真的时序波形:
可以看出输出和输入均符合要求(如果不符合要求,则说明代码可能有问题):
在进行完下面的综合(synthesis)和应用(implementation)之后,均可以进行仿真,其中后者更为重要,一般会观察到和行为仿真不同的结果,结果中存在一定的延迟。
通过RTL分析,可以查看自动生成的与d_latch.v对应的数字电路
用于对工程进行综合,具体含义为:将上述代码功能与实际的FPGA可支持的功能进行综合,综合后查看synthesis下面的schematic可以发现电路使用的模块与上面那张图有所不同(使用的元件全部源于FPGA开发板本身)。
点击左侧流程栏中的Implementation,进行应用操作,该过程将进一步对源文件和FPGA进行综合,给代码中的变量分配具体的引脚。如果之前没有进行任何约束设置(constraint),则该过程将自动为工程项目分配引脚:
由于上面的引脚分配仅仅是临时的,我们应当进行保存。勾选上图中每个端口的Fixed,将端口锁定,ctrl+s快捷键保存,会自动询问是否要保存该临时约束文件,给约束文件命名(这里命名为d_latch_IO),点击OK
可以发现source栏中多出了一个d_latch_IO.xdc文件,即为约束文件
双击打开该文件后可发现其中的具体端口约束代码。
注:本小节与6-1小节是并列关系,都可实现约束文件的添加。
其实在implementation之前,便可以自行新建约束文件,在文件中添加上述代码也可(或者点击window中的package,可手动添加引脚)。如果不知道FPGA具体的引脚信息,则可以使用自动分配引脚的方法。下面具体介绍该方法:
点击左边侧栏中Synthesis中的Open Synthesized Design,此时可在顶部工具栏的Window点开I/O port,I/O端口信息会在屏幕底部显示,此时还没有分配引脚
在栏目内右击,点击Autoplace I/O Ports,
可见端口已经自动分配,但这只是临时的,要想固定这一选择,可以点击Fixed(打对号),然后ctrl+s保存,
选择一个已存在的文件,即之前创建好的d_latch_IO.xdc空文件
点击Reload重新加载:
就得到了和6-1中一样的结果:
应用到FPGA之后,从下图可以看出,仿真结果出现延时,但基本的功能仍然支持。
出现失败!
原因是我使用了默认的I/O端口初始值,I/O Std 显示为Default(LVCMOS18),我们要确定选择LVCMOS18才可以(改成如下图所示),ctrl+s保存,重写约束文件,
发现多了三行约束代码:
然后重新跑Implementation和Generagte Bitstream,即可顺利生成比特流文件。
如果不想从头开始写一个I/O端口约束文件,而是在原本的基础上更改,可以参考下述步骤:
1、打开 Open Synthesis Design 或 Open Implementation Design,两者都可。这时,可以在软件顶部点击Window—>I/O Ports,则I/O Ports会在屏幕底部出现。
【注意:I/O Ports的最左侧栏可以拉开并显示代码中定义的名称】
2、选择需要更改的I/O端口对应的Package Pin,选择所需的端口(Package速览方法:Window—>Package),点击Fixed,并紧接着ctrl+s保存,弹出文件已更改的提示窗口点击OK,右弹出如下窗口,提示保存新的约束Constraint。
【1】如果之前没有创建Constraint文件,或者想要新建一个约束文件夹,则可以由此创建。
【2】如果已经有Constraint文件,则可以选择Overwrite,如下图所示,即对文件夹constrs_1进行重写。重写之后,关闭文件夹constrs_1中的约束文件(如果之前一直打开着的话),并重新打开,则可以发现端口已经更改。