PYNQ - 自定义含 DPU 的 overlay 层(MPSoC)

news2025/7/15 15:05:45

目录

1. 简介

2. 通过脚本构建

2.1 准备工作

2.2 通过 Makefile 构建

2.3 Makefile 源码及解析

2.3.1 源码-中文注释

2.3.2 主要功能分析

2.3.3 vivado batch 模式

2.3.4 package_xo 命令

2.3.5 vitis v++ 命令

2.4 DPU 参数

2.4.1 Arch 选项卡

2.4.2 Advanced 选项卡

2.4.3 参数汇总

2.5 工程参数

2.5.1 prj_config 文件

2.5.2 clock 选项

2.5.3 connectivity 选项

2.5.4 advanced 选项

2.5.5 vivado 选项

2.6 在 PYNQ 中使用

3. 创建 vivado platform

3.1 创建 Vivado 工程

3.1.1 platform 属性

3.1.2 创建 Block Design

3.1.3 配置时钟与复位

3.1.4 添加中断控制器

3.1.5 连接模块

3.1.6 platform 属性设置

3.1.7 Verification

3.1.8 导出 Platform

3.2 执行自定义 Makefile

3.2.1 拷贝 XSA

3.2.2 修改 Makefile

3.2.3 修改 prj_config

3.2.4 执行脚本

3.2.5 在 PYNQ 中使用

3.3 关键语句

4. 重要命令和概念解释

4.1 XO 文件

4.1.1 通过 HLS 导出 xo

4.2 xclbin 文件

4.3 xclbinutil

5. 总结


1. 简介

应网友邀请,分享在 PYNQ 框架下,搭建自定义包含 DPU 的 overlay 的过程。

  • 使用 kv260 官方代码构建 DPU。
  • 使用 vivado 创建自定义平台,修改官方代码构建 DPU。
  • 构建 DPU 的 Makefie 解析。
  • 一些重要概念的解释。

2. 通过脚本构建

2.1 准备工作

1)下载 DPU-PYNQ:

Releases · Xilinx/DPU-PYNQ · GitHubDPU on PYNQ. Contribute to Xilinx/DPU-PYNQ development by creating an account on GitHub.icon-default.png?t=O83Ahttps://github.com/Xilinx/DPU-PYNQ/releases

目录结构:

├── boards
├── host
├── LICENSE
├── MANIFEST.in
├── pynq_dpu
├── pyproject.toml
├── README.md
└── setup.py

2)首先确保 Vitis 和 XRT 已安装,XRT安装方法见如下博文:

Vitis Accelerated Libraries 学习笔记--OpenCV 安装指南(附 XRT 安装)_vitis vision library-CSDN博客文章浏览阅读1.4k次,点赞37次,收藏9次。本文分享 ubuntu 环境下 Xilinx XRT 与 OpenCV 的安装指南。_vitis vision libraryhttps://blog.csdn.net/DongDong314/article/details/139803440

3)配置环境变量:

source /opt/xilinx/xrt/setup.sh
source /opt/Xilinx/Vitis/2022.1/settings64.sh

2.2 通过 Makefile 构建

以 KV260 为例。

通过 Makefile 构建需要输出以下三个文件:

  • dpu.bit
  • dpu.hwh
  • dpu.xclbin

执行以下代码即可。

cd <DPU-PYNQ-2.5.0>/boards/
make BOARD=kv260_som

执行完毕,可以在 <DPU-PYNQ-2.5.0>/boards/kv260_som 目录下,找到上述文件。

2.3 Makefile 源码及解析

2.3.1 源码-中文注释

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 check_env

# 默认规则
all : check_env DPU_TRD dpu.xclbin

# 如果用户没有设置VITIS_PLATFORM,则默认为板子目录中的platform.xsa文件
VITIS_PLATFORM ?= ${DIR_PRJ}/platform.xsa

# 如果没有提供平台,则使用gen_platform.tcl脚本生成一个平台
${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

# DPU IP的HDL源文件在DPU TRD流程中,更多信息请参阅Xilinx文档
DPU_TRD:
	wget -O DPUCZDX8G.tar.gz https://www.xilinx.com/bin/public/openDownload?filename=DPUCZDX8G.tar.gz && \
        tar xf DPUCZDX8G.tar.gz && \
	rm DPUCZDX8G.tar.gz

# 从TRD流程中获取的可选参数
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 HDL源文件列表
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 HDL源文件列表
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		

# 复制构建DPU设计所需的脚本
# 使用sed替换路径以反映我们的板子目录结构
${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.xml中的内核名称匹配
DPU_KERN_NAME = DPUCZDX8G
SFM_KERN_NAME = sfm_xrt_top

# 如果内核为DPU_SM,则添加softmax.xo
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

# 添加此规则以便从解压的TRD中成功复制源文件
# 否则makefile将失败
${DPU_HDLSRCS}: ${DPU_TRD}

# 规则:构建Vitis DPU内核
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} 

# 规则:生成PYNQ覆盖二进制文件,我们只使用硬件平台
# 软件组件由PYNQ镜像处理,因此使用--package.no_image选项
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

2.3.2 主要功能分析

1)变量定义:

DIR_PRJ = $(shell pwd)/${BOARD}  # 定义项目目录路径为当前路径加上板子名称
DIR_TRD = $(shell pwd)/DPUCZDX8G # 定义DPUCZDX8G目录路径为当前路径加上DPUCZDX8G
VIVADO_ROOT := $(XILINX_VIVADO)  # 定义Vivado根目录路径
RM = rm -f      # 定义删除文件命令
RMDIR = rm -rf  # 定义删除目录命令
VIVADO := ${VIVADO_ROOT}/bin/vivado # 定义Vivado命令路径
TARGET := hw   # 定义目标为硬件
KERNEL := DPU  # 定义内核名称为DPU
  • DIR_PRJ 和 DIR_TRD:定义项目和 DPU TRD(Target Reference Design)的目录。
  • VIVADO_ROOT 和 VIVADO:定义 Vivado 工具的路径。
  • TARGET 和 KERNEL:定义目标硬件和内核类型。
  • VITIS_PLATFORM:定义 Vitis 平台文件路径,如果未设置,则默认生成。

