简介:Xilinx Vitis 高层次综合用户指南(UG1399 v2022.2)中文版面向用 HLS 做 FPGA 硬件加速的工程师与相关专业高年级学生,对应 2022 年 12 月 7 日发布的工具版本,帮助读者从 C/C++ 算法描述过渡到可综合的硬件 IP。全文按七部分展开:HLS 简介与效率优势、HLS 编程指南(顺序执行、数据并行、任务并行三大范例及其组合方式)、Vitis HLS 的环境配置与工程创建、代码性能分析与报告查看、命令行接口与编译选项、C 语言测试平台驱动、预定义库函数与模板,以及既有软件代码和 IP 核的移植策略,目录层级完整,便于按主题检索对照。包内为 1 个 PDF 文件,约 16.41MB,适合离线查阅与打印。目前已有 737 人学习,可作为入门通读和工程实践时随手翻检的案头手册。
1. 装 Vitis HLS 2022.2 之前,先把 UG1399 v2022.2 摊在第二个屏幕上
上周帮人远程看一台开发机,vitis_hls敲下去只回了一行error while loading shared libraries: libtinfo.so.5,屏幕上干干净净,新手当场就懵了。这问题跟 HLS 本身没有关系,纯粹是因为系统里的依赖没补全,但它的后果很严重:工具链没起来、工程建不了、综合跑不动,后面的高层次综合思路再清楚也没有用。HLS 这套环境(FPGA 方向,Vitis HLS 2022.2 配 Vivado)属于那种「装一次、用两年」的配置,装对了后面几乎不用再管,装歪了每次打开工程都得先跟环境搏斗半小时。UG1399 v2022.2 中文版恰好是这一版工具对应的行为手册,从 Flow Navigator 到协同仿真,工具怎么反应它都写了。这篇笔记按「装什么版本 → 怎么配环境 → 怎么跑第一个工程 → 崩了怎么救 → 怎么确认真的通了」走一遍,适合刚上手 Vitis HLS、或者从旧版 Vivado HLS 迁过来的人。
2. 安装 Vitis HLS 2022.2:统一安装器里到底勾哪几个组件
2.1 装之前先对表:系统版本、磁盘余量和依赖库
Vitis HLS 2022.2 不是独立安装包,它挂在 AMD 统一安装器(Unified Installer)里,跟 Vivado、Vitis 嵌入式那一套共享同一个安装根目录。所以第一件事不是点下载,是对机器做一次体检。常见做法是先把这三项确认掉:
| 检查项 | 建议值 | 说明 |
|---|---|---|
| 操作系统 | Ubuntu 20.04 LTS / RHEL、CentOS 7.x~8.x;Windows 10/11 64 位 | 太新的发行版容易缺老版本 so,太老的 glibc 又会挡住安装器自检 |
| 磁盘余量 | 单一安装目录留 120 GB 以上 | 只勾 Vitis HLS + Vivado 也要几十 GB,加上工程和仿真波形,余量给足 |
| 内存 | 16 GB 起步,跑大工程 32 GB 更稳 | C 综合和协同仿真都是吃内存的环节 |
| 系统依赖 | libtinfo5、libncurses5、libstdc++6 | Ubuntu 20.04 上最容易缺的就是 libtinfo5 |
Linux 下补依赖别一个个试,直接一把装:
# Ubuntu / Debian 系补 2022.2 最常缺的几个运行库 sudo apt update sudo apt install -y libtinfo5 libncurses5 libstdc++6 libxrender1 libxtst6 libxi6 # 确认动态链接器能找到,报错时用它反查缺哪个 ldd /tools/Xilinx/Vitis_HLS/2022.2/bin/unwrapped/lnx64.o/vitis_hls | grep "not found"这段命令里apt install那行的重点在libtinfo5,它是 2022.2 这代工具链在 Ubuntu 20.04 上最典型的缺库;ldd那条是排错用的,输出里只要还有not found,就说明还有依赖没落地,别急着往下走。/tools/Xilinx是安装器默认的根路径,装的时候如果改过,这里要换成自己的实际路径。
提示:不要试图用
apt install libtinfo-dev去糊弄libtinfo.so.5,这两者不是一回事,装完照样报错。
Windows 这边相对省心,安装器会把 VC++ 运行库一并处理,唯一要留意的是安装路径不要带中文和空格,后面 Tcl 脚本里写绝对路径时,空格会直接把-f参数切断。
2.2 统一安装器里勾哪几项,不勾哪几项
安装器跑起来之后会问你要装哪个产品。这里有个取舍:全套 Vitis 会把嵌入式、AI 引擎那一堆都带上,体积翻倍,但对你写 HLS 一点用没有。我一般只勾这几项:
- Vitis HLS:核心,必须勾,装了它才有
vitis_hls命令和 GUI。 - Vivado:强烈建议一起装。HLS 导出的 IP 要在 Vivado 里例化验证,版本必须跟 HLS 同号,跨版本混装是最常见的翻车来源。
- DocNav:可选。UG1399 这类文档用它检索比翻 PDF 快,但如果你已经有中文版 PDF,不装也不影响干活。
- Vitis Embedded / Model Composer:不写嵌入式软件、不做 Simulink 建模的话,跳过。
安装类型选「Custom」而不是「Vitis」,Custom 才能按组件勾选。器件支持那一步也别全选,全选能多占几十 GB,只勾你实际会用的器件族就够了——比如拿入门开发板练手,勾 7 系列和 Zynq-7000 就够跑通整条流程。
安装过程中有一处容易被跳过:安装器会让你确认 license 配置。免费档位覆盖的器件范围有限,选set_part的时候如果目标器件不在免费范围,综合会直接卡在第一步。装完后打开 Vivado 的 Manage License 看一眼状态,比综合报错了再回头查省事得多。
2.3 settings64 怎么加载,PATH 顺序别搞反
装完之后工具不会自动进 PATH,这是第二个高频卡点。Linux 下每个新终端都要 source 一次:
# 把 Vitis HLS 2022.2 的环境变量注入当前 shell source /tools/Xilinx/Vitis_HLS/2022.2/settings64.sh # 确认命令能找到,且指向 2022.2 这一份 which vitis_hls vitis_hls -versionsettings64.sh干的事不只是改PATH,它还设置了XILINX_VITIS、XILINX_HLS、LD_LIBRARY_PATH和工具自带的 GCC 路径。which那条是关键校验:如果输出指向的是别的年份目录,说明你机器上装了两套,PATH 顺序反了,后面综合出来的报告会跟你手上这本 v2022.2 的文档对不上,问题会非常难查。vitis_hls -version用来确认版本号确实是 2022.2。
Windows 下不用手动 source,菜单里那个「Vitis HLS 2022.2 Command Prompt」快捷方式就是把这件事做完了。我的习惯是把自己写的run_hls.tcl放在工程目录,用这个快捷方式 cd 过去再执行,避免在普通 CMD 里敲命令时找不到工具。
如果确实需要在 bashrc 里写死,建议包一层判断,别直接把 source 写在最外面,否则打开一个跟 FPGA 无关的终端也要等它加载半天:
# 需要时再加载,别污染所有 shell alias hls2022='source /tools/Xilinx/Vitis_HLS/2022.2/settings64.sh'3. 第一个 HLS 工程:从 C 源码到 IP 的 Flow Navigator 配置
3.1 工程目录怎么摆:src、tb、script 三层就够
Vitis HLS 建工程的时候会把源文件路径记进工程文件,路径一乱,换台机器就复现不了。我习惯从一开始就把目录定成固定的三层,后面写 Tcl 脚本、做版本管理都省事:
proj_hls/ ├── src/ # 综合用的 C/C++ 源文件 │ └── top.cpp ├── tb/ # 测试激励,不参与综合 │ └── tb_top.cpp └── script/ └── run_hls.tclsrc和tb必须分开,这是 HLS 和普通 C 工程最大的区别:add_files加进去的是要被综合成硬件的代码,测试激励要用add_files -tb单独加,加错位置的结果是激励里的printf、文件读写全被当成硬件逻辑去综合,报一堆「不受支持的 C/C++ 构造」——UG1399 第 7 章专门列了这一类,系统调用、动态内存、递归都在黑名单上。顶层函数还得是能被综合的那种写法:不能有main,参数走接口,返回值简单。
3.2 set_part 与 create_clock:这两个参数决定后面所有报告
工程建起来之后,有两个参数一旦定错,后面所有报告都是废的:目标器件和时钟周期。
# 器件决定资源上限,时钟决定时序约束,两者都影响综合结果 set_part {xc7z020clg400-2} create_clock -period 10 -name defaultset_part里的-2是速度等级,别随手改成-1或-3,速度等级变了,同样的代码时序收敛情况完全不同;create_clock -period 10表示 10 ns 一个周期,也就是 100 MHz。这个数不是随便填的,它直接决定 Schedule Viewer 里每个操作的延迟预算——周期给小了,工具只能塞更多寄存器、拆更多级流水,资源估算跟着涨;给小了再想降回来,得重新综合。我的做法是先按目标板子的实际主频填,跑一轮看报告,再决定要不要为了面积放宽。
GUI 里对应的是 Project Settings 里的 Synthesis 页面,Flow Target那一栏下面就是时钟和器件。命令行改完记得回 GUI 看一眼是否同步,两边不同步是另一个经典坑。
3.3 Flow Target 选 Vivado IP 还是 Vitis Kernel
这一栏很多人直接默认点过去,其实它决定了导出产物的形态:
- Vivado IP:导出成 IP catalog 里的一个核,在 Vivado 的 Block Design 里例化。做纯 FPGA 逻辑、自己画框图的话选这个。
- Vitis Kernel:导出成
.xo,给 Vitis 应用加速流程用,接口约束更严格,必须按平台要求写m_axi、s_axilite。
选错了不是不能改,但工程里已有的接口 pragma 可能要重写一遍。第一次跑通流程建议就用 Vivado IP,产物直观,能在 Vivado 里点开看端口。
3.4 第一次综合要看的三份结果
点 Run C Synthesis 之后,别只看它绿没绿,重点看三处:
- Synthesis Summary 里的 Latency 和 Interval:Latency 是这套逻辑跑一次要多少时钟周期,Interval 是两次输入之间最短隔多久。这两个数跟你算法预期差得远,说明循环没展开或者没流水。
- 资源估算表:BRAM、DSP、FF、LUT 四项。估算值超过器件一半就要警惕,后面布局布线的实际占用通常还会涨。
- Schedule Viewer:图形化看每个操作的调度。里面 II 那一栏只要出现大于 1 的,就是流水被打断了,通常是循环里有跨迭代的依赖。
4. 命令行把流程跑通:vitis_hls 批处理与 Tcl 脚本
4.1 run_hls.tcl 骨架:一条命令跑完仿真、综合、协同仿真
GUI 适合调参,但真要复现和批量跑,还是得靠 Tcl。这套骨架我基本是照抄的,改改顶层名和文件名就能用:
# 全流程脚本:仿真 -> 综合 -> 协同仿真 -> 导出 IP open_project -reset proj_hls set_top top_func add_files src/top.cpp add_files -tb tb/tb_top.cpp open_solution -reset "solution1" -flow_target vivado set_part {xc7z020clg400-2} create_clock -period 10 -name default # 先用 C 仿真验证功能,错了没必要往下走 csim_design -clean # 综合出 RTL 与报告 csynth_design # C/RTL 协同仿真,指定用 xsim cosim_design -rtl verilog -tool xsim # 导出成 IP,供 Vivado 例化 export_design -format ip_catalog exit逐段说一下。open_project -reset里的-reset表示工程已存在就清空重建,做回归测试时必须带,否则会读到上一轮的旧结果;set_top指定哪个函数是硬件顶层,写错了工具会去综合一个无关函数;-flow_target vivado对应上一节说的导出形态;csim_design -clean的-clean是清掉上次的编译产物,避免改了代码但跑的还是旧可执行文件;cosim_design是最容易跳过的一步,但它才是真正验证「综合出来的 RTL 和 C 代码行为一致」的环节,-rtl verilog指定用 Verilog,-tool xsim指定 XSIM 作为仿真器。
4.2 vitis_hls 命令行参数怎么用
脚本写好后,用vitis_hls拉起来:
# -f 执行 Tcl 脚本;-l 把全过程日志落到文件 vitis_hls -f script/run_hls.tcl -l build/hls_run.log # 想进 GUI 看结果,用 -p 打开已有工程 vitis_hls -p proj_hls-f是批处理入口,脚本跑完进程就退出,适合挂 CI;-l把日志重定向到文件,别小看这个,协同仿真跑十几分钟,终端滚屏信息根本回看不到,出问题只能靠日志回头查;-p是打开现成工程进图形界面,调 pragma 的时候用得多。批处理模式下没有弹窗,所有错误都落在日志里,所以跑完先grep -i error扫一遍,比肉眼看终端靠谱。
4.3 批处理下的日志与退出码
批处理最坑的一点是:工具报错不一定会让进程返回非零。所以别只看$?,得看日志里有没有 ERROR:
# 先跑,再按关键字筛错误;找不到 ERROR 才算通过 vitis_hls -f script/run_hls.tcl -l build/hls_run.log grep -nE "ERROR|Error:|failed" build/hls_run.log | head -20grep -nE里-n带行号,方便直接定位到日志对应位置;-E支持多关键字,比写三个 grep 干净。如果你把这套挂到流水线上,建议再补一步检查报告文件是否存在,因为有些阶段是静默失败——日志干净,但solution1/syn/report下面压根没生成报告。
5. 避坑记录:Vitis HLS 2022.2 装完之后最容易翻车的五处
5.1 安装与许可证阶段的两个坑
现象一:命令行敲vitis_hls,立刻报error while loading shared libraries: libtinfo.so.5: cannot open shared object file。原因:Ubuntu 20.04 及更新版本已经把 libtinfo 升到 6,2022.2 这代工具链还链着 5,安装器自检不会拦这一条。解决:sudo apt install libtinfo5,装完用ldd再跑一遍确认没有not found。如果发行版仓库里没有这个包,常见的做法是去装旧版本发行版对应的 deb 包,别自己去建软链接糊弄,其他依赖可能一起崩。
现象二:工程能建,一综合就停在第一步,报器件相关的 ERROR,或者提示找不到 license。原因:免费档位覆盖的器件范围有限,set_part选了大器件;或者安装时 license 那一步被跳过,环境里根本没有有效许可证。解决:先用一块明确在免费范围内的入门器件把整条流程跑通,确认工具链没问题,再换目标器件;许可证这边打开 Vivado 的 Manage License 看状态,浮动 license 的环境变量要对齐团队给的配置,别自己猜路径。
5.2 综合与协同仿真阶段的三个坑
现象三:C 仿真报一堆语法错误,报错信息里的 C++ 标准看着完全陌生,代码本身在别处能编过。原因:PATH 被系统 g++ 抢先了,工具没用自带的编译器。2022.2 自带一套 GCC,用系统的新版本编 HLS 代码大概率不兼容。解决:先 sourcesettings64.sh,再用which g++确认指向工具目录下的编译器;如果你在脚本里手动设过CXX,把它去掉,让 settings 脚本自己接管。
现象四:综合能过,但 Latency 比预期大好几倍,Schedule Viewer 里 II 那一列全是 2 以上。原因:循环体里存在跨迭代依赖,或者数组没做分割,一个周期只能读一个元素,工具没法把 II 压到 1。解决:先给最内层循环加#pragma HLS PIPELINE II=1看工具怎么报,它会在报告里明确指出是哪条依赖挡住了;数组访问密集的地方加ARRAY_PARTITION,把一块大 BRAM 拆成多个小存储。这两个 pragma 别一起无脑加,资源会爆,一轮改一个,看报告对比。
现象五:C/RTL 协同仿真起不来,报找不到仿真器,或者跑很久没动静。原因:cosim_design默认要找 XSIM,环境变量没加载时找不到;另一个原因是测试激励里printf打太多,协同仿真每个周期都要同步,打印量一大就慢得离谱。解决:确认-tool xsim指定正确、环境已 source;激励里把调试打印用宏包起来,只在 C 仿真阶段打开。协同仿真的输入激励规模也要控制,别拿几万组数据去跑第一轮。
6. 装完怎么验证:三份报告加一次协同仿真才算真通
工具装没装好,不是看图标能不能双击,是看一条完整链路能不能自动跑完。我的验收标准是四件事全绿,缺一件都算没装完。
第一件,vitis_hls -version输出 2022.2,且which指向的目录跟你以为的那份一致。第二件,csim_design跑完,测试激励里所有比对都打印 Pass——这一步证明你的 C 代码本身逻辑是对的,跟硬件无关。第三件,csynth_design生成的综合报告里,Latency 和 Interval 落在你预期范围,资源估算没超过目标器件的一半。第四件,cosim_design通过,这一条最有说服力,它意味着综合出来的 RTL 在仿真器里跑出来的结果,跟你 C 代码跑出来的一致。
对着报告核对的时候,可以按这张表逐项过:
| 检查点 | 看哪里 | 合格标准 |
|---|---|---|
| 版本一致性 | vitis_hls -version | 2022.2,与 UG1399 v2022.2 文档对得上 |
| 功能正确性 | C 仿真日志 | 测试激励全部 Pass,无 mismatch |
| 性能达标 | Synthesis Summary | Latency、Interval 符合算法预期 |
| 资源可控 | 资源估算表 | BRAM/DSP/FF/LUT 未超器件一半 |
| 行为一致 | 协同仿真日志 | 无差异,仿真正常结束 |
| 可交付 | export_design产物 | IP 目录生成,能在 Vivado 里被检索到 |
还有一个我常用来快速判断「这套环境到底稳不稳」的小技巧:把工程目录整个删掉,只留src、tb、script三个目录,换一个新终端重新 source 环境,再跑一遍vitis_hls -f script/run_hls.tcl。能一把跑通,说明你的工程不依赖任何本地残留状态,换机器、换同事都能复现。跑不通,那多半是某个路径写死在工程文件里了,趁早改成相对路径。
导出 IP 之后别停在 HLS 这一侧,去 Vivado 里建个最小工程,把 IP 例化进 Block Design,跑一次综合看端口对不对。这一步能提前暴露接口 pragma 写错的问题——比如s_axilite没绑到return,在 HLS 报告里看不出来,一到 Vivado 就发现控制接口缺了。
从那以后我每次装完这套环境,都不急着写业务代码,先拿一个只有加法器的最小例子把「仿真 → 综合 → 协同仿真 → 导出 IP → Vivado 例化」整条链路走一遍,全部通过再动真工程。这套流程花不了二十分钟,但能挡掉后面百分之八十的玄学问题。希望帮到你。
本文还有配套的精品资源,点击获取