2. Vivado开发环境搭建:Vivado安装与配置、创建第一个Zynq工程、硬件描述语言基础回顾
好,咱们正式开始动手了。
这一章,说白了就是“磨刀”。工欲善其事,必先利其器。Vivado就是我们做Zynq开发的那把刀。我见过不少新手,一上来就急着写代码,结果环境没配好,编译报错折腾半天,心态直接崩了。所以,咱们先把刀磨快,后面才能砍柴不费劲。
2.1 Vivado安装与配置
安装Vivado其实不复杂,但有几个坑我得提前跟你说。我个人习惯,安装前一定先看一遍官方Release Notes,虽然文档又臭又长,但里面会写明哪些操作系统版本有已知问题。嗯,这一步能省你后面很多麻烦。
2.1.1 下载与安装
去Xilinx官网下载Vivado HLx版本。注意,现在AMD接手后,下载流程稍微变了一下,但核心没变。你选“Vivado HL WebPACK”就够了,除非你要搞VU9P那种大芯片。WebPACK是免费的,支持Zynq-7000全系列。
- 安装包大小:完整版大概50-70GB,WebPACK小一些,但也得30GB+。硬盘留够空间。
- 安装选项:勾选“Vivado HL WebPACK”和“Zynq-7000”器件支持。其他的像SDAccel、DocNav,新手可以先不装。
- 安装路径:千万别有中文!千万别有空格!我吃过这个亏,当年装到“Program Files (x86)”里,结果License死活认不到。
2.1.2 License配置
Vivado需要License才能用。WebPACK版本是免费的,你只需要在Xilinx官网申请一个Node-Locked License,绑定你电脑的MAC地址就行。
- 打开Vivado License Manager。
- 选择“Load License”。
- 导入你下载的.lic文件。
搞定之后,你可以在“Help” -> “About Vivado”里看到License状态。如果显示“WebPACK”,那就对了。
2.2 创建第一个Zynq工程
环境搭好了,咱们来建个工程。别怕,就是点几下鼠标的事。我带你走一遍,你跟着做就行。
2.2.1 新建工程
打开Vivado,点击“Create Project”。
- Project Name:我建议用“led_test”这种简单名字,别搞花里胡哨的。
- Project Location:同样,路径不要有中文。
- Project Type:选“RTL Project”。勾选“Do not specify sources at this time”,后面再加。
然后选择器件。这里要注意,你得选对Zynq型号。比如你用的是Zynq-7020,那就搜“xc7z020”。别选错了,否则后面综合会报错。
2.2.2 添加源文件
工程建好了,咱们写个最简单的Verilog代码,点个灯。
右键“Sources” -> “Add Sources” -> “Add or create design sources”。创建一个新文件,叫“led.v”。
module led (
input wire clk,
input wire rst_n,
output reg led_out
);
reg [31:0] counter;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 32'd0;
led_out <= 1'b0;
end else begin
if (counter == 32'd50_000_000) begin // 假设时钟50MHz,1秒翻转一次
counter <= 32'd0;
led_out <= ~led_out;
end else begin
counter <= counter + 1'b1;
end
end
end
endmodule
这段代码很简单,就是一个计数器,每5000万次时钟周期翻转一次LED。说白了,就是让LED以1Hz的频率闪烁。
2.2.3 添加约束文件
代码写好了,你得告诉Vivado,你的LED接在哪个管脚上。这就需要约束文件(XDC)。
同样,右键“Constraints” -> “Add Sources” -> 创建“led.xdc”。
set_property PACKAGE_PIN M14 [get_ports led_out]
set_property IOSTANDARD LVCMOS33 [get_ports led_out]
set_property PACKAGE_PIN K17 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN L15 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
这里的管脚号你得查你的板子原理图。我上面写的M14、K17、L15是某款开发板的例子,别直接抄。
2.2.4 综合、实现、生成比特流
一切就绪,点击“Run Synthesis”。综合完成后,点击“Run Implementation”。最后“Generate Bitstream”。
这个过程可能需要几分钟。你可以去泡杯咖啡。如果报错,别慌,看错误信息。90%的错误都是管脚约束写错了,或者代码有语法问题。
2.3 硬件描述语言基础回顾
我知道,有些同学可能Verilog忘得差不多了。咱们快速过一遍核心概念。你不需要成为Verilog高手,但基础语法得会看会写。
2.3.1 模块与端口
Verilog的基本单元是module。每个模块都有输入输出端口。就像我们刚才写的led模块一样。
module 模块名 (
input wire 端口1,
output reg 端口2,
inout wire 端口3
);
// 内部逻辑
endmodule
注意,wire和reg的区别。简单说:wire是连线,reg是寄存器。在always块里赋值的变量,必须是reg类型。
2.3.2 组合逻辑与时序逻辑
这是FPGA设计的核心概念。
- 组合逻辑:输出只取决于当前输入。用
assign或always @(*)实现。 - 时序逻辑:输出不仅取决于当前输入,还取决于之前的状态。用
always @(posedge clk)实现。
我刚开始学的时候,总把组合逻辑和时序逻辑混在一起写。结果仿真没问题,上板就跑飞了。后来才明白,时序逻辑一定要有时钟沿触发,组合逻辑不能有寄存器。
2.3.3 阻塞赋值与非阻塞赋值
这个坑,几乎每个FPGA工程师都踩过。
- 阻塞赋值(=):顺序执行,前面的赋值会立即影响后面的语句。用于组合逻辑。
- 非阻塞赋值(<=):并行执行,所有赋值在时钟沿同时更新。用于时序逻辑。
记住一个口诀:“组合用等号,时序用小于等于”。我曾经在同一个always块里混用了两种赋值,结果综合出来的电路和我想的完全不一样,查了两天才找到原因。
2.3.4 参数化设计
用parameter可以让你的代码更灵活。比如我们刚才的计数器,可以把计数上限做成参数。
module led #(
parameter CNT_MAX = 32'd50_000_000
) (
input wire clk,
input wire rst_n,
output reg led_out
);
// 内部逻辑不变,只是把50_000_000换成了CNT_MAX
endmodule
这样,以后你要改闪烁频率,只需要改参数,不用改代码逻辑。我在项目中经常用这个技巧,尤其是做IP核封装的时候,非常方便。
本章小结
这一章,我们完成了Vivado的安装配置,创建了第一个Zynq工程,并且回顾了Verilog的核心基础。你想想看,其实FPGA开发没那么神秘,就是写代码、加约束、跑流程。后面我们会在这个基础上,一步步加入图像处理的逻辑。
嗯,环境搭好了,代码也能跑了,接下来就该玩点真格的了。