2)伪目标:

  • all:默认目标,依赖于 check_env、DPU_TRD 和 dpu.xclbin。
  • check_env:检查 vitis 和 XRT 的版本是否正确。

3)生成平台文件:

  • 如果 VITIS_PLATFORM 未设置,则运行 gen_platform.tcl 脚本生成平台文件。

4)环境检查:

  • 输出 BOARD 和 VITIS_PLATFORM 变量,并运行 check_env.sh 脚本。

5)下载和解压 DPU TRD:

  • 下载 DPU TRD 压缩包并解压。

6)DPU 和 Softmax 内核的 HDL 源文件:

  • 定义 DPU 和 Softmax 内核的 HDL 源文件路径。

7)复制必要的脚本:

  • 从 TRD 目录复制生成 DPU 和 Softmax 内核的 TCL 脚本,并进行路径替换。

8)生成 DPU 和 Softmax 内核:

  • 使用 Vivado 工具生成 DPU 和 Softmax 内核的 XO 文件。

9)生成 xclbin 文件:

  • 使用 Vitis 工具生成 xclbin 文件(dpu.xclbin),并复制相关文件(HWH和BIT文件)。

2.3.3 vivado batch 模式

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}

1)目标文件和依赖

binary_container_1/dpu.xo: ${DPU_HDLSRCS}
  • binary_container_1/dpu.xo,定义了一个规则的目标文件,这是想要生成的文件。
  • ${DPU_HDLSRCS},是这个目标的依赖文件,它是一个变量,代表 DPU 源文件的集合。只有当这些依赖文件发生变化时,目标文件才会被重新构建。

2)binary_container_1

@mkdir -p ${DIR_PRJ}/binary_container_1
  • 创建一个目录(如果它不存在的话)。mkdir -p 命令用于创建目录,-p 参数确保即使目录已经存在,也不会报错。${DIR_PRJ} 是一个变量,代表项目的目录。

3)删除已存在的目标文件

-@$(RM) ${DIR_PRJ}/$@
  • 删除已存在的目标文件以准备新的构建。
  • $(RM) 变量表示 rm -f,-@ 前缀的意思是即使命令失败也不会停止执行后续命令,并且 @ 会使得命令在执行时不显示在控制台。
  • ${DIR_PRJ}/$@ 中的 $@ 是自动变量,代表规则的目标文件名。

4)执行 vivado 命令

cd ${DIR_PRJ} ;\
	$(VIVADO) -mode batch -source scripts/gen_dpu_xo.tcl -notrace -tclargs $@ $(DPU_KERN_NAME) ${TARGET} ${BOARD}
  • 首先切换到项目目录 ${DIR_PRJ}
  • 执行 $(VIVADO) 命令,以批处理模式运行(-mode batch),并指定一个Tcl脚本(scripts/gen_dpu_xo.tcl)来生成目标文件。
  • -notrace 参数表示在执行过程中不显示详细的调试信息。
  • -tclargs 后面跟着的参数会传递给 Tcl 脚本,这里传递以下四个参数:
    • $@,即目标文件名。
    • ${DPU_KERN_NAME},DPU IP 核的名称。
    • ${TARGET},即目标平台名称。
    • ${BOARD},即板卡信息。

2.3.4 package_xo 命令

《Vitis 统一软件平台文档:应用加速开发(UG1393)》

1)gen_dpu_xo.tcl

if { $::argc != 4 } {
    puts "ERROR: Program \"$::argv0\" requires 4 arguments!\n"
    puts "Usage: $::argv0 <xoname> <krnl_name> <target> <device>\n"
    exit
}

set xoname    [lindex $::argv 0]
set krnl_name [lindex $::argv 1]
set target    [lindex $::argv 2]
set device    [lindex $::argv 3]
puts $xoname
set suffix "${krnl_name}_${target}_${device}"
if { [info exists ::env(DIR_PATH)] } {
    source -notrace $env(DIR_PRJ)/scripts/package_dpu_kernel.tcl
} else {
    source -notrace ./scripts/package_dpu_kernel.tcl
}

if {[file exists "${xoname}"]} {
    file delete -force "${xoname}"
}

if { [info exists ::env(DIR_PATH)] } {
    package_xo -xo_path ${xoname} -kernel_name ${krnl_name} -ip_directory ./packaged_kernel_${suffix} -kernel_xml $env(DIR_PRJ)/kernel_xml/dpu/kernel.xml
} else {
    package_xo -xo_path ${xoname} -kernel_name ${krnl_name} -ip_directory ./packaged_kernel_${suffix} -kernel_xml ./kernel_xml/dpu/kernel.xml
}
  • suffix 字符串,该字符串是 krnl_name、target 和 device 的组合。仅仅用于命名文件。

2)package_xo:

Package IP/Package XO Flow — Vitis™ Tutorials 2022.1 documentation

package_xo 命令来创建 vitis object ( .xo ) 文件。 package_xo 命令还将 IP 文件和 kernel.xml 文件打包到生成的 .xo 文件中。

package_xo  \
    -force  \
    -xo_path <path>/.../Vadd_A_B.xo \
    -kernel_name Vadd_A_B           \
    -ip_directory <path>/.../IP
  • package_xo:由 Vivado IP 创建 vitis object 文件 (.xo)。
  • -force:覆盖现有的内核文件(如果存在)。
  • -xo_path:xo 文件的路径和名称。
  • -kernel_name:要创建的内核的名称,应与 RTL 模块名称匹配。
  • -ip_directory:Vivado IP 的路径。

