Amaranth HDL

类似myhdl的Python转HDL

参考

Vitis HLS 例子

myhdl文档
官方文档
在线 Playground
GitHub
Verilog规则和常用模板

1. 背景:硬件描述语言的困境

传统的硬件描述语言------Verilog 和 VHDL------诞生于上世纪 80 年代,其核心设计目标是"仿真"而非"综合"。几十年下来,工程师们积累了大量"综合安全子集"的经验,形成了各种 lint 规则和编码规范,本质上是在用外力约束语言本身的危险特性。

这带来了几个长期痛点:

  • 意外生成 latch(忘记在 always 块中给信号赋默认值)
  • 阻塞赋值(=)和非阻塞赋值(<=)的混用陷阱
  • 代码复用困难,参数化模块写起来极为繁琐
  • 测试基础设施薄弱,与现代软件工程工具链脱节

Amaranth HDL(前身是 nMigen)正是为了解决这些问题而生的。


2. Amaranth 是什么

Amaranth 是一个以 Python 为宿主语言的硬件描述语言(HDL),由 whitequark 主导开发,以两条款 BSD 协议开源。它不是把 Python 编译成硬件,而是用 Python 的类和对象来构建一棵描述数字逻辑的 AST(抽象语法树),再由工具链将其转换为 Verilog-2001,最终送入各家 FPGA 的综合器。

整个工具链由四个部分组成:

复制代码
Amaranth 语言  →  标准库  →  仿真器  →  构建系统
  • 语言:Python 库,提供 Signal、Module、ClockDomain 等核心原语
  • 标准库:FIFO、仲裁器、流接口等常用组件
  • 仿真器:纯 Python 实现,事件驱动,支持多时钟域
  • 构建系统:对接 Yosys+nextpnr 等 FOSS 工具链,以及 Lattice、Xilinx 等厂商工具

3. 在线 Playground:零门槛上手

Playground

官方提供了一个基于 WebAssembly 的在线 Playground,在浏览器里就能运行完整的 Amaranth 代码------包括仿真。它的技术底座是把 Yosys 编译为 WASM,再通过 wasmtime-py 驱动,做到了真正的本地运算,不需要后端服务器。

这对学习和快速验证逻辑非常有价值。打开页面即可编写代码、运行仿真、观察波形,不需要安装任何东西。


4. 核心概念详解

4.1 Signal:比特的容器

python 复制代码
from amaranth.hdl import *

# 4 位无符号信号,复位值为 0
counter = Signal(4)

# 1 位信号(默认)
enable = Signal()

# 有符号信号
offset = Signal(shape=signed(8))

Signal 是 Amaranth 的基本数据单元,对应 Verilog 里的 wire/reg。它的位宽和符号性在构造时确定,后续操作会自动进行类型推断。

4.2 Module:逻辑的容器

python 复制代码
m = Module()

# 组合逻辑(对应 always @(*) 或 assign)
with m.If(enable):
    m.d.comb += output.eq(a & b)
with m.Else():
    m.d.comb += output.eq(0)

# 时序逻辑(对应 always @(posedge clk))
with m.If(enable):
    m.d.sync += counter.eq(counter + 1)

这里有一个非常重要的设计决策:Amaranth 里组合逻辑和时序逻辑使用不同的赋值域m.d.combm.d.sync),从语法层面消除了 Verilog 里阻塞/非阻塞赋值混用的可能性。

4.3 Elaboratable:可综合的模块单元

Amaranth 中每个可综合的设计单元都是一个实现了 elaborate() 方法的类:

python 复制代码
class Counter(Elaboratable):
    def __init__(self, width=8):
        self.width = width
        # 端口定义在 __init__ 里
        self.en = Signal()
        self.count = Signal(width)

    def elaborate(self, platform):
        m = Module()

        with m.If(self.en):
            m.d.sync += self.count.eq(self.count + 1)

        return m

这种面向对象的设计带来了软件工程里习以为常的好处:参数化、继承、组合------都是原生 Python 的能力,不需要任何特殊语法扩展。

4.4 FSM:有限状态机

Amaranth 对 FSM 有一流的原生支持:

python 复制代码
with m.FSM():
    with m.State("IDLE"):
        with m.If(start):
            m.next = "RUNNING"

    with m.State("RUNNING"):
        m.d.sync += data.eq(data + 1)
        with m.If(done):
            m.next = "IDLE"

不需要手动管理状态编码,工具链会自动处理。

4.5 时钟域

python 复制代码
# 创建名为 "fast" 的时钟域
m.domains.fast = ClockDomain("fast")

# 在 fast 域中做时序逻辑
m.d.fast += reg.eq(value)

多时钟域是 Amaranth 的一等公民,跨域信号可以用标准库里的同步器处理。


5. 一个完整示例:4 位环形计数器

python 复制代码
from amaranth.hdl import *
from amaranth.sim import *

