MyHDL: describe hardware in Python (and try it in your browser now)

Verilog and VHDL are the languages of FPGA design, and they're worth learning. But if you already think in Python, there's a delightful third option: MyHDL, a library that turns Python itself into a hardware description language. You write generators that model concurrent hardware, simulate them on the Python interpreter with the full unittest framework, and then convert the design to Verilog or VHDL for a standard synthesis flow.

We built a MyHDL playground so you can run all of this in your browser, no installs. This post is the on-ramp.

Why Python for hardware?

The trade is real too, and worth stating plainly: MyHDL is a smaller community than Verilog/VHDL, the synthesizable subset is a subset (as it is in every HDL), and most job postings still say "Verilog." MyHDL is a wonderful way to learn and to build when Python is your home, not a replacement for knowing the classic HDLs.

How it compares

MyHDL Verilog VHDL Chisel Amaranth
Host language Python (own) (own) Scala Python
Simulate with Python interpreter iverilog/Verilator GHDL/others Scala/Verilator Python
Verification unittest/pytest SystemVerilog/UVM VHDL testbench ScalaTest Python
Converts to Verilog, VHDL Verilog Verilog
Parameterize with plain Python generate/params generics Scala plain Python
Learning curve gentle (if you know Python) moderate steeper steep gentle
Best when you think in Python industry default rigor/mil-aero complex generators modern Python RTL

The two Python options (MyHDL and Amaranth, formerly nMigen) share a philosophy; MyHDL is the older, generator-based one with the most direct "this looks like the Verilog I'd write" mapping, which makes it a great teaching bridge.

The basics in five minutes

A MyHDL design is a function decorated with @block that returns generator functions. Each generator is a concurrent process. Here's a 4-bit counter:

from myhdl import block, always_seq, Signal, modbv, ResetSignal

@block
def counter(clk, rst, en, count):
    @always_seq(clk.posedge, reset=rst)
    def logic():
        if en:
            count.next = count + 1     # .next = the "<=" of MyHDL
    return logic

Three things to notice:

Simulate and test

The testbench is also a @block: it wires signals, generates a clock, drives stimulus, and calls run_sim(). config_sim(trace=True) dumps a VCD.

from myhdl import block, always, instance, Signal, modbv, ResetSignal, \
                  delay, StopSimulation

@block
def tb():
    clk = Signal(bool(0))
    rst = ResetSignal(0, active=1, isasync=False)
    en  = Signal(bool(0))
    count = Signal(modbv(0)[4:])
    dut = counter(clk, rst, en, count)

    @always(delay(5))
    def clkgen():
        clk.next = not clk

    @instance
    def stim():
        rst.next = 1
        yield delay(12)
        rst.next = 0
        en.next = 1
        yield delay(160)
        raise StopSimulation
    return dut, clkgen, stim

inst = tb()
inst.config_sim(trace=True)
inst.run_sim()

The real payoff is self-checking tests. Because it's just Python, a proper test asserts expected values and integrates with unittest:

@block
def check(clk, rst, en, count):
    @instance
    def logic():
        yield rst.negedge
        for expected in range(5):
            yield clk.posedge
            yield delay(1)
            assert count == expected, f"got {count}, want {expected}"
        raise StopSimulation
    return logic

That is the whole pitch: your hardware and its proof live in the same language, tested with the same tools.

Try it right now

Everything above runs in the MyHDL playground: the counter is the default; press Run and read the waveform. Change the width, add a down-counter, write a shift register. It simulates server-side and draws the trace, exactly like our Verilog playground does for classic HDL.

What's next: libfpga-myhdl

The libfpga library is a growing set of verified building blocks in Verilog. Its Python companion, libfpga-myhdl, is now live: CDC synchronizers, a show-ahead FIFO, Gray codecs, an LFSR and a MAC, each written in MyHDL with a self-checking pytest suite and a conversion check that proves the generated Verilog and VHDL compile. It grows toward parity with the Verilog library, UART, SPI and friends next. Open an issue to steer the roadmap.

New to the underlying ideas, clocks, resets, FIFOs, state machines? The free HDL course teaches them from logic gates up, and the glossary defines every term. MyHDL is a lovely way to practice them in a language you already speak.

Sources: the MyHDL project and its overview.