2.3.5 vitis v++ 命令

《Vitis 统一软件平台文档:应用加速开发(UG1393)》- Vitis 编译器命令

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

1)主要功能

  • 定义了一个目标 dpu.xclbin
  • 依赖于两个文件:$(kernel_xo) 和 $(VITIS_PLATFORM),即 platform.xsa 文件

2)v++ 介绍

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/$@ $<
  • --link (-l):用于将多个内核和单个目标硬件平台链接到赛灵思器件二进制文件 (xclbin) 中。
  • --package.no_imag:绕过 SD 卡镜像创建操作。

2.4 DPU 参数

2.4.1 Arch 选项卡

  • RAM Usage:在片上存储器中对权重、偏差和中间特征映射进行缓冲。高 RAM 用量表示片上存储器块将更大,使 DPUCZDX8G 能更灵活地 处理中间数据。

DPUCZDX8G 架构

低 RAM 用量

高 RAM 用量

B512

72

88

B1024

104

136

B4096

255

315

  • Channel augmentation:一种在DPU中提高计算效率的技术,它可以将多个小通道的特征图合并成一个大通道的特征图,从而减少内存访问次数和数据传输量。

DPUCZDX8G 架构

搭配通道增广使用的额外 LUT

B512

3121

B1024

3133

B4096

1701

  • Alu:DepthwiseConv(逐通道卷积),它是深度可分离卷积(Depthwise separable convolution)的第一步。它的特点是每个输入通道只用一个卷积核进行卷积,不会混合不同的输入通道。

ALU并行

LUT

FF

Block RAM

DSP

1

44212

88250

255

662

2

46599

92380

255

678

4(推荐)

51388

98525

255

710

8

60751

111329

255

774

2.4.2 Advanced 选项卡

  • dpu_2x Clock Gating:dpu_2x 时钟门控,添加 2x_clk 的使能信号,用于降低 DPU 功耗。
  • DSP Cascade:DSP 级联,用于设置 DSP48E slice(切片)级联链的最大长度。通常级联长度越长,使用的逻辑资源越少,但可能时序更糟。较短的级联长度可能不适合小型器件,因为小型器件需要更多硬件资源。建议在首次迭代中选择中间值(即 4),如果不满足时序,则调整该值。
  • DSP Usage:是否使用 DSP48E slice 来执行累加。如果所选 DSP 用量较低,那么在卷积模块中,DPUCZDX8G IP 会将 DSP slice 仅用于乘法。在高 DSP 用量模式下,DSP slice 将同时用于乘法和累加。因此,DSP 用量越高,耗用的 DSP slice 数量越多,耗用的 LUT 越少。
  • 时间戳:启用该选项时,DPUCZDX8G 会记录 DPUCZDX8G 工程执行综合的时间。禁用该选项时,该时间戳会保持上次 IP 更新时的值不变。
  • UltraRAM:每个Block RAM 都包含 2 个 18K slice,此 slice 可配置为 9b*4096、18b*2048 或36b*1024。UltraRAM 采用固定配置 72b*4096。DPUCZDX8G 中的存储器单元位宽为 ICP*8 位,深度为 2048。对于 B1024 架构,ICP 为 8,存储器单元位宽为 8*8 位。随后,每个存储器单元均可利用一个 UltraRAM 块来加以例化。当 ICP 大于 8 时,DPUCZDX8G 中的每个存储器单元都需要至少 2 个 UltraRAM 块。默认情况下,DPUCZDX8G 使用Block RAM 作为存储器单元。对于同时包含块 RAM 和 UltraRAM 的目标器件,请配置 UltraRAM 数量,以判定用于替换部分块 RAM 的 UltraRAM 数量。UltraRAM 数量应设置为 DPUCZDX8G 中每个存储器单元所需的 UltraRAM 数量的倍数。

2.4.3 参数汇总

You can modify the dpu_conf.vh file to change the DPU IP settings in the board folder. The adjustable settings of the DPU IP include:

  • DPU model number
  • URAM_ENABLE
  • RAM_USAGE_LOW
  • CHANNEL_AUGMENTATION_ENABLE
  • DWCV_ENABLE
  • POOL_AVG_ENABLE
  • RELU_LEAKYRELU_RELU6
  • DSP48_USAGE_HIGH
  • LOWPOWER_ENABLE
  • DEVICE Configuration

2.5 工程参数

2.5.1 prj_config 文件

1)prj_config 文件汇总路径:

<DPU-PYNQ-2.5.0>/boards/DPUCZDX8G/prj/Vitis/config_file
---
prj_config
prj_config_102_3dpu
prj_config_102_3dpu_LPD
prj_config_104_2dpu
prj_config_1dpu
prj_config_1dpu_l1s1
prj_config_1dpu_sfm

2)KV260_SOM 的 prj_config

[clock]

freqHz=200000000:DPUCZDX8G_1.aclk
freqHz=400000000:DPUCZDX8G_1.ap_clk_2

[connectivity]

sp=DPUCZDX8G_1.M_AXI_GP0:HPC0
sp=DPUCZDX8G_1.M_AXI_HP0:HP0
sp=DPUCZDX8G_1.M_AXI_HP2:HP1

nk=DPUCZDX8G:1

[advanced]
misc=:solution_name=link

#param=compiler.addOutputTypes=sd_card
#param=compiler.skipTimingCheckAndFrequencyScaling=1

[vivado]
prop=run.impl_1.strategy=Performance_Explore
#param=place.runPartPlacer=0

2.5.2 clock 选项

freqHz=200000000:DPUCZDX8G_1.aclk
freqHz=400000000:DPUCZDX8G_1.ap_clk_2

1)对于 ap_clk_2 和 aclk 这两个接口:

