
简介VD100 Vitis Platform是针对ALINX VD100开发板设计的Vitis软件平台实例面向使用Versal ACAP进行AI边缘计算与嵌入式开发的工程师。它整合了硬件平台定义、设备树与启动镜像等关键组件支持C/C、Python高级语言编程帮助开发者绕开底层硬件描述专注AI引擎和高带宽内存应用开发。压缩包共48个文件大小15.33MB核心类型包括xsa硬件平台文件、dtsi/dts/dtb设备树文件、bif启动配置、elf固件、pdi镜像以及二十个h头文件并附有少量txt/json说明便于理解平台结构。目前已有166人学习下载适合需要快速搭建VD100开发环境的开发者直接参考使用。资源提供了经过Vitis 2024.2验证的完整平台套件包含QEMU与linux_psv_cortexa72等仿真运行支持可显著降低从设计到部署的难度为深度学习、机器学习等应用开发提供一站式基础。 不做平台的人永远体会不到这种憋屈Vitis 装好了license 也通了打开工具却发现可选平台里躺着的全是 Alveo 系列的模板根本没有自己手上这块板子的影子。VD100 Vitis Platform 就是这个问题的答案——它不是赛灵思官方预置的现成平台而是针对 VD100 这块自定义 PCIe 加速卡在 Vitis 工具链里从零手搓出来的一套完整硬件软件平台。本文要把整个搭建过程掰开揉碎讲清楚 XSA 要准备到什么粒度、Linux 内核和 rootfs 怎么配、平台文件如何打包验证以及我在实际开发中踩过的几个容易让人一夜白头的坑。现在这个环境已经被我们用于好几个内部推理项目稳定性实测下来是可以接受的。1. 为什么自定义板卡的 Vitis 平台必须自己动手先搞清平台文件在替谁说话先交代一下 VD100 的背景。VD100 是一块面向数据中心推理场景的 PCIe 加速卡主芯片用的是 UltraScale 架构的 VU9P板载两条 DDR4 通道、一组 QSFP28 高速接口通过 PCIe x16 金手指与主机通信。性能上它和 Alveo U250 有些相似但 CLB 排列、时钟约束、PCIe 位置都不一样直接套 U250 的平台文件综合出来的 bitstream 放上去就是起不来——这件事我们团队在项目早期就验证过了所以别抱侥幸心理。1.1 Vitis 平台到底是什么很多人把 Vitis 理解为在 FPGA 上写 C 语言这么说没错但漏了最关键的一层Vitis 并不是直接把你的 C 代码烧进 FPGA它需要一个中间人来描述这块板子长什么样、有哪些资源、操作系统是什么、怎么启动。这个中间人就是平台文件。一个 Vitis 平台文件.xpfm本质上就是一个结构化目录内部包含硬件侧由 Vivado 导出的 XSA 文件里面封装了 FPGA 的静态逻辑、引脚约束、时钟频率、DDR 地址映射、PCIe 配置等信息。软件侧启动所需的 boot 组件、Linux 内核镜像、设备树DTB、根文件系统rootfs、以及对应的 sysroot 交叉编译环境。平台描述元数据告诉 Vitis 这个平台的名称、版本、支持的器件型号、有哪些 AXI 接口可以挂载用户 kernel。你可以把平台理解成板卡的护照简历。Vitis 在编译你的 kernel 之前先读这份简历搞清楚手上这块板子能提供多少个 SLR、哪些 AXI 接口能访问 DDR、时钟树长了什么样、跑的是什么系统。没有这份简历编译器再聪明也无从下手。1.2 为什么官方模板不能直接覆盖 VD100赛灵思在 Vitis 安装目录下确实预置了一批平台模板Alveo U200/U250/U280 都覆盖了。但这些模板是针对官方板卡调优过的里面的时钟拓扑、复位逻辑、PCIe 桥接方式都和 VD100 的硬件设计有出入。比如 VD100 的 DDR4 走的是两个独立的内存控制器而 U250 模板默认把内存当作一个统一地址空间来配置再比如 VD100 的 PCIe 用了一颗 XDMA 的 IP而 U250 用的是自己内部封装的 DMA 引擎。这种差异导致最直接的后果是kernel 在仿真里跑得好好的上板之后一发起 DMA 读写就崩或者频繁报 AXI 超时错误。你当然可以通过 patch 平台内部的 xsa 和 dtb 来打补丁但那我建议你干脆自己从零搭一套因为后续要维护、要升级内核、要加新功能底子是自己的改起来才顺手。2. 硬件侧先行Vivado 工程里 XSA 的准备粒度与关键参数平台搭建的第一步永远在 Vivado 里做这一步决定后面的软件工作能不能顺利进行。我的习惯是先建一个规范的 block design把静态逻辑和可重配置区域分开规划然后再导出 XSA。2.1 Block Design 里必须包含的组件VD100 的 block design 我最终定稿的版本包含这些核心组件PCIe XDMA IP作为主机和 FPGA 之间的数据通道配置成 AXI Memory Mapped 模式地址宽度 64 位中断用 MSI-X。DDR4 MIG IP两套分别挂在不同的 AXI 端口上对应板卡上两条物理内存通道。每套配了独立的时钟和复位。时钟管理一组 Clocking Wizard 为 kernel 区域提供 100MHz/200MHz 用户时钟统一从 PCIe 参考时钟派生保证上板后的时钟对齐。外部中断控制器把 XDMA 的中断和用户逻辑的中断汇总成一个 AXI INTC再上报给主机。这里有个容易被忽略的点Block Design 里挂 user kernel 的 AXI 接口Vivado 2019.2/Vitis 平台依赖的是 PFM 属性来识别。你需要用set_property把 AXI 主从端口的名称、类型、地址空间描述清楚。例如set_property PFM.AXI_PORT {S_AXI_CTRL} [get_bd_intf_pins /axi_intc/s_axi] set_property PFM.AXI_PORT {M_AXI_HPC0} [get_bd_intf_pins /xdma_0/M_AXI]M_AXI_HPC0这个名字不是随便起的Vitis 会依据这个名字判断出这是一个高性能High Performance接口并据此自动做地址对齐和 burst 长度匹配。2.2 时钟和复位最容易埋雷的区域时钟在平台文件里是以 PFM.CLOCK_INFO 属性登记的登记的内容包括时钟频率、时钟用途clk_wiz输出的哪个端口、是不是全局时钟等。我给 VD100 登记的 kernel 时钟方案如下时钟名频率用途kernel_clk0200 MHzkernel 主时钟kernel_clk1100 MHzAXI-Lite 控制通道时钟kernel_clk2300 MHz高带宽数据通路时钟Vitis 对 kernel 时钟的数量有限制具体取决于器件型号的 clock region 数量但更关键的是你登记的时钟必须和实际的 Clocking Wizard 输出一一对应而且频率值必须填写真实值。写错了不会在平台打包时报错kernel 编译也通过但上板后时序就是乱跑起来数据全是花的。复位也一样。Vitis 平台要求 reset 信号必须能够由主机端控制也就是通过 AXI-Lite 寄存器去断言和释放。我的做法是在 block design 里加一个proc_sys_reset把它的输出接到 kernel 区域的复位端口并且确保这个 IP 的aux_reset_in连到了 PCIe 的 reset 域。这样主机侧xbutil reset才能真正把用户逻辑复位干净。2.3 导出 XSA 时的要点XSA 导出走的是 Vivado 的write_hw_platform命令但导出的时机和选项很讲究write_hw_platform -include_bit -force ./vd100_platform.xsa注意必须带-include_bit否则生成的 XSA 里没有 bitstreamVitis 在硬件仿真和上板运行时都会报找不到 bit 文件的错误。导出之前还要跑一遍 implementation 并生成比特流这个顺序不能乱。很多人习惯在综合完成后就导出结果拿到 Vitis 里一跑就报错。导出完成后我建议先用platforminfo工具检查一下 XSA 的完整性platforminfo -xsa vd100_platform.xsa这个命令会列出 XSA 中包含的器件型号、PFM 接口、时钟、地址段等信息。对照自己的设计逐项检查确认无误后再进入软件侧能省掉后面一大半调试时间。3. 软件侧合体内核、u-boot 与 rootfs 的选择逻辑硬件 XSA 就位后Vitis 平台的另一半是软件组件。这里的核心难点不在怎么编译而在怎么选版本。3.1 先想清楚 VD100 要不要跑 Linux平台软件侧可以做成裸机bare-metal模式也可以做成 Linux 模式。VD100 作为数据中心推理卡我们的目标是让主机端通过 PCIe 驱动加载 kernel、用 XRT 管理运行时那 Linux 就是刚需。如果只是做个简单加速实验裸机平台也能用但后期扩展性很差所以我下面的内容都围绕 Linux 平台来讲。Linux 平台需要准备的软件组件包括 boot 文件u-boot 或 FSBL、内核镜像、设备树、rootfs、以及 sysroot。对 VD100 这种基于 PCIe 的加速卡启动方式和嵌入式 SoC 不太一样VD100 上没有一个独立的 ARM 处理器来跑 Linux它的系统其实跑在主机侧而板卡侧只需要一个轻量级的微控制器或者直接由 FPGA 逻辑提供 PCIe 枚举能力。这说着简单但实际配置里差距很大。VD100 的板卡侧我做的是无处理器的 PCIe 从设备方案主机通过 XDMA 的 AXI-Lite 接口访问 FPGA 内部的寄存器通过 AXI-MM 接口做数据搬运。这样一来Vitis 平台里 software 部分的内核就不再是板卡上跑的内核而是主机侧加载的 XRT Linux 内核驱动模块。这也是很多从 Zynq 转过来的人会纠结的地方平台文件里到底放不放内核我的答案是放但放的是 VD100 赖以工作的驱动框架所依赖的主机内核头文件和 PDI/bit 管理工具链而不是一个嵌入式内核镜像。Vitis 在软件侧的组件划分里对这类纯 PCIe 加速卡的处理方式和 MPSoC 平台完全不同它会把重心放在 sysroot 和xrt运行时库上。3.2 用 Xilinx 提供的配套版本别自己另起炉灶如果你用过petalinux-build会知道赛灵思整个软件生态是版本环环相扣的。Vitis 2019.2 配套的内核版本、XRT 版本、GCC 版本都是锁定好的。我自己在别的项目中踩过一次为了用新内核特性把 host 内核升了一个小版本结果 XRT 驱动编译不过Vitis 运行时和内核模块的 ABI 对不上最后整个平台都跑不了。所以 VD100 平台我直接用了赛灵思发布包里的标准内核源码和 XRT 版本不要自己从 kernel.org 拉一个最新内核来编。想升级内核先查官方文档确认 XRT 支持矩阵再动手。# 以 Vitis 2019.2 为例内核版本锁定在 4.19 分支 git clone -b xlnx-rebase-v4.19 git://github.com/Xilinx/linux-xlnx.git cp vd100_defconfig arch/arm64/configs/ make ARCHarm64 xlnx_vd100_defconfig make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(nproc)3.3 设备树DTB里要写清楚哪些东西设备树是 Vitis 平台软件侧最容易被忽视、但影响最直接的部分。它必须描述清楚 PCIe 枚举出来的黑马设备XDMA 驱动节点、中断、DMA 通道等信息。VD100 的设备树里我重点写了XDMA 节点指定了 AXI-Lite 控制寄存器基地址、中断号、MSI-X 能力。板载温度、电源监控节点这样主机的xbutil examine才能正确读取传感器数据。两个 DDR4 控制器的地址映射关系确保用户 kernel 访问的地址和 MIG 配置一致。适配 DTB 的通用做法是先把系统启动起来然后通过/sys/firmware/devicetree/base/导出实际运行的树和源文件对比逐项修正。4. 平台打包与 Vitis 侧验证从 hello_world 到真实 kernel软件组件备齐后进入平台打包环节。在 Vitis 2019.2 里有两种打包方式命令行和 GUI。4.1 命令行方式打包平台我在脚本化流程里用的是platform命令Vitis 2019.2 里是platform -create再通过platform -finalize生成可发布平台。命令行的好处是可以写进 CI每次硬件改版后一键重新打包。下面是一个从 XSA 创建平台的最小脚本platform -create -name vd100_platform -hw ./vd100_platform.xsa \ -proc psu_cortexa53 -os linux platform -write在实际项目里还要指定 sysroot、boot 目录等参数。sysroot 交叉编译环境是整个平台最值钱的部分Vitis 里的应用工程全靠它来链接 XRT 库和内核头文件。你在 Linux 平台上编译 App 时遇到的头文件找不到、库版本不匹配十有八九是 sysroot 和内核版本没有严格配套。GUI 方式则是打开 Vitis → 选择 XSA → 指定 Linux 系统组件 → 让工具自动生成平台。GUI 对新手友好但版本升级后工程文件兼容性有时会出幺蛾子所以团队统一约定用命令行构建平台工程GUI 只用于快速预览。4.2 hello_world 验证的真正意义平台打包完第一件要做的事不是急着跑自己写的算法 kernel而是按下面的顺序逐级验证先跑 Vitis 自带的 hello_world 软件工程确认平台能被正常枚举、system.bit 能下载、UART/串口能输出。再跑一个空的vkernel 编译流程确认 kernel 编译链、链接、打包都没有问题。最后跑一个简单的 AXI 读写自测 kernel——比如往一个固定地址写值再读回来验证 DDR 通路、XDMA 链路是否打通。这一步别跳。我一共调过三块不同厂商的加速卡每一次跳过中间层验证直接上算法最后都沦为在仿真器和 JTAG 之间来回折腾的悲剧。hello_world 通过只代表平台能启动完全不代表 DDR 通路可靠AXI 读写自测通过才能说平台侧基本可信。4.3 上板实测时的检查路径VD100 上板后建议的调试路径是主机上用lspci -v确认 FPGA 设备被正常枚举记录它的 BDF 号。用xbutil examine检查平台状态观察温度、电压、DDR 校验结果。用xbutil validate跑一遍官方验证流程。加载自测 kernel观察 AXI 读写的返回值和预期是否一致。在第 2 步如果发现 DDR 报错优先检查 XSA 里的 MIG 配置是否和板卡实际颗粒匹配尤其是地址位宽、bank group、刷新间隔等参数。曾经遇到过 MIG 配置死活没问题、结果发现是 DTB 里没有给 MIG 的 AXI 端口预留足够地址窗口导致 DMA 访问越界的情况这类问题在dmesg里往往只报一个通用 AXI 错误排查起来非常费神。5. 实测中吞过泪的三个非典型故障平台本身的功能调试之外还有几个环境类故障单看报错信息根本想不到和平台构建有什么关系但实际浪费的时间反而最多。我按踩坑顺序逐个说。5.1 Windows 下 Vitis 启动时 Qt 平台插件加载失败这个报错原文是qt.qpa.plugin: could not load the qt platform plugin windows in ...。大部分时候的原因不是 Vitis 本身坏了而是系统里缺少对应的运行库或者环境变量里QT_QPA_PLATFORM_PLUGIN_PATH被别的软件改掉了。我们这边就有同事装了另一套工业软件后 Vitis 就打不开。处理方法设置环境变量指向 Vitis 自带的 Qt 插件目录同时确认 Visual C Redistributable 运行库已安装。我的常用检查命令是set QT_QPA_PLATFORM_PLUGIN_PATHC:\Xilinx\Vitis\2019.2\data\vitis\plugins vitis5.2 Intel Platform License Manager 服务连接超时Windows 机器上跑 Vitis 时如果日志里出现等待 intel(r) platform license manager service 服务的连接超时(45000 毫秒)别觉得奇怪。这个服务是 Intel 的许可证管理器和赛灵思的 license 没有关系但它会拖慢 Vitis 启动时对 license 的枚举。我们的处理是在 Windows 服务管理器里把该服务设为手动启动并且避免在系统启动阶段加载这样 Vitis 起来时不会等它白白超时。5.3 JUnit Platform Launcher 依赖解析失败这个报错failed to resolve org.junit.platform:junit-platform-launcher:1.6.3一般出现在用 Gradle 构建主机端应用时。Vitis 自带的 Java 运行时可能是老版本导致 JUnit 平台的分发解析失败。解决思路是在主机端应用里明确指定一个与当前 Java 版本兼容的 JUnit 版本或者在 Gradle 配置里强制使用本地已下载的依赖仓库不要让它走网络解析。repositories { mavenCentral() } dependencies { testImplementation org.junit.platform:junit-platform-launcher:1.9.3 }这类问题和 FPGA 本身无关但一旦卡住很容易误导你在平台文件里找原因浪费半天时间。6. 一些想留给后来者的话VD100 平台的这次搭建前后我改了大概四版 XSA第一版 PCIe 带宽跑不满第二版 DDR 校验不稳定第三版才把内核时钟和复位做干净第四版主要是把设备树明细补完整。回头总结最核心的经验就一句话平台的每一层都要可验证硬件侧有 AXI 自测软件侧有 hello_world别把看起来能跑当成真能跑。如果你是第一次搭 Vitis 平台我建议从官方提供的 xilinx_vcu1525 或类似开源平台工程入手对比着看它的 block design 怎么建、PFM 属性怎么设、软件组件怎么组织再落到自己的板卡上。直接打开一个空工程从头写要摸索的东西太多了。最后分享一个实用技巧平台文件打包完成后顺手把整个平台目录压缩归档标好对应的 XSA 哈希和内核版本号。这个习惯在我们后续维护多版本、复现问题的时候帮了大忙——因为你会发现三个月后再回来看真的记不清当初这个平台配的是哪个版本的内核。本文还有配套的精品资源点击获取