【Vitis-AI】DPU-PYNQ自定义Overlay硬件设计 -> .bit .hwh .xclbin 【FPGA开发】

【Vitis-AI】DPU-PYNQ自定义Overlay硬件设计 -> .bit .hwh .xclbin 【FPGA开发】

前景提要

【Vitis-AI】解析DPU-PYNQ
FPGA加速计算生态系统:从Vivado到Vitis AI的全面解析
https://github.com/Xilinx/DPU-PYNQ

makefile分析

https://github.com/Xilinx/DPU-PYNQ/blob/design_contest_3.5/boards/Makefile

DIR_PRJ = $(shell pwd)/${BOARD}
DIR_TRD = $(shell pwd)/DPUCZDX8G
VIVADO_ROOT := $(XILINX_VIVADO)
RM = rm -f
RMDIR = rm -rf
VIVADO := ${VIVADO_ROOT}/bin/vivado
TARGET := hw
KERNEL := DPU

.PHONY: all clean check_env
all : check_env DPU_TRD dpu.xclbin

# If VITIS_PLATFORM not set by user, will default to expected file output
# of gen_platform.tcl in the board directory
VITIS_PLATFORM ?= ${DIR_PRJ}/platform.xsa

# If platform not provided, generate a platform using the gen_platform.tcl
# script.
${VITIS_PLATFORM}:
	cd ${DIR_PRJ} && \
	vivado -mode batch -source gen_platform.tcl

check_env :
	@echo "BOARD: ${BOARD}"
	@echo "VITIS_PLATFORM: ${VITIS_PLATFORM}"
	bash check_env.sh

# The DPU IP HDL sources for MPSoC live in the DPU TRD flow, hosted on opendownloads
# more info: https://docs.xilinx.com/r/en-US/pg338-dpu/Vitis-DPU-TRD-Flow
DPU_TRD:
	wget -O DPUCZDX8G.tar.gz https://www.xilinx.com/bin/public/openDownload?filename=DPUCZDX8G_VAI_v3.0.tar.gz && \
        tar xf DPUCZDX8G.tar.gz && \
	mv DPUCZDX8G_VAI_v3.0 DPUCZDX8G && \
	rm DPUCZDX8G.tar.gz
	

# Optional parameters from the TRD flow
XOCC_OPTS = -t ${TARGET} --platform ${VITIS_PLATFORM} \
	    --save-temps --config ${DIR_PRJ}/prj_config \
	    --xp param:compiler.userPostSysLinkOverlayTcl=${DIR_TRD}/prj/Vitis/syslink/strip_interconnects.tcl 

DPU_HDLSRCS=\
	${DIR_PRJ}/kernel_xml/dpu/kernel.xml\
	${DIR_PRJ}/scripts/package_dpu_kernel.tcl\
	${DIR_PRJ}/scripts/gen_dpu_xo.tcl\
	${DIR_PRJ}/scripts/bip_proc.tcl\
	${DIR_PRJ}/dpu_conf.vh\
	${DIR_TRD}/dpu_ip/Vitis/dpu/hdl/DPUCZDX8G.v\
	${DIR_TRD}/dpu_ip/Vitis/dpu/inc/arch_def.vh\
	${DIR_TRD}/dpu_ip/Vitis/dpu/xdc/*.xdc\
	${DIR_TRD}/dpu_ip/DPUCZDX8G_*/hdl/DPUCZDX8G_*_dpu.sv\
	${DIR_TRD}/dpu_ip/DPUCZDX8G_*/inc/function.vh\
	${DIR_TRD}/dpu_ip/DPUCZDX8G_*/inc/arch_para.vh