<dpu_ip>/Vitis/dpu/xdc/timing_clocks.xdc
---
[line 21]:set clk_1x [get_clocks -of_objects [get_ports aclk]]
[line 22]:set clk_2x [get_clocks -of_objects [get_ports ap_clk_2]]
<dpu_ip>/DPUCZDX8G_v4_0_0/ttcl/timing_clocks_xdc.ttcl
---
[line 31]:set clk_2x [get_clocks -of_objects [get_ports dpu_2x_clk     ] ]
...
[line 37]:set clk_1x [get_clocks -of_objects [get_ports m_axi_dpu_aclk ] ]

2)v++ 命令中的 --clock 选项

《Vitis 统一软件平台文档:应用加速开发(UG1393)》- Vitis 编译器命令 - [--clock 选项]

如果不指定 --clock.XXX 选项,则会对每个 kernel 默认时钟。对于含 2 个时钟的内核,来自平台的时钟 ID 0 将分配给 ap_clk,时钟 ID 1 则分配给 ap_clk_2。

总结:在此配置中,s_axi_clk 并未被指定,那么将会使用平台默认时钟,即 200MHz,m_axi_dpu_aclk 被指定为 200MHz 这个时钟,所以:s_axi_clk 与 m_axi_dpu_aclk(DPUCZDX8G_1.aclk -> clk_1x) 将会共用 200MHz 这个时钟。

3)等价的 clock 连接方式

id=1:DPUCZDX8G_1.aclk
id=2:DPUCZDX8G_1.ap_clk_2

2.5.3 connectivity 选项

sp=DPUCZDX8G_1.M_AXI_GP0:HPC0
sp=DPUCZDX8G_1.M_AXI_HP0:HP0
sp=DPUCZDX8G_1.M_AXI_HP2:HP1

nk=DPUCZDX8G:1

1)DPUCZDX8G 的 GP 接口

prj/Vivado/scripts/base/trd_bd.tcl:
---
[2633]    M_AXI_GP    [dict create "M_AXI_INSTR" {M_AXI_GP0}]

M_AXI_INSTR 是用于 DPUCZDX8G 指令提取的 32 位 AXI 存储器映射接口。

2)DPUCZDX8G 的 HP 接口

DPUCZDX8G 的两个 M_AXI 接口:

  • M_AXI_HP0 -> DPUx_M_AXI_DATA0
  • M_AXI_HP2 -> DPUx_M_AXI_DATA1

中间没有 M_AXI_HP1,不知为什么,从以下文件中能观察到 M_AXI 对应 DPU 内存访问空间。

prj/Vitis/kernel_xml/dpu/kernel.xml
---
[16]: <arg name="dpu_base0_addr"  ... id="5"  port="M_AXI_HP0"     size="0x8" offset="0x60" ...>
[17]: <arg name="dpu_base1_addr"  ... id="6"  port="M_AXI_HP0"     size="0x8" offset="0x68" ...>	
[18]: <arg name="dpu_base2_addr"  ... id="7"  port="M_AXI_HP0"     size="0x8" offset="0x70" ...>	
[19]: <arg name="dpu_base3_addr"  ... id="8"  port="M_AXI_HP0"     size="0x8" offset="0x78" ...>
[20]: <arg name="dpu_base4_addr"  ... id="9"  port="M_AXI_HP2"     size="0x8" offset="0x80" ...>
[21]: <arg name="dpu_base5_addr"  ... id="10" port="M_AXI_HP2"     size="0x8" offset="0x88" ...>
[22]: <arg name="dpu_base6_addr"  ... id="11" port="M_AXI_HP2"     size="0x8" offset="0x90" ...>
[23]: <arg name="dpu_base7_addr"  ... id="12" port="M_AXI_HP2"     size="0x8" offset="0x98" ...>

3)Number of Kernel

nk,即 Number of Kernel,该配置包含一个 DPUCZDX8G。

4)--connectivity 选项

《Vitis 统一软件平台文档:应用加速开发(UG1393)》- Vitis 编译器命令 - [--connectivity 选项]

2.5.4 advanced 选项

misc=:solution_name=link

advanced 选项包含三个子项,本配置只包含一个 misc 用于指定 solution_name。

  • misc
  • param
  • prop

2.5.5 vivado 选项

用于配置 Vivado 工具,以对器件二进制文件 (.xclbin) 执行综合与实现。例如:

  • 指定要生成的作业数量
  • impl run 的 LSF 命令
  • 要使用的特定实现策略
  • 还可配置最优化、布局、时序
  • 指定要输出的报告

2.6 在 PYNQ 中使用

执行 make BOARD=kv260_som 得到如下三个文件:

  • dpu.bit
  • dpu.hwh
  • dpu.xclbin

拷贝至 jupyter 中,即可使用。

3. 创建 vivado platform

3.1 创建 Vivado 工程

3.1.1 platform 属性

勾选 Project is an extensible Vitis platform

或者在工程创建后,通过 Settings 修改:

3.1.2 创建 Block Design

  • All Automation
  • Zynq_ultra_ps_e_0
  • Apply Board Presets

添加一个风扇控制,kv260 的专用风扇控制 IO:

I/O Configuration -> Low Speed -> Processing Unit -> TTC -> TTC0 -> Waveout: EMIO

该引脚绑定为:

