文章来源:OpenFPGA
使用 Python/MyHDL 创建自定义 FPGA IP,与 Vivado 集成,并通过 PYNQ 进行控制——实现软件上的简单硬件设计。
介绍
传统上,FPGA 开发意味着编写 Verilog 或 VHDL 代码——这些语言功能强大但冗长,与现代软件工作流程格格不入。如果能用 Python 来描述硬件呢?Python 也是你用于软件开发、测试和数据分析的语言。
本项目演示了如何使用MyHDL (一种基于 Python 的硬件描述语言)创建自定义 FPGA IP 核,并将其集成到 Xilinx Vivado 中。通过 Python 的强大表达能力和 MyHDL 的硬件转换功能,我们可以使用熟悉的工具和语法来设计、仿真和部署 FPGA 逻辑。
最终成果:一个支持周期性(基于定时器)和软件触发中断的中断生成器 IP,通过 AXI4-Lite 与 Zynq UltraScale+ PS 完全集成,可以通过 PYNQ 的 Python 接口进行控制。
为什么选择 MyHDL?
MyHDL弥合了软件开发和硬件开发之间的差距:
Python 语法:用熟悉的 Python 代码编写硬件描述
仿真支持:在综合之前,使用 Python 测试硬件逻辑。
代码生成:自动将 Verilog 代码转换为 Vivado 集成所需的格式
模块化设计:可重用的接口定义和组件
类型安全:硬件感知类型检查可防止常见错误
项目概述
中断生成器 IP 提供:
两个独立的中断输出:独立的中断 1 和中断 2 通道
周期性中断模式:可配置的基于定时器的中断,带有 32 位周期计数器
软件触发模式:通过寄存器写入按需生成中断
基于寄存器的控制:用于配置和状态监控的 AXI4-Lite 接口
中断管理:用于灵活中断控制的状态寄存器和使能寄存器
先决条件
硬件:

Xilinx KR260 机器人入门套件 网络连接(用于 PYNQ 访问)
软件:
Ubuntu 24.04 LTS(构建主机)
Python 3.12
Vivado 2025.2(或兼容版本)
定制的 Yocto Linux 镜像,包含 PYNQ
参考:
https://www.hackster.io/wstanislaus/custom-yocto-linux-network-boot-for-xilinx-kr260-e22ac3
Jupyter Notebook 服务器(包含在 PYNQ 镜像中)
构建依赖项:
sudo apt-get update
sudo apt-get install -y python3.12 python3.12-venv make
项目结构:

构建 MyHDL IP
构建过程将基于 Python 的 MyHDL 代码转换为 Verilog,以便与 Vivado 集成。
步骤 1:构建 IP
cd myhdl
make all
这条命令:
创建一个 Python 3.12 虚拟环境
安装 MyHDL 软件包
将 MyHDL 代码转换为 Verilog
输出:build/interrupt_generator_ip.v
手动构建过程:
# Create virtual environment
python3.12 -m venv venv
source venv/bin/activate
# Install MyHDL
pip install --upgrade pip
pip install myhdl
# Convert to Verilog
PYTHONPATH=. python PL/MyHDL/src/interrupt_generator_ip/interrupt_generator_ip.py
生成的 Verilog 文件(interrupt_generator_ip.v)包含完整的 IP 核,带有 AXI4-Lite 接口,可直接用于 Vivado 集成。
MyHDL IP架构
核心组件:
中断生成器核心(interrupt_gen.py)实现周期性和软件触发的中断逻辑,管理周期计数器和中断状态,提供两个独立的中断输出。
IP Wrapper ( interrupt_generator_ip.py)将 AXI4-Lite 接口转换为内部 AxiLocal 格式,实例化中断生成器内核,并为 Vivado 生成 Verilog 输出。
AXI 接口(axi_lite.py,axi_local.py)标准 AXI4-Lite 从接口,用于内部路由的简化本地 AXI 总线
寄存器:

步骤 1:创建新项目
打开 Vivado 并选择“创建项目”
选择RTL 项目,然后单击“下一步”。
设置项目名称:interrupt_demo
选择项目路径
选择“Do not specify sources at this time”。
点击“Boards”,然后选择“Kria KR260 Robotics Starter Kit SOM”。
步骤 2:添加 MyHDL 生成的 Verilog
在 Vivado 中,右键单击Design Sources → Add Sources。
选择“Add or create design sources”
点击“Add Files”并导航至build/interrupt_generator_ip.v
点击“完成”

步骤 3:创建模块设计
在“ Sources ”窗口中右键单击→创建块设计
给它起个名字interrupt_demo
单击“确定”

步骤 4:添加IP核
将以下 IP 核添加到模块设计中:
Zynq UltraScale+ PS ( zynq_ultra_ps_e)双击配置启用PL-PS 时钟(100MHz)启用M_AXI_HPM0_LPD接口启用IRQ_F2P中断输入
中断生成器 IP (自定义 IP)在模块设计中右键单击 →添加模块从列表中选择这是 MyHDL 生成的 IPinterrupt_generator_ip_0

AXI Smart Memory Controller (axi_smc)通过 AXI4-Lite 将 PS 连接到自定义 IP
AXI 中断控制器(axi_intc)合并 PL 中断基地址:0xB0010000