SOFTMAX_HDLSRCS=\
	${DIR_PRJ}/kernel_xml/sfm/kernel.xml\
	${DIR_PRJ}/scripts/package_sfm_kernel.tcl\
	${DIR_PRJ}/scripts/gen_sfm_xo.tcl\
	${DIR_TRD}/dpu_ip/Vitis/sfm/hdl/*.v\
	${DIR_TRD}/dpu_ip/DPUCZDX8G_*/hdl/DPUCZDX8G_*_sfm.sv\
	${DIR_TRD}/dpu_ip/DPUCZDX8G_*/xci/sfm/fp_*/*.xci		

# Rules for copying the necessary scripts for building the DPU design
# Some paths are sed replaced to reflect our boards directory structure
${DIR_PRJ}/kernel_xml/dpu/kernel.xml:
	@mkdir -p $(@D)
	cp -rf ${DIR_TRD}/prj/Vitis/kernel_xml/dpu/kernel.xml $@
${DIR_PRJ}/kernel_xml/sfm/kernel.xml:
	@mkdir -p $(@D)
	cp -rf ${DIR_TRD}/prj/Vitis/kernel_xml/sfm/kernel.xml $@

${DIR_PRJ}/scripts:
	@mkdir -p $@
${DIR_PRJ}/scripts/gen_dpu_xo.tcl: $(DIR_PRJ)/scripts
	cp -f ${DIR_TRD}/prj/Vitis/scripts/gen_dpu_xo.tcl $@
${DIR_PRJ}/scripts/gen_sfm_xo.tcl: $(DIR_PRJ)/scripts
	cp -f ${DIR_TRD}/prj/Vitis/scripts/gen_sfm_xo.tcl $@
${DIR_PRJ}/scripts/bip_proc.tcl : $(DIR_PRJ)/scripts
	cp -f ${DIR_TRD}/prj/Vitis/scripts/bip_proc.tcl $@
${DIR_PRJ}/scripts/package_dpu_kernel.tcl: $(DIR_PRJ)/scripts
	cp -f ${DIR_TRD}/prj/Vitis/scripts/package_dpu_kernel.tcl $@
	sed -i 's/set path_to_hdl "..\/..\/dpu_ip"/set path_to_hdl "..\/DPUCZDX8G\/dpu_ip"/' $@
${DIR_PRJ}/scripts/package_sfm_kernel.tcl: $(DIR_PRJ)/scripts
	cp -f ${DIR_TRD}/prj/Vitis/scripts/package_sfm_kernel.tcl $@
	sed -i 's/set path_to_hdl "..\/..\/dpu_ip"/set path_to_hdl "..\/DPUCZDX8G\/dpu_ip"/' $@

# Kernel name must match kernel name in kernel.xml
DPU_KERN_NAME = DPUCZDX8G
SFM_KERN_NAME = sfm_xrt_top

ifeq ($(KERNEL),DPU_SM)
kernel_xo += binary_container_1/dpu.xo
kernel_xo += binary_container_1/softmax.xo
else
kernel_xo += binary_container_1/dpu.xo
endif

# Added this rule so the sources get happily copied from the extracted TRD
# otherwise makefile will fail
${DPU_HDLSRCS}: ${DPU_TRD}

# Rule to build Vitis DPU kernel
binary_container_1/dpu.xo: ${DPU_HDLSRCS}
	@mkdir -p ${DIR_PRJ}/binary_container_1
	-@$(RM) ${DIR_PRJ}/$@
	cd ${DIR_PRJ} ;\
	$(VIVADO) -mode batch -source scripts/gen_dpu_xo.tcl -notrace -tclargs $@ $(DPU_KERN_NAME) ${TARGET} ${BOARD}

binary_container_1/softmax.xo: $(SOFTMAX_HDLSRCS)
	@mkdir -p ${DIR_PRJ}/binary_container_1
	-@$(RM) ${DIR_PRJ}/$@
	cd ${DIR_PRJ} ;\
	$(VIVADO) -mode batch -source scripts/gen_sfm_xo.tcl \
		-tclargs $@ $(SFM_KERN_NAME) ${TARGET} ${BOARD} 

# Rule to generate the PYNQ overlay binaries, we only use the hardware platform
# software components get taken core of by the PYNQ image, so using the --package.no_image option
dpu.xclbin: $(kernel_xo) $(VITIS_PLATFORM) 
	cd ${DIR_PRJ} ;\
	v++ $(XOCC_OPTS) -l --temp_dir binary_container_1 \
		--log_dir binary_container_1/logs --package.no_image \
		--remote_ip_cache binary_container_1/ip_cache -o ${DIR_PRJ}/binary_container_1/$@ $<
	cp -f ${DIR_PRJ}/binary_container_1/link/vivado/vpl/prj/prj.gen/sources_1/bd/*/hw_handoff/*.hwh \
		${DIR_PRJ}/dpu.hwh
	cp -f ${DIR_PRJ}/binary_container_1/link/vivado/vpl/prj/prj.runs/impl_1/*.bit \
		${DIR_PRJ}/dpu.bit
	cp -f ${DIR_PRJ}/binary_container_1/$@ \
		${DIR_PRJ}/dpu.xclbin

我们来详细分析这个 Makefile 的执行过程,以及它所依赖的工具和环境。

这个 Makefile 旨在自动化构建包含 DPU IP 的硬件设计,最终生成 PYNQ 可以使用的 overlay 文件 (.bit, .hwh) 以及 VART/XRT 需要的 .xclbin 文件。它遵循的是 Vitis 应用加速流程,而非纯粹的 Vivado 流程。

Make 过程详解:

当你在命令行运行 make BOARD=<Your_Board_Name> 时,make 工具会读取这个 Makefile 并执行以下主要步骤(按依赖关系):

  1. check_env 目标:

    • 作用: 检查必要的环境变量和设置是否就绪。
    • 动作:
      • 打印用户指定的 BOARD 和 Vitis 平台路径 (VITIS_PLATFORM)。
      • 执行 bash check_env.sh 脚本。这个脚本的具体内容未给出,但通常会检查 XILINX_VITIS, XILINX_XRT, XILINX_VIVADO 等环境变量是否设置,以及 BOARD 是否有效,Xilinx Board Files 是否存在等。
    • 依赖工具/环境: bash, 用户设置的 BOARD 变量, 可能需要 XILINX_* 环境变量(由 check_env.sh 检查)。
  2. DPU_TRD 目标:

    • 作用: 下载并解压 DPU 的硬件源代码 (TRD - Target Reference Design)。这是运行 DPU 所必需的 IP 核源文件。
    • 动作:
      • 使用 wget 从 Xilinx 网站下载 DPUCZDX8G TRD 的 .tar.gz 压缩包。
      • 使用 tar 解压压缩包。
      • 使用 mv 将解压后的目录重命名为 DPUCZDX8G
      • 使用 rm 删除下载的压缩包。
    • 依赖工具/环境: wget (需要网络连接), tar, mv, rm (标准的 Linux 命令)。
  3. 复制和修改脚本/配置文件 (由 .xo 文件的依赖触发):

    • 作用: 将 DPU TRD 中用于构建 Vitis 内核的 Tcl 脚本和 kernel.xml 文件复制到当前项目的工作目录 (${DIR_PRJ})下,并可能修改其中的路径以适应当前项目结构。
    • 动作:
      • 执行多个 mkdircp 命令,将 kernel.xml, gen_dpu_xo.tcl, gen_sfm_xo.tcl, package_dpu_kernel.tcl 等文件从 ${DIR_TRD}/prj/Vitis/... 复制到 ${DIR_PRJ}/kernel_xml/${DIR_PRJ}/scripts/
      • package_dpu_kernel.tclpackage_sfm_kernel.tcl 文件使用 sed 命令,将其中的相对路径 ../../dpu_ip 修改为 ../DPUCZDX8G/dpu_ip,以指向正确下载的 DPU TRD 源码位置。
    • 依赖工具/环境: cp, mkdir, sed
  4. ${VITIS_PLATFORM} 目标 (例如 ${DIR_PRJ}/platform.xsa):

    • 作用: 生成 Vitis 硬件平台文件 (.xsa)。这是 Vitis 流程的基础,定义了 Zynq PS 配置、时钟、可用 AXI 接口等。这是 Vitis 流程的第一步 (平台创建)
    • 动作:
      • cd ${DIR_PRJ}: 进入特定板子的目录。
      • vivado -mode batch -source gen_platform.tcl: 启动 Vivado 工具,在批处理模式下运行该板子目录下的 gen_platform.tcl 脚本。这个 Tcl 脚本负责创建 Vivado 工程、配置 Zynq PS、生成 Block Design(可能只包含 PS 和必要的接口),并最终导出 .xsa 文件
    • 依赖工具/环境: vivado, gen_platform.tcl 脚本。需要 XILINX_VIVADO 环境变量。
  5. binary_container_1/dpu.xo 目标 (以及可能的 softmax.xo):

    • 作用: 将 DPU (和 Softmax) 的 RTL 源代码编译成 Vitis 内核对象 (.xo) 文件。这是 Vitis 流程的第二步 (内核编译)。
    • 动作:
      • cd ${DIR_PRJ}: 进入板子目录。
      • $(VIVADO) -mode batch -source scripts/gen_dpu_xo.tcl ...: 再次启动 Vivado 工具,运行之前复制过来的 gen_dpu_xo.tcl (或 gen_sfm_xo.tcl) 脚本。这个脚本使用 Vivado 的功能(可能是 package_xo Tcl 命令或类似机制)将 DPU 的 HDL 源代码 (${DPU_HDLSRCS}) 打包编译成 .xo 格式。注意,这里没有直接使用 v++ -c 命令,而是通过 Vivado Tcl 脚本来完成内核打包。
    • 依赖工具/环境: vivado, gen_dpu_xo.tcl 等脚本, DPU TRD 源代码文件 (${DPU_HDLSRCS}). 需要 XILINX_VIVADO
  6. dpu.xclbin 目标:

    • 作用: 将编译好的内核 (.xo 文件) 链接 (link) 到硬件平台 (.xsa),生成最终的 .xclbin 文件。这是 Vitis 流程的第三步 (链接)。
    • 动作:
      • cd ${DIR_PRJ}: 进入板子目录。
      • v++ $(XOCC_OPTS) -l ... -o ${DIR_PRJ}/binary_container_1/$@ $(kernel_xo): 启动 v++ (Vitis 编译器/链接器) 工具。
        • -l: 指定为链接模式。
        • $(XOCC_OPTS): 传递一系列选项,包括:
          • -t hw: 目标为硬件。
          • --platform ${VITIS_PLATFORM}: 指定之前生成的 .xsa 平台文件。
          • --config ${DIR_PRJ}/prj_config: 指定链接时的配置文件。
          • --save-temps: 保留中间文件。
          • --xp param:compiler.userPostSysLinkOverlayTcl=...: 指定一个在系统链接后运行的 Tcl 脚本 (用于清理互联)。
        • --temp_dir, --log_dir, --remote_ip_cache: 指定临时/日志/缓存目录。
        • --package.no_image: 重要! 告诉 Vitis 只生成硬件平台相关文件 (.xclbin 等),不要打包完整的 SD 卡镜像,因为 PYNQ 会提供自己的根文件系统。
        • -o .../dpu.xclbin: 指定输出的 .xclbin 文件路径。
        • $(kernel_xo): 指定要链接的内核对象文件列表 (例如 binary_container_1/dpu.xo)。
      • 这个 v++ -l 命令内部会调用 Vivado 来执行布局布线,生成最终的比特流,并将比特流和所有必要的元数据打包进 .xclbin 文件。
    • 依赖工具/环境: v++, .xsa 平台文件, .xo 内核文件。需要 XILINX_VITISXILINX_XRT 环境变量。
  7. 复制最终产物 (在 dpu.xclbin 规则的末尾):

    • 作用: 将 Vitis 链接过程中生成的 .hwh, .bit, 和 .xclbin 文件从 Vitis 的临时构建目录 (binary_container_1/...) 复制到项目的主目录 (${DIR_PRJ}) 并重命名为 dpu.hwh, dpu.bit, dpu.xclbin。这是为了方便 PYNQ 使用。
    • 动作: 执行三个 cp 命令。
    • 依赖工具/环境: cp

总结:工具和环境

这个 Makefile 明确地使用了以下核心 Xilinx 工具:

  1. Vivado (vivado): 用于:
    • 生成 Vitis 硬件平台 (.xsa) (通过 gen_platform.tcl)。
    • 将 DPU RTL 源代码编译/打包成 Vitis 内核对象 (.xo) (通过 gen_dpu_xo.tcl)。
  2. Vitis Compiler/Linker (v++): 用于:
    • 将内核 (.xo) 链接到平台 (.xsa)。
    • 生成最终的 .xclbin 文件 (内部包含比特流和元数据)。

必要的环境设置 (需要在运行 make 之前完成):

  1. 安装 Vitis: 需要完整的 Vitis 安装 (包括 Vivado)。
  2. 安装 XRT: Xilinx Runtime 是 Vitis 运行和构建的基础。
  3. 设置环境变量:
    • source <vitis-install-path>/Vitis/<version>/settings64.sh: 设置 Vitis 和 Vivado 相关的环境变量 (包括 XILINX_VITIS, XILINX_VIVADO, 并将工具添加到 PATH)。
    • source /opt/xilinx/xrt/setup.sh (或类似路径): 设置 XRT 相关的环境变量 (包括 XILINX_XRT, 并更新库路径)。
  4. Xilinx Board Files (XBF): 需要克隆或下载目标板的板级文件 (Makefile 提示从 XilinxBoardStore 获取)。
  5. 传递 BOARD 变量: 运行 make 时必须指定 BOARD,例如 make BOARD=zcu104
  6. 标准的 Linux 构建环境: make, bash, wget, tar, cp, mv, rm, mkdir, sed
  7. 网络连接: 用于 wget 下载 DPU TRD。

这个 Makefile 完美地展示了如何使用 Vitis 流程来构建一个包含预定义 RTL 内核 (DPU) 的硬件设计,并最终生成 PYNQ 和 VART/XRT 所需的所有文件 (.bit, .hwh, .xclbin)。

疑难解答

不能先用 Vivado 生成最终的 .bit.hwh 文件,然后 独立地使用 v++ 命令为 同一个设计 生成一个功能匹配的 .xclbin 文件。 你必须通过包含 Vitis 链接阶段的流程来生成 .xclbin

以下是详细解释:

  1. Vivado 的角色和输出:

    • Vivado 主要负责硬件设计(RTL、IP 集成)、综合、实现(布局布线)。
    • 对于嵌入式系统(如 Zynq),Vivado 可以导出:
      • .bit: FPGA 配置文件。
      • .hwh: 硬件描述文件,包含 IP 地址映射、中断等信息,主要供 PYNQ 和 Vitis 经典(SDK 风格)驱动生成使用。
      • .xsa: 硬件平台规范文件。这是关键!它定义了处理器配置、时钟、可用接口(AXI 等)、内存映射等,作为 Vitis 工具链的输入
  2. Vitis (v++) 的角色和输入/输出:

    • Vitis 设计用来构建加速应用程序,它工作在 Vivado 生成的平台 (.xsa) 之上
    • v++ --compile (v++ -c): 将 HLS C++/RTL 等编译成内核对象文件 (.xo)。
    • v++ --link (v++ -l): 这是关键的链接阶段。它需要:
      • 平台文件 (--platform <platform.xsa>): 定义了基础硬件。
      • 内核对象文件 (<kernel1>.xo, <kernel2>.xo …): 要集成到平台中的加速器内核(比如你的 HLS IP,或者像 DPU 这样的预编译 .xo)。
      • 可能的连接配置: 指定内核如何连接到平台的 AXI 接口、内存等。
    • v++ --link输出是:
      • .xclbin: 这是 XRT 运行时需要的容器文件。它内部包含了最终的比特流 (.bit),以及 XRT 管理内核所需的所有元数据(内核签名、内存连接拓扑、寄存器偏移、时钟信息等)。
      • 通常也会生成相关的报告文件。
  3. 为什么不能“后添加”.xclbin 信息?

    • .xclbin 不是简单地给一个现成的 .bit 文件加个“标签”。
    • Vitis 的 v++ --link 过程是一个集成和再实现的过程。它获取平台 (.xsa) 和内核 (.xo),然后决定如何将这些内核有效地放置在 FPGA 上并连接到平台接口。这个过程通常会重新运行部分或全部布局布线来生成最终的、包含平台和所有链接内核的比特流。
    • Vivado 生成的 .bit 文件只包含那个特定 Vivado 项目的硬件实现。它不知道 Vitis 内核、XRT 运行时所需的特定元数据或潜在的链接时优化。
    • .hwh 文件虽然描述了硬件,但它缺少 XRT 需要的完整运行时上下文和元数据。
  4. 正确的流程是什么?

    • 流程 A: Vitis 应用加速流程 (推荐用于 DPU + HLS IP)

      1. Vivado: 创建基础硬件平台。定义 PS 配置、时钟、可用 AXI 接口(比如连接 DPU 和 HLS IP 的接口)。导出 .xsa 文件。 (你可能也会在这个 Vivado 项目里放置一些“静态”的、非加速内核的 IP)。
      2. Vitis HLS (如果需要): 将你的 C++ 代码编译成 .xo 内核文件 (v++ -c)。
      3. Vitis Link (v++ -l):
        • 使用 Vivado 导出的 .xsa 作为平台 (--platform)。
        • 提供你的 HLS 内核 .xo 文件。
        • 提供 DPU 的 .xo 文件(通常由 Xilinx 提供)。
        • 指定连接方式。
        • 运行 v++ --link 命令。
        • 输出得到 .xclbin 文件。 这个 .xclbin 文件内部就包含了最终配置 FPGA 所需的比特流。
      4. 后续: 使用这个 .xclbin 文件配合 XRT/VART 运行你的应用程序。
    • 流程 B: 纯 Vivado -> PYNQ (不适合直接运行 DPU)

      1. Vivado: 完成包含 HLS IP 的完整硬件设计。生成 .bit.hwh 文件。
      2. PYNQ: 加载 .bit/.hwh,通过 PYNQ API 直接控制 HLS IP。

总结:

  • 你不能将 Vivado 生成的 .bit/.hwh 和 Vitis 生成的 .xclbin 视为可以独立生成然后“混合”的东西。
  • 要获得用于 XRT/VART(进而用于 DPU)的 .xclbin 文件,你必须使用 Vitis 工具链的链接步骤 (v++ --link)
  • 这个链接步骤的输入是 Vivado 生成的平台文件 (.xsa) 和你的加速器内核 (.xo 文件)。
  • 链接步骤的输出是 .xclbin 文件,它里面已经包含了最终的比特流以及所有 XRT 需要的元数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值