set_property PACKAGE_PIN A12     [get_ports {fan_en_b[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {fan_en_b[0]}]

Slice 配置:

最后效果:

3.1.3 配置时钟与复位

  • V++ 链接器可以自动链接内核与平台之间的时钟信号。平台中可用的时钟信号通过 PFM.CLK 属性导出。
  • 对于简单的设计,中断信号可以由处理器的 pl_clk 来源。限制是处理器最多有 4 个 pl_clk,且它们的相位没有对齐。
  • 为了提供更多的中断信号,或提供相位对齐的时钟,可以使用 Clocking Wizard。
    • clk_out1 设为 75 MHz
    • clk_out2 设为 150 MHz
    • clk_out3 设为 300 MHz
    • clk_out4 设为 600 MHz
    • 复位类型为低电平有效

使用 pl_clk 作为输入时钟,并生成整个逻辑设计所需的时钟。

使用 75 MHz 的时钟作为 axi_lite 控制总线时钟。

300 MHz 和 600 MHz 的时钟被保留用于数据处理单元(DPU)AXI 接口时钟和 DPU 核心时钟,在设计链接阶段使用。

需要为每个时钟创建复位信号,因为在设置时钟导出时需要这些信号。

添加 4 个 proc_sys_reset 模块,分别命名为:

  • proc_rst_1
  • proc_rst_2
  • proc_rst_3
  • proc_rst_4

3.1.4 添加中断控制器

V++ 链接器可以自动链接内核与平台之间的中断信号。

1)添加一个 AXI LPD Master 接口

  • 使用 AXI HPM0 LPD 进行寄存器控制,它的数据位宽是 32 位。
  • 如果 Master 接口超过 32 位,比如 AXI HPM0 FPD,则 AXI 互连或 SmartConnect 将使用 PL 逻辑进行 AXI 总线宽度转换。这将消耗逻辑资源并引入不必要的延迟。
  • 在 Block Design 中禁用 AXI HPM0 FPD 和 AXI HPM1 FPD,可以防止它们被自动连接。
  • 可以在平台设置中导出未使用的 AXI 接口,无论它是否在 Block Design 中可见。

2)添加一个 AXI Interrupt Controller

对稳定性来说,中断控制器和别的内核 IRQ 信号同步到一个时钟是最好的。但如果内核在不同的时钟下运行,不用担心异步 IRQ。中断控制器也可以很好地管理带有电平中断信号的异步 IRQ

3.1.5 连接模块

  • 使用 75 MHz 连接 M_AXI_HPM0_LPD 相关模块。
  • M_AXI_HPM0_LPD  复位选择 interconnect_aresetn 信号。

3.1.6 platform 属性设置

Windows -> Platform Setup

1)时钟

注意:Platform 应该有且只有一个默认时钟。在 v++ 链接过程中,如果没有指定的链接配置,链接器将使用默认时钟来连接 IP 块。

2)中断

3)AXI Port

  • Memport: Memory Port
  • M_AXI_GP: General Purpose AXI Master
  • SP Tag: Slave Port Tag

4)Platform Name

  • Name: kv260_hardware_platform
  • Board: kv260
  • Vendor: xilinx
  • Version: 0.0

3.1.7 Verification

注意:在验证过程中,Vivado 会报告 /axi_intc_0/intr 未连接的严重警告。请忽略此警告,因为 v++ 链接器会将内核中断信号链接到此浮动 intr 信号。

[PFM-48] Interrupt pin /xlconcat_0/In0 does not have an assigned id.
It is being assigned ID 1.

3.1.8 导出 Platform

1)Generate HDL Wrapper

2)Generate Output Product

3)Export Platform

注意:确保Utility Sources - utils_1 下没有dcp 文件,否则会导致脚本运行期间出错。

<...>/kv260_platform.srcs/utils_1/imports/synth_1/design_1_wrapper.dcp' does not exist

...
ERROR: [v++ 60-661] v++ link run 'run_link' failed
ERROR: [v++ 60-626] Kernel link failed to complete
ERROR: [v++ 60-703] Failed to finish linking
INFO: [v++ 60-1653] Closing dispatch client.
make: *** [Makefile:116: dpu.xclbin] Error 1

3.2 执行自定义 Makefile

3.2.1 拷贝 XSA

将上一步导出的 XSA 文件放到自定义的板卡目录下,如 kv260_my

3.2.2 修改 Makefile

DPU_TRD:
	wget -O DPUCZDX8G.tar.gz https://www.xilinx.com/bin/public/openDownload?filename=DPUCZDX8G.tar.gz && \
        tar xf DPUCZDX8G.tar.gz && \
	rm DPUCZDX8G.tar.gz

修改为:

DPU_TRD:
	tar xf DPUCZDX8G.tar.gz

目的:避免每次下载 DPUCZDX8G.tar.gz,经常会无法建立连接。

3.2.3 修改 prj_config

[clock]
freqHz=300000000:DPUCZDX8G_1.aclk
freqHz=600000000:DPUCZDX8G_1.ap_clk_2

[connectivity]
sp=DPUCZDX8G_1.M_AXI_GP0:HPC0
sp=DPUCZDX8G_1.M_AXI_HP0:HP0
sp=DPUCZDX8G_1.M_AXI_HP2:HP1
nk=DPUCZDX8G:1

[advanced]
misc=:solution_name=link

[vivado]
prop=run.impl_1.strategy=Performance_Explore
impl.jobs=16
synth.jobs=16

新增了:

impl.jobs=16
synth.jobs=16

用于加快执行速度,需根据 CPU 和内存容量设定,否则会导致脚本执行失败。

3.2.4 执行脚本

make BOARD=kv260_my

执行完毕:

