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

目录

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++ 命令的详细用法。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GPT-SoVITS语音合成模型部署及使用

1、概述 GPT-SoVITS是一款开源的语音合成模型&#xff0c;结合了深度学习和声学技术&#xff0c;能够实现高质量的语音生成。其独特之处在于支持使用参考音频进行零样本语音合成&#xff0c;即使没有直接的训练数据&#xff0c;模型仍能生成相似风格的语音。用户可以通过微调模…

25.DDD数量关系

学习视频来源&#xff1a;DDD独家秘籍视频合集 https://space.bilibili.com/24690212/channel/collectiondetail?sid1940048&ctype0 文章目录 关系型数据库的数量关系领域模型的数量关系实现聚合数量关系聚合内聚合间具体说明代码 数量关系是本质吗&#xff1f;领域对象之…

GB28181系列二:TS、PS格式

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、TS、PS简介 二、PES格式 三、TS格式 3.1 固定字段 3.2、调整域(Adaptation field) 3.3、第一个可选域(optional fields) 3.4、第二个可选域(optional fields) 3.5、负载 3.6、PSI 四、PS格式 4.1、PS头…

OpenAI 正式赋予 ChatGPT 通过视频实时与用户互动的能力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

QT 国际化(翻译)

QT国际化&#xff08;Internationalization&#xff0c;简称I18N&#xff09;是指将一个软件应用程序的界面、文本、日期、数字等元素转化为不同的语言和文化习惯的过程。这使得软件能够在不同的国家和地区使用&#xff0c;并且可以根据用户的语言和地区提供本地化的使用体验。…

【大语言模型】LangChain 核心模块介绍(Chains、Retrieval、Tools)

【大语言模型】LangChain 核心模块 一、LangChain 核心模块 Chains1、简介2、应用场景3、使用技巧3.1、LCEL Chains3.2、Legacy Chains 4、实践演练 二、LangChain 核心模块 Retrieval1、简介2、应用场景2.1、需求说明2.2、实现思路 三、LangChain 核心组件 Tools1、应用场景2、…

webstorm开发uniapp(从安装到项目运行)

1、下载uniapp插件 下载连接&#xff1a;Uniapp Tool - IntelliJ IDEs Plugin | Marketplace &#xff08;结合自己的webstorm版本下载&#xff0c;不然解析不了&#xff09; 将下载到的zip文件防在webstorm安装路径下&#xff0c;本文的地址为&#xff1a; 2、安装uniapp插…

实现 RAM 时应该考虑的性能因素

实现 RAM 时应该考虑的性能因素 要高效地推断存储元件&#xff0c;需要考虑下列影响性能的因素&#xff1a; • 使用专用块还是分布式 RAM RAM 可以在专用块 RAM 或使用分布式 RAM 的 LUT 内实现。不同的选择会影响资源选择&#xff0c;同时还会严重地影响性 能和功耗…

【前端开发】HTML+CSS网页,可以拿来当作业(免费开源)

HTML代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content_lizhongyu"widthdevice-width, initial-scale1.0"><title>小兔鲜儿-新鲜、惠民、快捷<…

TongWe7.0-东方通TongWeb控制台无法访问 排查

**问题描述&#xff1a;**无法访问TongWeb的控制台 逐项排查&#xff1a; 1、控制台访问地址是否正确&#xff1a;http://IP:9060/console #IP是服务器的实际IP地址 2、确认TongWeb进程是否存在&#xff0c;执行命令&#xff1a;ps -ef|grep tongweb 3、确认TongWeb服务启动…

【Python入门】传输与运算成分

文章一览 前言一、print函数&#xff08;输出&#xff09;1、字符串和数值类型&#xff0c;可以直接输出2、变量&#xff1a;无论什么类型&#xff0c;数值、字符、列表、字典... 可以直接输出3. 格式化输出3.1 str.format() 方法3.2 f-string 方法 二、input 函数1、函数 eval…

Linux内核结构及源码概述

参考&#xff1a;深入分析LINUX内核源码 深入分析Linux内核源码 (kerneltravel.net) Linux 是一个庞大、高效而复杂的操作系统&#xff0c;虽然它的开发起始于 Linus Torvalds 一个人&#xff0c;但随着时间的推移&#xff0c;越来越多的人加入了 Linux 的开发和对它的不断完善…

linux - 存储管理

1.了解硬件 -- 磁盘 硬盘有机械硬盘(HDD)和固态硬盘(SDD) 接下来&#xff0c;主要以机械磁盘为例(更具代表性&#xff0c;在linux系统层面&#xff0c;无论是机械磁盘还是固态硬盘&#xff0c;文件的读取和写入都iNode(索引节点)管理文件的元数据和实际数据块) 1.盘片&#x…

某名校考研自命题C++程序设计——近10年真题汇总(上)

本帖更新一些某校的编程真题&#xff0c;总体来说不难&#xff0c;考察的都是基本功&#xff0c;92高校大一期末的难度&#xff0c;不过有些细节颇为繁琐&#xff0c;各位还是需要一定程度上注意的~ 目录 一.分数求和 二.大小写字母转换 三.判断当年天序 四.交替合并字符串…

滑动窗口算法专题

滑动窗口简介 滑动窗口就是利用单调性&#xff0c;配合同向双指针来优化暴力枚举的一种算法。 该算法主要有四个步骤 1. 先进进窗口 2. 判断条件&#xff0c;后续根据条件来判断是出窗口还是进窗口 3. 出窗口 4.更新结果&#xff0c;更新结果这个步骤是不确定的&#xff0c…

Prime2_解法二:openssl解密凭据

Prime2_解法二&#xff1a;openssl解密凭据 本博客提供的所有信息仅供学习和研究目的&#xff0c;旨在提高读者的网络安全意识和技术能力。请在合法合规的前提下使用本文中提供的任何技术、方法或工具。如果您选择使用本博客中的任何信息进行非法活动&#xff0c;您将独自承担全…

R语言的数据结构-向量

【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) R语言编程_夏天又到了的博客-CSDN博客 在R语言中&#xff0c;数据结构是非常关键的部分&#xff0c;它提…

SpringBoot使用Nacos进行application.yml配置管理

Nacos是阿里巴巴开源的一个微服务配置管理和服务发现的解决方案。它提供了动态服务发现、配置管理和 服务管理平台。Nacos的核心功能包括服务发现、配置管理和动态服务管理&#xff0c;使得微服务架构下的服务治理 变得简单高效。 Nacos的设计基于服务注册与发现、配置管理、动…

【Java学习笔记】Collections 工具类

一、基本介绍 Collections 是一个操作 Set、List 和 Map 等集合的工具类Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作 二、排序操作&#xff1a;&#xff08;均为 static 方法) 三、查找、替换

【含开题报告+文档+PPT+源码】基于ssm框架的购物交流圈交流及市场服务平台

开题报告 随着互联网技术的迅猛发展&#xff0c;社交网络和电子商务已成为人们日常生活中不可或缺的一部分。特别是在移动互联网的普及下&#xff0c;人们越来越倾向于通过在线平台进行交流、分享和购物。这种趋势为基于 SSM&#xff08;Spring、SpringMVC、MyBatis&#xff0…