class RingCounter(Elaboratable):
    """4 位环形计数器,输出始终只有一位为高"""

    def __init__(self):
        self.en  = Signal()           # 使能
        self.out = Signal(4, reset=1) # 输出,复位后第 0 位为 1

    def elaborate(self, platform):
        m = Module()

        with m.If(self.en):
            # 循环左移
            m.d.sync += self.out.eq(
                self.out[1:] | (self.out[0] << 3)
            )

        return m


# 仿真
dut = RingCounter()
sim = Simulator(dut)

def bench():
    yield dut.en.eq(1)
    for _ in range(8):
        yield
        val = yield dut.out
        print(f"out = {val:04b}")

sim.add_clock(1e-6)  # 1 MHz
sim.add_sync_process(bench)

with sim.write_vcd("ring.vcd"):
    sim.run()

运行后输出:

复制代码
out = 0010
out = 0100
out = 1000
out = 0001
out = 0010
out = 0100
out = 1000
out = 0001

仿真产生的 .vcd 文件可以用 GTKWave 打开查看波形。


6. 与 Verilog 互操作

Amaranth 不要求你推翻现有代码库。你可以把 Verilog 模块包装进来:

python 复制代码
from amaranth.hdl.ir import Instance

# 引用一个已有的 Verilog 模块
uart_core = Instance("uart_top",
    i_clk=ClockSignal(),
    i_rst=ResetSignal(),
    i_tx_data=tx_data,
    o_rx_data=rx_data,
)
m.submodules.uart = uart_core

反过来,Amaranth 设计也可以导出为 Verilog 接入已有的 Verilog/SystemVerilog 流程:

python 复制代码
from amaranth.back.verilog import convert
verilog_src = convert(Counter(), ports=[counter.en, counter.count])

7. 构建与上板

以 Lattice iCE40 为例(使用 iCEBreaker 开发板):

python 复制代码
from amaranth_boards.icebreaker import ICEBreakerPlatform

class Blinky(Elaboratable):
    def elaborate(self, platform):
        m = Module()
        led = platform.request("led", 0)
        timer = Signal(24)
        m.d.sync += timer.eq(timer + 1)
        m.d.comb += led.o.eq(timer[-1])
        return m

ICEBreakerPlatform().build(Blinky(), do_program=True)

一行 build() 调用会依次完成:生成 Verilog → Yosys 综合 → nextpnr 布局布线 → icepack 打包 → iceprog 下载。

支持的 FPGA 家族涵盖:Lattice iCE40、ECP5、Nexus、MachXO 系列,AMD/Xilinx Virtex/Spartan 系列,Intel/Altera,以及 Quicklogic EOS S3 等。


8. 安装

bash 复制代码
pip install amaranth amaranth-boards
# 需要系统安装 Yosys 和 nextpnr(或使用 WASM 版本)

WASM 版本的 Yosys 通过 amaranth-yosys 包提供,无需本地安装即可在 Python 环境中使用综合功能,这也是 Playground 的技术基础。


9. 设计哲学

Amaranth 的核心设计原则可以归结为一句话:让正确的代码容易写,让错误的代码难以写

具体体现在:

  • 组合逻辑自动有默认值,不会产生意外 latch
  • 时序逻辑强制使用非阻塞语义,赋值域隔离
  • 所有运算符的位宽规则与 Python 整数语义一致,没有 Verilog 那样的"截断陷阱"
  • 模块化和参数化直接复用 Python 的类系统,无需学习额外语法

代价是:相比 Verilog,Amaranth 的仿真速度较慢(纯 Python 实现),对于性能敏感的大规模仿真,仍建议导出 Verilog 后接入 Verilator 或 Icarus。

相关推荐
龙泉寺天下行走1 天前
LangChain Skills框架核心解析
python·langchain·aigc
echome8881 天前
Python 装饰器详解:从入门到精通的实用指南
开发语言·python
tang777891 天前
爬虫代理IP池到底有啥用?
网络·爬虫·python·网络协议·tcp/ip·ip
sg_knight1 天前
设计模式实战:享元模式(Flyweight)
python·设计模式·享元模式·flyweight
墨有6661 天前
基于弦论流体对偶与环空间约化的湍流精确数值模型
python·流体力学·弦理论
兰文彬1 天前
n8n 2.x版本没有内嵌Python环境
开发语言·python
smileNicky1 天前
Spring AI系列之对话记忆与工具调用指南
人工智能·python·spring
飞Link1 天前
深度解析 TS2Vec:时序表示学习中的层次化建模(Hierarchical Contrastive Learning)
开发语言·python·学习·数据挖掘
代码探秘者1 天前
【Java集合】ArrayList :底层原理、数组互转与扩容计算
java·开发语言·jvm·数据库·后端·python·算法
格鸰爱童话1 天前
向AI学习项目技能(二)
java·人工智能·python·学习