Interrupt Concatenator(xlconcat)组合中断生成器输出,连接到 AXI 中断控制器
Processor System Reset (proc_sys_reset)PL逻辑复位控制器
步骤 5:连接IP核
连接以下部件:
PS → AXI SMC → Interrupt Generator:AXI4-Lite 接口
Interrupt Generator → Interrupt Concatenator:两个中断输出
Interrupt Concatenator → AXI Interrupt Controller:组合中断总线
AXI Interrupt Controller → PS :IRQ_F2P 中断输入
PS → 所有 IP :时钟和复位信号
步骤 6:创建 HDL 包装器
右键单击块设计 →创建 HDL 包装器
选择“让 Vivado 管理包装器并自动更新”
单击“确定”
步骤 7:完成积木设计
最终的模块设计应该如下所示:

步骤 8:生成比特流
步骤 9:导出硬件
File → Export → Export Hardware
Include bitstream
Export to interrupt_demo.xsa
PYNQ 集成
硬件平台导出后,现在可以使用 PYNQ 的 Python 接口与自定义 IP 进行交互。
步骤 1:将文件复制到 KR260
将以下内容复制到 KR260 开发板:
interrupt_demo.bit→/nfsroot/lib/firmware/
interrupt_demo.hwh→/nfsroot/lib/firmware/
APU/pynq_interrupt.ipynb→/nfsroot/home/xilinx/Notebook/
步骤 2:打开 Jupyter 服务器
在 Ubuntu 构建/开发机器上:
firefox http://172.20.1.2:9090/
找到pynq_interrupt.ipynb并打开它。
步骤 3:加载Overlay
from pynq import Overlay, Interrupt
import asyncio
# Load the FPGA overlay
overlay = Overlay('interrupt_demo.bit')
overlay.download()
# Get the interrupt generator IP
intr = overlay.interrupt_generator_ip_0
# Configure PL clock (100MHz)
overlay.clock_dict['fclk_clk0'] = 100000000
步骤 4:配置中断
# Register offsets
period1 = 0x00
period2 = 0x04
isr = 0x08
ier = 0x0C
trigger = 0x10
# Configure interrupt1 for software triggering
intr.write(period1, 0) # Disable periodic mode
intr.write(ier, 1) # Enable interrupt1
# Configure interrupt2 for periodic interrupts (1 second at 100MHz)
intr.write(period2, 100000000)
intr.write(ier, 2) # Enable interrupt2
步骤 5:处理中断
# Create interrupt instances
intr_inst1 = Interrupt('axi_intc', intr_id=0) # interrupt1
intr_inst2 = Interrupt('axi_intc', intr_id=1) # interrupt2
# Async interrupt handler
async def interrupt_handler(interrupt_object, interrupt_bit):
print("Handler task started. Waiting for interrupt...")
# Wait for interrupt
await interrupt_object.wait()
print("Interrupt received!")
# Clear the interrupt (write 1 to the bit to clear it)
intr.write(isr, interrupt_bit)
# Trigger software interrupt
intr.write(trigger, 1) # Trigger interrupt1
# Wait for interrupt
await interrupt_handler(intr_inst1, 1)
# Periodic interrupt will fire automatically
await interrupt_handler(intr_inst2, 2)
中断操作模式
周期性中断:
将周期寄存器设置为所需的时钟周期计数
在 IER 寄存器中启用中断
当计数器到期时,中断会自动触发。
中断发生时,ISR 位被置位。
软件清除 ISR 位以确认
软件触发中断:
将周期寄存器设置为 0(禁用周期模式)
在 IER 寄存器中启用中断
向 TRIGGER 寄存器位写入 1
Interrupt fires immediately
ISR 位已设置
软件清除 ISR 位以确认
设计优势
MyHDL 的优势:
快速原型开发:用 Python 编写硬件,用 Python 进行测试,然后转换为 Verilog 格式
代码复用:采用可复用接口定义的模块化设计
仿真:综合之前测试硬件逻辑。
可维护性:Python 的可读性使得硬件代码更容易理解。
整合优势:
标准接口:AXI4-Lite 提供与 PS 的标准连接。
PYNQ 兼容性:通过 Python 无缝控制自定义 IP
灵活配置:基于寄存器的控制支持运行时重新配置
中断支持:正确的 PL 到 PS 中断处理
资源
MyHDL 文档:
PYNQ 文档:
Xilinx Vivado 文档:
KR260 开发板文档:
https://www.xilinx.com/products/boards-and-kits/kria.html
定制 Yocto Linux 项目:
https://www.hackster.io/wstanislaus/custom-yocto-linux-network-boot-for-xilinx-kr260-e22ac3
本项目源文件
https://github.com/wstanislaus/Xilinx_KR260_Projects/tree/main/myhdl
结论
该项目表明,FPGA 开发并不意味着要放弃现代软件工具。通过使用 MyHDL,我们可以:
用 Python 编写硬件代码
利用 Python 的生态系统进行测试和仿真
生成用于 Vivado 集成的标准 Verilog
通过 PYNQ 的 Python 接口控制硬件
最终形成的开发工作流程既能让软件工程师感到自然流畅,又能保持 FPGA 设计的强大功能和灵活性。无论是在构建新的 IP 核原型、尝试软硬件协同设计,还是构建生产系统,MyHDL 都能在软件和硬件世界之间架起一座桥梁。