INFO: [v++ 60-1653] Closing dispatch client.
cp -f /home/fl/Documents/DPU-PYNQ-2.5.0/boards/kv260_my/binary_container_1/link/vivado/vpl/prj/prj.gen/sources_1/bd/*/hw_handoff/*.hwh \
        /home/fl/Documents/DPU-PYNQ-2.5.0/boards/kv260_my/dpu.hwh
cp -f /home/fl/Documents/DPU-PYNQ-2.5.0/boards/kv260_my/binary_container_1/link/vivado/vpl/prj/prj.runs/impl_1/*.bit \
        /home/fl/Documents/DPU-PYNQ-2.5.0/boards/kv260_my/dpu.bit
cp -f /home/fl/Documents/DPU-PYNQ-2.5.0/boards/kv260_my/binary_container_1/dpu.xclbin \
        /home/fl/Documents/DPU-PYNQ-2.5.0/boards/kv260_my/dpu.xclbin

3.2.5 在 PYNQ 中使用

执行 make BOARD=kv260_som 得到如下三个文件:

  • dpu.bit
  • dpu.hwh
  • dpu.xclbin

拷贝至 jupyter 中,即可使用。

3.3 关键语句

1)vivado 命令

<...>/vivado -mode batch                        \
             -source scripts/gen_dpu_xo.tcl     \
             -notrace                           \
             -tclargs binary_container_1/dpu.xo DPUCZDX8G hw kv260_my
  • -mode batch:这个选项告诉Vivado以批处理模式运行,即不弹出图形用户界面,而是直接按照脚本执行命令。 
  • -source scripts/gen_dpu_xo.tcl:指定了要执行的Tcl脚本。
  • -notrace:这个选项关闭了Vivado的跟踪功能,可以减少输出信息,提高执行效率。
  • -tclargs 后面跟着的参数会传递给 Tcl 脚本。

2) v++ 命令

v++ -t hw
    --platform <...>/boards/kv260_som/platform.xsa
    --save-temps
    --config <...>/boards/kv260_som/prj_config
    --xp param:compiler.userPostSysLinkOverlayTcl=<...>/boards/DPUCZDX8G/prj/Vitis/syslink/strip_interconnects.tcl
    -l
    --temp_dir binary_container_1
    --log_dir  binary_container_1/logs
    --package.no_image
    --remote_ip_cache binary_container_1/ip_cache
    -o <...>/boards/kv260_som/binary_container_1/dpu.xclbin
    binary_container_1/dpu.xo

3)xclbinutil 命令

xclbinutil --add-section BITSTREAM:RAW:<...>/boards/kv260_som/binary_container_1/link/int/system.bit
           --force
           --target hw
           --key-value SYS:dfx_enable:false
           --add-section :JSON:<...>/boards/kv260_som/binary_container_1/link/int/dpu.rtd
           --add-section CLOCK_FREQ_TOPOLOGY:JSON:<...>/boards/kv260_som/binary_container_1/link/int/dpu_xml.rtd
           --add-section BUILD_METADATA:JSON:<...>/boards/kv260_som/binary_container_1/link/int/dpu_build.rtd
           --add-section EMBEDDED_METADATA:RAW:<...>/boards/kv260_som/binary_container_1/link/int/dpu.xml
           --add-section SYSTEM_METADATA:RAW:<...>/boards/kv260_som/binary_container_1/link/int/systemDiagramModelSlrBaseAddress.json
           --key-value   SYS:PlatformVBNV:xilinx_board_kv260_pfm_0_0
           --output <...>/boards/kv260_som/binary_container_1/dpu.xclbin
xclbinutil --quiet
           --force
           --info  <...>/boards/kv260_som/binary_container_1/dpu.xclbin.info
           --input <...>/boards/kv260_som/binary_container_1/dpu.xclbin

4. 重要命令和概念解释

4.1 XO 文件

.xo 文件是 Xilinx 对象文件(Xilinx Object File),主要用于 Vitis 开发环境中。它包含了硬件加速内核的二进制表示,可以在 FPGA 上执行。以下是 .xo 文件的一些关键点:

  • 生成:.xo 文件通常由 Vivado 或 Vitis HLS 生成,包含了硬件内核的实现。
  • 用途:在 Vitis 中,.xo 文件被用作硬件加速内核,可以与其他内核和主机代码链接,生成最终的 FPGA 可执行文件(.xclbin)。
  • 集成:您可以将 .xo 文件导入 Vitis 项目中,作为硬件加速部分的一部分进行编译和链接。

4.1.1 通过 HLS 导出 xo

1)在 Synthesis Settings 中,选择 Vitis Kernel Flow Target

// Read Data from Global Memory and write into Stream inStream
static void read_input(uint32_t* in, hls::stream<uint32_t>& inStream, int vSize) {
// Auto-pipeline is going to apply pipeline to this loop
mem_rd:
    for (int i = 0; i < vSize; i++) {
#pragma HLS LOOP_TRIPCOUNT min = size max = size
        // Blocking write command to inStream
        inStream << in[i];
    }
}

// Read Input data from inStream and write the result into outStream
static void compute_add(hls::stream<uint32_t>& inStream1,
                        hls::stream<uint32_t>& inStream2,
                        hls::stream<uint32_t>& outStream,
                        int vSize) {
// Auto-pipeline is going to apply pipeline to this loop
execute:
    for (int i = 0; i < vSize; i++) {
#pragma HLS LOOP_TRIPCOUNT min = size max = size
        // Blocking read command from inStream and Blocking write command
        // to outStream
        outStream << (inStream1.read() + inStream2.read());
    }
}

// Read result from outStream and write the result to Global Memory
static void write_result(uint32_t* out, hls::stream<uint32_t>& outStream, int vSize) {
// Auto-pipeline is going to apply pipeline to this loop
mem_wr:
    for (int i = 0; i < vSize; i++) {
#pragma HLS LOOP_TRIPCOUNT min = size max = size
        // Blocking read command to inStream
        out[i] = outStream.read();
    }
}

extern "C" {
/*
    Vector Addition Kernel Implementation using dataflow
    Arguments:
        in1   (input)  --> Input Vector 1
        in2   (input)  --> Input Vector 2
        out   (output) --> Output Vector
        vSize (input)  --> Size of Vector in Integer
*/
void krnl_vadd(uint32_t* in1, uint32_t* in2, uint32_t* out, int vSize) {
    static hls::stream<uint32_t> inStream1("input_stream_1");
    static hls::stream<uint32_t> inStream2("input_stream_2");
    static hls::stream<uint32_t> outStream("output_stream");
#pragma HLS INTERFACE m_axi port = in1 bundle = gmem0 depth = 4096
#pragma HLS INTERFACE m_axi port = in2 bundle = gmem1 depth = 4096
#pragma HLS INTERFACE m_axi port = out bundle = gmem0 depth = 4096

#pragma HLS dataflow
    // dataflow pragma instruct compiler to run following three APIs in parallel
    read_input(in1, inStream1, vSize);
    read_input(in2, inStream2, vSize);
    compute_add(inStream1, inStream2, outStream, vSize);
    write_result(out, outStream, vSize);
}
}

