2、Vivado HLS工具入门:工具安装与环境配置、创建第一个HLS项目、理解HLS工程结构
好,咱们正式开始动手了。这一章我带你走一遍 Vivado HLS 的完整入门流程。说实话,很多初学者卡在第一步——工具装好了,但不知道点哪里。别急,我当年也踩过这个坑。
2.1 工具安装与环境配置
先聊聊安装。Vivado HLS 是 Xilinx 家的工具,现在叫 Vitis HLS 了,但核心逻辑没变。我个人习惯用 2019.1 或 2020.1 版本,稳定,坑少。
安装前你要知道的事
- 操作系统:Windows 10/11 或 Ubuntu 18.04/20.04 都行。我建议用 Linux,编译速度快不少。
- 硬盘空间:至少 50GB 空闲。别问我怎么知道的——我第一次装完发现 C 盘爆了。
- 内存:16GB 起步。如果你跑大一点的工程,32GB 更稳。
注意:安装路径不要带中文或空格。我曾经因为路径里有个“项目”两个字,折腾了一下午。
环境变量配置
装完之后,记得配环境变量。Linux 下加一行到 .bashrc:
source /opt/Xilinx/Vivado/2019.1/settings64.sh
Windows 用户直接在系统环境变量里加 %XILINX_VIVADO%/bin 就行。
配好之后,打开终端敲 vivado_hls,能看到版本信息就说明成了。
2.2 创建第一个HLS项目
好,工具就绪了。咱们来建个最简单的项目——一个加法器。别嫌简单,麻雀虽小五脏俱全。
图形界面方式
- 打开 Vivado HLS,点击 Create New Project。
- 给项目起个名字,比如
adder_prj。路径别乱放,我习惯建一个hls_workspace文件夹统一管理。 - 选择顶层函数。这里先跳过,后面再指定。
- 选择器件。如果你用的是 Zynq 系列,选 xc7z020clg484-1 就行。
- 点击 Finish,项目就建好了。
小技巧:器件型号可以在板子的官方文档里找到。实在不确定,选个同系列的通用型号也行。
命令行方式(我推荐)
说实话,图形界面点来点去效率不高。我更喜欢用 Tcl 脚本。下面是一个最小示例:
open_project adder_prj
set_top adder
add_files adder.cpp
add_files -tb adder_tb.cpp
open_solution "solution1"
set_part {xc7z020clg484-1}
create_clock -period 10
csynth_design
把这段保存成 run.tcl,然后执行 vivado_hls -f run.tcl。嗯,这才是工程师该有的样子。
2.3 理解HLS工程结构
项目建好了,咱们看看里面都有啥。打开工程目录,你会看到这样的结构:
adder_prj/
├── solution1/
│ ├── impl/ # 综合后的实现文件
│ ├── syn/ # 综合报告
│ ├── report/ # 各种报告
│ └── verilog/ # 生成的RTL代码
├── src/ # 你的源代码
├── tb/ # 测试文件
└── vivado_hls.log # 日志文件
这里我重点说几个关键目录:
- src/:放你的 C/C++ 源码。注意,HLS 支持 C、C++ 和 SystemC。
- tb/:测试文件。没有测试文件,你都不敢说你的设计是对的。
- solution1/:每个 solution 对应一组约束和配置。你可以建多个 solution 做对比实验。
核心概念:HLS 的本质是把 C 代码翻译成 RTL。你写的 C 函数会被综合成硬件模块,循环会被展开或流水线化,数组会被映射成 BRAM 或 LUTRAM。
一个完整的加法器示例
咱们写个简单的加法器,看看 HLS 怎么处理:
// adder.cpp
#include "adder.h"
int adder(int a, int b) {
#pragma HLS INTERFACE s_axilite port=return
return a + b;
}
对应的头文件:
// adder.h
#ifndef ADDER_H
#define ADDER_H
int adder(int a, int b);
#endif
测试文件:
// adder_tb.cpp
#include "adder.h"
#include <iostream>
int main() {
int result = adder(3, 5);
if (result == 8) {
std::cout << "Test passed!" << std::endl;
return 0;
} else {
std::cout << "Test failed!" << std::endl;
return 1;
}
}
你看,代码和普通 C++ 几乎一样。唯一的区别是那个 #pragma HLS 指令,它告诉工具怎么生成硬件接口。
2.4 知识体系总览
为了让你对本章内容有个整体认识,我画了张图:
2.5 避坑指南
最后,分享几个我踩过的坑:
- 路径问题:项目路径不要有中文、空格、特殊字符。我曾经用“测试项目”做名字,结果综合报错找不到文件。
- 版本匹配:Vivado HLS 版本要和 Vivado 版本一致,否则生成的 IP 可能用不了。
- 仿真 vs 综合:C 仿真通过了不代表综合没问题。有些 C 语法 HLS 不支持,比如动态内存分配。
我的习惯:每建一个新项目,先跑一个最小示例(比如加法器),确认工具链没问题再开始写正式代码。这能省下大量调试时间。
好了,这一章就到这里。工具装好了,项目建起来了,结构也搞清楚了。下一章咱们开始写真正的 HLS 代码,看看怎么把 C 语言变成硬件。