用 Python 写 FPGA IP!—— MyHDL 自定义中断生成器实践

文章来源:OpenFPGA

使用 Python/MyHDL 创建自定义 FPGA IP,与 Vivado 集成,并通过 PYNQ 进行控制——实现软件上的简单硬件设计。

介绍

硬件开源编程利器MyHDL简介

传统上,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 接口

  • 中断管理:用于灵活中断控制的状态寄存器和使能寄存器

先决条件

硬件:

KR260.png

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

项目结构:

项目结构.png

构建 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 总线

寄存器:

寄存器.png

步骤 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

  • 点击“完成”

1.png

步骤 3:创建模块设计

  • 在“ Sources ”窗口中右键单击→创建块设计

  • 给它起个名字interrupt_demo

  • 单击“确定”

2.png

步骤 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

3.png

  • AXI Smart Memory Controller (axi_smc)通过 AXI4-Lite 将 PS 连接到自定义 IP

  • AXI 中断控制器(axi_intc)合并 PL 中断基地址:0xB0010000

4.png

  • 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:完成积木设计

最终的模块设计应该如下所示:

5.png

步骤 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 文档:

http://www.myhdl.org/

  • PYNQ 文档:

https://pynq.readthedocs.io/

  • Xilinx Vivado 文档:

https://www.xilinx.com/support/documentation/sw_manuals/xilinx2025_2/ug910-vivado-getting-started.pdf

  • 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 都能在软件和硬件世界之间架起一座桥梁。