2)完成 C Synthesis 后,导出 RTL

注意,如果选择 Vivado IP Flow Target 流程,则无 xo 选项。

4.2 xclbin 文件

xclbin container format(也称为 AXLF,Accelerated eXecutable and Linkable Format),由文件 xclbin.h 定义 。该文件使用 xclbin2 作为魔术字。 AXLF 是基于 section 的可扩展容器。不同 section 存储已编译应用程序的不同部分,例如 PL(FPGA)的比特流、AIE 块的 ELF 以及 Microblaze 等嵌入式处理器。它还包含结构良好的元数据,用于定义内存拓扑、实例化外设和计算内核的 IP 布局、每个计算内核的时钟详细信息和内核连接。

编译器为每个编译的应用程序生成带有 UUID 标记的唯一 xclbin 文件。每个 xclbin 还有一个另一个 UUID,用于定义其与 Shell 的兼容性。 Vitis 编译器、v++ 生成此文件作为链接阶段的一部分。最终用户通过 XRT xclLoadXclbin() API 加载此文件。 XRT 用户空间和内核空间组件通过对硬件进行编程并初始化 XRT 用户空间库和 XRT 内核驱动程序中的关键数据结构来消耗 xclbin 的不同部分。

xclbin.h 的路径是 XRT 安装目录中的 xrt/include/xclbin.h

struct axlf_section_header {
    uint32_t m_sectionKind;             /* Section type */
    char m_sectionName[16];             /* Examples: "stage2", "clear1", "clear2", "ocl1", "ocl2, "ublaze", "sched" */
    uint64_t m_sectionOffset;           /* File offset of section data */
    uint64_t m_sectionSize;             /* Size of section data */
};

struct axlf {
    char m_magic[8];                            /* Should be "xclbin2\0"  */
    int32_t m_signature_length;                 /* Length of the signature. -1 indicates no signature */
    unsigned char reserved[28];                 /* Note: Initialized to 0xFFs */

    unsigned char m_keyBlock[256];              /* Signature for validation of binary */
    uint64_t m_uniqueId;                        /* axlf's uniqueId, use it to skip redownload etc */
    struct axlf_header m_header;                /* Inline header */
    struct axlf_section_header m_sections[1];   /* One or more section headers follow */
};

XRT 提供了一个非常强大的实用程序 xclbinutil ,可用于读取/写入/更改 xclbins。

4.3 xclbinutil

xclbinutil可以创建、修改和报告 xclbin 内容信息。

通过 -info 选项可以获取各种信息,包括创建日期、硬件平台、时钟、内存配置、内核、工具生成选项等信息。请注意,可以选择指定输出文件。如果未指定,则输出将转到控制台。

5. 总结

本文演示相关步骤和代码示例,分享了在 PYNQ 框架下搭建自定义包含 DPU 的 overlay 的完整指南。

有以下难点并未完全理解,持续探索中:

  • xclbin 文件的完整生成步骤。
  • v++ 命令的详细用法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2259303.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

路径规划之启发式算法之十六:和声搜索算法(Harmony Search, HS)

和声搜索算法(Harmony Search, HS)是一种新兴的启发式全局搜索算法,是一种模拟音乐家即兴演奏过程的群体智能优化算法。这种算法由Zong Woo Geem等人在2001年提出,灵感来源于音乐家在寻找和声时的创造性思维过程。HS算法通过模拟音乐家演奏音乐时的选择过程来寻找问题的最优…

【Vulkan入门】14-ShowBySDL

文章目录 先叨叨关键代码Git信息main.cpp 运行结果接下来我会做什么重构代码在b站出一套视频 先叨叨 上篇我们让Vulkan渲染了一个三角形&#xff0c;但还没有把它显示出来。本篇介绍一下&#xff0c;如何使用SDL将这个图形显示出来。 原理其实很简单&#xff0c;就是将渲染的内…

uni-app多环境配置动态修改

前言 这篇文章主要介绍uniapp在Hbuilderx 中&#xff0c;通过工程化&#xff0c;区分不同环境、动态修改小程序appid以及自定义条件编译&#xff0c;解决代码发布和运行时手动切换问题。 背景 当我们使用uniapp开发同一个项目发布不同的环境二级路径不同时&#xff0c;这时候…

.NET平台使用C#设置Excel单元格数值格式

设置Excel单元格的数字格式是创建、修改和格式化Excel文档的关键步骤之一&#xff0c;它不仅确保了数据的正确表示&#xff0c;还能够增强数据的可读性和专业性。正确的数字格式可以帮助用户更直观地理解数值的意义&#xff0c;减少误解&#xff0c;并且对于自动化报告生成、财…

单目深度估计模型 lite-mono 测试

lite-mono 使用工业数据集kitti 进行训练&#xff0c;目的使用单目摄像头实现物体深度预测&#xff0c;关于kitti数据集的介绍和下载参考 &#xff08;二&#xff09;一文带你了解KITTI数据集-CSDN博客文章浏览阅读2.7w次&#xff0c;点赞64次&#xff0c;收藏294次。文章介绍…

单片机锂电池电量电压检测

一、引言 &#xff08;一&#xff09;锂电池电量检测的重要性简述 在如今这个科技飞速发展的时代&#xff0c;众多电子设备都依赖锂电池来供电&#xff0c;像我们日常使用的智能手机、平板电脑、笔记本电脑&#xff0c;还有出行必备的电动自行车、电动汽车等等&#xff0c;锂…

