第三章 FPGA开发环境搭建:Vivado安装与配置、Vivado HLS/Vitis HLS入门、第一个HLS工程:矩阵乘法加速
好,咱们进入实战环节了。前面两章聊了CT重建的原理和为什么选FPGA,这一章咱们得把家伙事儿备齐——把开发环境搭起来,跑通第一个HLS工程。
说实话,环境搭建这事儿,看着简单,但坑不少。我见过太多同学卡在安装这一步,折腾一整天连个灯都没点亮。所以这一章我会把细节掰开揉碎了讲,尤其是那些容易踩坑的地方。
3.1 Vivado安装与配置
Vivado是Xilinx(现在叫AMD了)的FPGA开发套件。版本很多,从2018到2024都有。我个人建议用2020.1或2021.1,这两个版本比较稳定,网上资料也多。
3.1.1 下载与安装
去官网下载Vivado HLx版本,大概20-30GB。嗯,你没看错,就是这么夸张。所以建议提前准备好网络环境,别用手机热点。
安装时注意几点:
- 选择版本:选Vivado HL WebPACK就够了,除非你要用Virtex UltraScale+这种大芯片
- 组件选择:一定要勾上Vivado HLS(或者Vitis HLS,看版本)
- 安装路径:别用中文路径!别用空格!我吃过这个亏,编译报错查了半天才发现是路径问题
- License:WebPACK版本不需要额外license,但如果你要用更高端的器件,得申请免费license
3.1.2 环境变量配置
安装完后,需要配置环境变量。Windows下比较简单:
# 添加系统环境变量
XILINX_VIVADO = C:\Xilinx\Vivado\2021.1
PATH = %XILINX_VIVADO%\bin;%PATH%
Linux下呢,我习惯在.bashrc里加一行:
source /tools/Xilinx/Vivado/2021.1/settings64.sh
为什么要配环境变量?说白了就是让系统能找到vivado、vitis_hls这些命令。不然每次都要跑到安装目录下去执行,太麻烦了。
3.1.3 验证安装
打开终端或命令行,输入:
vivado -version
如果能看到版本信息,恭喜你,安装成功了。如果报错说找不到命令,八成是环境变量没配好。
3.2 Vivado HLS / Vitis HLS入门
好,接下来聊聊HLS。HLS全称是High-Level Synthesis,说白了就是让你用C/C++写FPGA逻辑,不用去手写Verilog。
你可能会问:为什么要用HLS?直接写Verilog不香吗?
我的看法是:对于CT重建这种算法密集型的任务,用HLS开发效率高得多。你想想看,一个矩阵乘法用Verilog写要几百行,用HLS几十行就搞定了。而且HLS做优化、迭代也快。
不过HLS也有它的局限性。我在项目中遇到过,有些时序敏感的逻辑,HLS生成的硬件效率不如手写Verilog。所以我的建议是:算法逻辑用HLS,接口和时序控制用手写Verilog,两者结合才是王道。
3.2.1 Vivado HLS vs Vitis HLS
这两个名字容易搞混。简单说:
| 特性 | Vivado HLS | Vitis HLS |
|---|---|---|
| 所属套件 | Vivado | Vitis统一平台 |
| 支持语言 | C/C++ | C/C++,OpenCL |
| 适用版本 | 2019.2及之前 | 2020.1及之后 |
| 使用场景 | 传统FPGA开发 | 异构计算、AI加速 |
如果你用的是2020.1之后的版本,建议直接用Vitis HLS。功能更强,而且和Vitis分析工具集成得更好。
3.2.2 HLS的基本工作流程
HLS的开发流程其实挺直观的:
- 写C代码:用C/C++描述算法
- 加pragma:用#pragma HLS告诉工具怎么优化
- C仿真:验证功能正确性
- C综合:把C代码转成RTL
- 分析报告:看延迟、吞吐量、资源占用
- 导出IP:生成IP核供Vivado使用
嗯,这里要注意:C仿真通过了不代表综合出来的硬件没问题。我遇到过C仿真结果正确,但综合后硬件跑出来不对的情况。所以一定要做RTL仿真和上板验证。
3.3 第一个HLS工程:矩阵乘法加速
理论说完了,咱们动手吧。第一个工程选矩阵乘法,原因很简单:
- CT重建里到处都是矩阵运算
- 矩阵乘法是典型的计算密集型任务,适合展示HLS的优化能力
- 代码简单,容易理解
3.3.1 创建工程
打开Vitis HLS,按以下步骤操作:
- 点击Create New Project
- 输入工程名:matrix_mult_hls
- 选择顶层函数:matrix_mult
- 选择器件:我习惯用xc7z020clg484-1(Zynq-7020),CT重建常用这个
- 点击Finish
3.3.2 编写代码
在Source里新建一个文件,叫matrix_mult.cpp:
#include <hls_stream.h>
#include "ap_int.h"
#define N 4
void matrix_mult(int A[N][N], int B[N][N], int C[N][N]) {
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE bram port=A
#pragma HLS INTERFACE bram port=B
#pragma HLS INTERFACE bram port=C
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
#pragma HLS PIPELINE II=1
int sum = 0;
for (int k = 0; k < N; k++) {
sum += A[i][k] * B[k][j];
}
C[i][j] = sum;
}
}
}
这段代码看着简单,但有几个关键点:
- #pragma HLS PIPELINE II=1:告诉工具尽量让循环流水线化,理想情况下每个时钟周期输出一个结果
- INTERFACE:定义端口类型,这里用BRAM接口,方便和Zynq的PS端通信
- ap_int.h:Xilinx的任意精度整数库,比标准int更灵活
3.3.3 编写测试激励
再建一个testbench文件,叫tb_matrix_mult.cpp:
#include <iostream>
#include "matrix_mult.cpp"
int main() {
int A[N][N] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16}};
int B[N][N] = {{1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}};
int C[N][N] = {0};
matrix_mult(A, B, C);
// 验证结果
bool pass = true;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (C[i][j] != A[i][j]) {
pass = false;
std::cout << "Mismatch at [" << i << "][" << j << "]" << std::endl;
}
}
}
if (pass) {
std::cout << "Test passed!" << std::endl;
return 0;
} else {
std::cout << "Test failed!" << std::endl;
return 1;
}
}
这里我用单位矩阵做测试,因为任何矩阵乘以单位矩阵结果不变,验证起来方便。
3.3.4 运行C仿真
在Vitis HLS界面里:
- 右键点击工程,选择Run C Simulation
- 在弹出的对话框里,选择tb_matrix_mult.cpp作为testbench
- 点击OK
如果看到"Test passed!",说明功能正确。如果报错,检查一下代码有没有拼写错误。
3.3.5 综合与优化
C仿真通过后,点击Solution → Run C Synthesis。等几分钟,工具会生成综合报告。
报告里重点关注几个指标:
- Latency:从输入到输出需要多少个时钟周期
- II (Initiation Interval):多久能处理一组新数据
- BRAM/DSP/FF/LUT:资源占用情况
对于4x4矩阵乘法,不加优化时延迟大概在几十个周期。如果加上PIPELINE和UNROLL优化,可以降到十几个周期。我在CT重建项目里,把矩阵乘法从64x64优化到4x4分块处理,延迟从几千周期降到了几百周期,效果很明显。
3.3.6 导出IP核
综合通过后,点击Export RTL,选择IP Catalog格式。这样生成的IP核就可以在Vivado里直接调用了。
导出时注意:
- 选择IP-XACT格式,兼容性最好
- 勾上"Evaluate with Vivado"可以自动打开Vivado检查
- IP核的名字和版本号要规范,方便后续管理
3.4 常见问题与避坑指南
最后,分享几个我踩过的坑:
- 综合时间太长:如果工程比较大,可以先做C仿真,确认逻辑正确后再综合。别每次改一行代码就综合一次,太浪费时间。
- 资源爆了:CT重建的算法往往很复杂,资源很容易超标。我的经验是先做资源评估,再决定优化策略。
- 时序不收敛:如果综合后时序不满足,可以试试降低时钟频率,或者用PIPELINE优化关键路径。
- 仿真和实际不一致:这个最头疼。我建议在C仿真通过后,一定要做RTL协同仿真(Co-simulation),确保RTL行为和C代码一致。
好了,这一章的内容就到这里。环境搭好了,第一个HLS工程也跑通了,下一章咱们开始真正进入CT重建的核心算法——滤波反投影(FBP)的FPGA实现。
记住,HLS只是工具,真正重要的是理解算法和硬件架构。多动手,多思考,你也能成为FPGA加速的高手。