xilinx Vivado的使用详细介绍(2):创建工程、添加文件、综合、实现、管脚约束、产生比特流文件、烧写程序、硬件验证
xilinx Vivado的使用详细介绍(2):创建工程、添加文件、综合、实现、管脚约束、产生比特流文件、烧写程序、硬件验证
Author:zhangxianhe
新建工程
打开Vivado软件,直接在欢迎界面点击Create New Project,或在开始菜单中选择File - New Project即可新建工程。
点击Next;
输入工程名称和路径。
选择默认的RTL Project选项,勾选Do not specify......(这样可以跳过添加源文件的步骤,源文件可以后面再添加)。
直接选择Boards,然后选择Zedboard Zynq Evaluation and Development Kit 硬件开发包。
点击Next,再点击Finish,项目新建完成
添加Verilog设计文件(Design Source)
在Project Manager窗口中,右击选择Design Sources,在空白处或任意文件夹上右击,选择Add Sources。
选择Add or Create Design Sources,点击Next。
点击Create File按钮,弹出的小窗口中输入文件名,点击OK。
可以一次性新建或添加多个文件,最后点击Finish。
稍后会弹出定义模块的窗口,也就是刚刚添加的Divider_multiple文件。可以在这里设置Divider_multiple模块的输入输出端口;或者直接点击OK,稍后再自行编写。
点击OK后,如果弹出下面窗口直接点击Yes。
设计文件和对应的模块即创建完成,如下图。
打开Divider_multiple设计文件,并把如下代码复制进去,并保存。
module Divider_Multiple_top( input clk_i, input rst_n_i, output div2_o, output div3_o, output div4_o, output div8_o, output div2hz_o ); reg div2_o_r; always@(posedge clk_i or negedge rst_n_i) begin if(!rst_n_i) div2_o_r<=1'b0; else div2_o_r<=~div2_o_r; end reg [1:0] div_cnt1; always@(posedge clk_i or negedge rst_n_i) begin if(!rst_n_i) div_cnt1<=2'b00; else div_cnt1<=div_cnt1+1'b1; end reg div4_o_r; reg div8_o_r; always@(posedge clk_i or negedge rst_n_i) begin if(!rst_n_i) div4_o_r<=1'b0; else if(div_cnt1==2'b00 || div_cnt1==2'b10) div4_o_r<=~div4_o_r; else div4_o_r<=div4_o_r; end always@(posedge clk_i or negedge rst_n_i) begin if(!rst_n_i) div8_o_r<=1'b0; else if((~div_cnt1[0]) && (~div_cnt1[1])) div8_o_r<=~div8_o_r; else div8_o_r<=div8_o_r; end reg [1:0] pos_cnt; reg [1:0] neg_cnt; always@(posedge div2_o_r or negedge rst_n_i) begin if(!rst_n_i) pos_cnt<=2'b00; else if(pos_cnt==2'd2) pos_cnt<=2'b00; else pos_cnt<=pos_cnt+1'b1; end always@(negedge div2_o_r or negedge rst_n_i) begin if(!rst_n_i) neg_cnt<=2'b00; else if(neg_cnt==2'd2) neg_cnt<=2'b00; else neg_cnt<=neg_cnt+1'b1; end reg div3_o_r0; reg div3_o_r1; always@(posedge div2_o_r or negedge rst_n_i) begin if(!rst_n_i) div3_o_r0<=1'b0; else if(pos_cnt<2'd1) div3_o_r0<=1'b1; else div3_o_r0<=1'b0; end always@(negedge div2_o_r or negedge rst_n_i) begin if(!rst_n_i) div3_o_r1<=1'b0; else if(neg_cnt<2'd1) div3_o_r1<=1'b1; else div3_o_r1<=1'b0; end reg div2hz_o_r; reg [25:0] div2hz_cnt; always@(posedge clk_i or negedge rst_n_i) begin if(!rst_n_i) div2hz_cnt<=0; else if(div2hz_cnt<26'd50_000000) div2hz_cnt<=div2hz_cnt+1'b1; else div2hz_cnt<=0; end always@(posedge clk_i or negedge rst_n_i) begin if(!rst_n_i) div2hz_o_r<=0; else if(div2hz_cnt==26'd24_999999 || div2hz_cnt==26'd49_999999) div2hz_o_r<=~div2hz_o_r; else div2hz_o_r<=div2hz_o_r; end assign div2_o=div2_o_r; assign div3_o=div3_o_r0 | div3_o_r1; assign div4_o=div4_o_r; assign div8_o=div8_o_r; assign div2hz_o=div2hz_o_r; endmodule
添加Verilog仿真文件(Simulation Source)
操作和上一步添加Verilog设计文件基本一致,唯一的区别是选择Add or Create Simulation Sources。新建一个名为Divider_Multiple_TB的仿真文件。
设计文件新建完成后,在Design Sources和Simulation Sources中都有,而仿真文件只会出现在Simulation Sources文件夹中。设计文件可以用于仿真,也可以用于最终烧写进开发板,而仿真文件仅用于仿真。
双击打开Divider_Multiple _TB仿真文件,并把如下代码复制进去,并保存。
module Divider_Multiple_TB; // Inputs reg clk_i; reg rst_n_i; // Outputs wire div2_o; wire div3_o; wire div4_o; wire div8_o; wire div2hz_o; // Instantiate the Unit Under Test (UUT) Divider_Multiple MyDivider_Multiple ( .clk_i(clk_i), .rst_n_i(rst_n_i), .div2_o(div2_o), .div3_o(div3_o), .div4_o(div4_o), .div8_o(div8_o), .div2hz_o(div2hz_o) ); initial begin // Initialize Inputs4 clk_i = 0; rst_n_i = 0; // Wait 100 ns for global reset to finish #96; rst_n_i=1; end always begin #5 clk_i=~clk_i; end endmodule
IO口配置(I/O Planning)/编辑约束文件(Edit Constraints Sets)
做好的模块,在烧写进板子之前,需要设置输入输出信号与板子上IO口的对应关系。
IO口设置有两种方法,第一种是直接创建并编辑约束文件,第二种是在图形界面进行设置。
编辑约束文件
操作和上一步添加Verilog设计文件、仿真文件基本一致,唯一的区别是选择Add or Create Simulation Sources。新建一个名为Zedboard_pin的约束文件。
打开Zedboard_pin的约束文件,并把如下代码复制进去。
create_clock -name clk100MHZ -period 10.0 [get_ports {clk_i}] set_property PACKAGE_PIN Y9 [get_ports {clk_i}] set_property IOSTANDARD LVCMOS33 [get_ports {clk_i}] set_property PACKAGE_PIN N15 [get_ports {rst_n_i}] set_property IOSTANDARD LVCMOS18 [get_ports {rst_n_i}] set_property PACKAGE_PIN T22 [get_ports {div2hz_o}] set_property IOSTANDARD LVCMOS33 [get_ports {div2hz_o}] set_property PACKAGE_PIN T21 [get_ports {div8_o}] set_property IOSTANDARD LVCMOS33 [get_ports {div8_o}] set_property PACKAGE_PIN U22 [get_ports {div4_o}] set_property IOSTANDARD LVCMOS33 [get_ports {div4_o}] set_property PACKAGE_PIN U21 [get_ports {div3_o}] set_property IOSTANDARD LVCMOS33 [get_ports {div3_o}] set_property PACKAGE_PIN V22 [get_ports {div2_o}] set_property IOSTANDARD LVCMOS33 [get_ports {div2_o}]
图形界面配置管脚
在实现完成后,Open Implemented Design选项从灰色变成可点击状态。
点击Open Implemented Design,即可打开Implemented Design窗口。
在I/O Ports窗口展开管脚,对于每个输入输出信号,在Site栏选择对应的管脚,注意确保Fixed栏处于勾选状态,I/O Std常选择LVCMOS33。
设置好后,Implemented Design窗口标题栏会显示一个*号,表示设置发生了更改。
按Ctrl+S快捷键保存设置,会弹出窗口如图,提示保存constraints文件会导致综合与实现过期。也就是说,修改了管脚分配设置后,需要重新进行综合、实现操作。这里点击OK。
弹出窗口,选择Create a new file并输入文件名,点击OK。
此时约束文件已经自动被创建并编辑,可以打开查看。
行为仿真(Run Behavioral Simulation)
在Flow Navigator窗口中点击Run Simulation - Run Behavioral Simulation;或者在菜单中选择Flow - Run Simulation - Run Behavioral Simulation,即可启动行为仿真。
稍后Behavioral Simulation窗口打开,即可看到输出的仿真波形。
综合(Synthesis)
综合类似于编程中的编译。
在Flow Navigator或Flow菜单中,选择Synthesis - Run Synthesis;或点击工具栏中的三角形按钮如图,即可开始对设计文件进行综合。
综合完成后,会弹出如下窗口。如果选择第一项并点击OK,就会启动下一步的实现。为了方便学习,这里我们直接点击Cancel。
综合后时序仿真(Run Post-Synthesis Timing Simulation)
在Flow Navigator窗口中点击Run Simulation - Run Post-Synthesis Timing Simulation;或者在菜单中选择Flow - Run Simulation - Run Post-Synthesis Timing Simulation,即可启动行为仿真。
观察波形可以清晰看到综合后仿真加入了延迟更加接近实际芯片的运行情况
执行(Implementation)
综合完成后,需要进行实现,在Flow Navigator或Flow菜单中,选择Synthesis - Run Implementation;或点击工具栏中的三角形按钮如图,即可开始对设计文件进行综合。实际中是在综合后没有错误直接点Run Implementation选项进行实现。
实现完成后,同样会出现一个窗口如下。选择第一项可以打开下一步的IO口设置界面,选择第二项可以启动后面要说的生成比特流操作。同样,这里还是点击Cancel关闭。
执行后时序仿真(Run Post-Implementation Timing Simulation)
观察波形可以清晰看到布局布线后仿真加入了延迟这要比综合后的时序更加接近真实的情况。
生成比特流
生成比特流文件,这个文件会被直接烧写进板子。类似于编程中的二进制可执行文件。点击Program and Debug->Generate Bitstream。或下图的上面图标即可执行生成比特流的操作。
比特流生成后显示如下对话框,为了方便直接点击Cancel。
烧写程序
连接电路板并打开电源。 生成比特流,打开硬件会话并编程FPGA。
确保Micro-USB电缆连接到Zedboard的电源连接器旁边的JTAG PROG连接器。
Zedboard需要通过位于POWER开关旁边的J20连接一个单独的电源。
选择Program and Debug - Open Hardware Manager。
如果之前连接过开发板,直接点击上方绿色栏的Open recent target即可打开;如果是第一次连接开发板,则点击Open a new hardware target。
第一次连接开发板,点击Open a new hardware target,点击Next
还是点击Next。
显示下面窗口,稍后即可打开硬件设备。
\
由于我以前连接过开发板,所以直接连接开发板。
Hardware Manager窗口即被打开,此时处于”Unconnected”状态。
单击Open target,在下面出现的菜单中选择 Auto Connect。
硬件会话状态从“Unconnected”更改为服务器名称,设备突出显示。 还要注意状态表明它没有被编程。
打开设备后,就会在Hardware窗口显示。右击设备并选择Program Device,进行Program。
或者直接点击绿色栏的Program Device进行Program。
弹出比特流文件选择窗口,一般直接按默认值点击Program,即可烧写程序到板子中。
本实验介绍了VIVADO 的FPGA 开发流程规范。包括了程序设计、行为仿真、综合过程、综合后时序仿真、执行过程、执行后仿真,比特流文件生成并下载到开发板上验证。
注意点一:
在vivado下建立工程,有以下几种情况:1.如果没有涉及到PS部分,可以采用基于v文件或者diagram的工程。基于v文件的工程是由一个个的verilog或vhdl或ip组成的;基于diagram的工程是先新建一个diagram,然后在diagram中添加一个个的ip。2.如果用到了PS,那只能采用基于diagram的工程。
PS和PL的关系:PS的实质就是ARM Cortex A9 MPcore,所以如果我们不使用可编程部分,我们完全可以只使用PS部分。也就是说,对于ZYNQ芯片,PS部分可以完全独立使用,不依赖PL部分。PL部分的实质是Xilinx FPGA。在ZYNQ中,我们可以把PL看成是PS的另一个具有可重配置特点的“外设”,它可以作为PS部分的一个从设备,受ARM处理器控制。比如ARM(PS)的串口数量不够时,以太网接口不够时,或者需要视频接口时都可以用PL部分扩展。当然我们也可以把PL部分看成一个不受ARM处理器控制,与ARM处理器对等的主设备,主动完成与外部芯片、接口的数据交互。更甚至PL部分也可以作为整个系统的主设备,主动从APU部分的存储器中获取、存储数据,并可控制ARM处理器的运算。所以,理论上PL部分也可以像PS部分那样独立运行。但限制是必须使用JTAG接口对PL部分进行配置。如果没有JTAG接口,就无法独立运行,因为ZYNQ的PS部分和PL部分都必须依靠PS来完成芯片的初始化配置。
注意点二:
PS核与PL的IP之间通信方式只有一种,那就是通过AXI总线。AXI interconnect IP是一个功能强大的IP,它能管理多个AXI接口的IP。用户如果用到多个AXI IP,那么只需PS将M_AXI_GP0引脚连接到AXI interconnect Ip的SO0_AXI引脚,再将AXI interconnect ip的输出分别连接到每个AXI IP的S_AXI引脚即可,省去了多个AXI互联的管理问题。Processor System Reset IP为其他IP提供复位信号。