Android通过okhttp下载文件(本文案例 下载mp4到本地,并更新到相册)

使用步骤分为两步 第一步导入 okhttp3 依赖 第二步调用本文提供的 utils 第一步这里不做说明了&#xff0c;直接提供第二步复制即用 DownloadUtil 中 download 为下载文件 参数说明 这里主要看你把 destFileName 下载文件名称定义为什么后缀&#xff0c;比如我定义为 .mp4 下…

华为eNSP:VRRP

一、VRRP背景概述 在现代网络环境中&#xff0c;主机通常通过默认网关进行网络通信。当默认网关出现故障时&#xff0c;网络通信会中断&#xff0c;影响业务连续性和稳定性。为了提高网络的可靠性和冗余性&#xff0c;采用虚拟路由冗余协议&#xff08;VRRP&#xff09;是一种…

2.生成Transformation

目录 前言 Source FlatMap KeyBy sum print 总结 前言 以下面的WordCount为例 package com.wlh.p1;import org.apache.flink.api.common.functions.FlatMapFunction; import org.apache.flink.api.java.functions.KeySelector; import org.apache.flink.api.java.tuple…

PCL点云库入门——PCL库可视化之CloudViewer类简单点云信息显示

1、前言 可视化&#xff08;visualization&#xff09;涉及运用计算机图形学和图像处理技术&#xff0c;将数据转换成图像并在屏幕上展示&#xff0c;同时支持交互式处理。在PCL库中&#xff0c;一系列强大的可视化工具可供使用&#xff0c;其中较为流行的包括CloudViewer和PCL…

AI大模型学习笔记|多目标算法梳理、举例

多目标算法学习内容推荐&#xff1a; 1.通俗易懂讲算法-多目标优化-NSGA-II(附代码讲解)_哔哩哔哩_bilibili 2.多目标优化 (python pyomo pareto 最优)_哔哩哔哩_bilibili 学习笔记&#xff1a; 通过网盘分享的文件&#xff1a;多目标算法学习笔记 链接: https://pan.baidu.com…

印闪网络:阿里云数据库MongoDB版助力金融科技出海企业降本增效

客户背景 上海印闪网络科技有限公司&#xff0c;于2017年1月成立&#xff0c;投资方包括红杉资本等多家国际知名风投公司。公司业务聚焦东南亚普惠金融&#xff0c;常年稳居行业头部。创始团队来自腾讯&#xff0c;中国团队主要由运营、风控及产研人员组成&#xff0c;核心成员…

路由引入问题(双点双向路由回馈问题)

简介 总所周知&#xff0c;路由引入import又称路由重分发redistribute&#xff0c;为了解决不同路由协议进程间路由信息不互通而使用的技术&#xff0c;由于不同路由协议的算法、机制、开销等因素的差异&#xff0c;它们之间无法直接交换路由信息。因此&#xff0c;路由引入技…

windows安装gradle

目录 1. gradle的简介2. 安装操作2.1 下载2.2 配置环境变量2.3 测试验证 3. 总结 1. gradle的简介 Gradle 是一个开源的项目自动化构建工具&#xff0c;专注于灵活性和性能。它基于 Apache Ant 和 Apache Maven 的概念&#xff0c;但采用了 Groovy 或 Kotlin 作为领域特定语言…

数据库中的代数运算

这些代数基本运算通常被封装在数据库查询语言中&#xff0c;如SQL中的SELECT、FROM、WHERE等子句&#xff0c;使得用户可以更方便地对数据库进行查询和处理。 下面的介绍基于以下两个关系来说明&#xff1a; 传统的集合运算 并&#xff08;∪&#xff09; 合并两个关系中的元组…

Linux驱动开发(12):中断子系统–按键中断实验

本章我们以按键为例讲解在驱动程序中如何使用中断&#xff0c; 在学习本章之前建议先回顾一下关于中断相关的裸机部分相关章节&#xff0c; 这里主要介绍在驱动中如何使用中断&#xff0c;对于中断的概念及GIC中断控制器相关内容不再进行讲解。 本章配套源码和设备树插件位于“…

智能家居WTR096-16S录放音芯片方案,实现语音播报提示及录音留言功能

前言&#xff1a; 在当今社会的高速运转之下&#xff0c;夜幕低垂之时&#xff0c;许多辛勤工作的父母尚未归家。对于肩负家庭责任的他们而言&#xff0c;确保孩童按时用餐与居家安全成为心头大事。此时&#xff0c;家居留言录音提示功能应运而生&#xff0c;恰似家中的一位无形…

【Qt】信号、槽

目录 一、信号和槽的基本概念 二、connect函数&#xff1a;关联信号和槽 三、自定义信号和槽 1.自定义槽函数 2.自定义信号函数 例子&#xff1a; 四、带参的信号和槽 例子&#xff1a; 五、Q_OBJECT宏 六、断开信号和槽的连接 例子&#xff1a; 一、信号和槽的基本…

Zemax 中的 LED 阵列模型

LED 阵列的光学特性 LED 阵列由多个发光二极管 &#xff08;LED&#xff09; 组成&#xff0c;这些二极管以特定模式或配置排列&#xff0c;以实现均匀照明、更高强度或特定照明特性。这些阵列广泛用于显示器、照明系统、光通信和传感等应用。 LED 阵列的光学特性对于了解它如…

Qt编写区位码gb2312、机内码、国标码————附带详细介绍和编码实现

文章目录 0 背景1 了解编码1.1 ASCII码1.2 机内码、国标码、区位码1.2.1 区位码1.2.2 国标码&#xff08;GB 2312-80&#xff09;1.2.3 汉字机内码&#xff08;GB 2312&#xff09; 1.3 GBK和GB2312的区别2 编码实现2.1 QString数据转QByteArray类型2.1.1 使用QTextCodec2.1.2 …