cocotb_stubgen

Rules

cocotb_stubgen

load("@rules_cocotb//cocotb:cocotb_stubgen.bzl", "cocotb_stubgen")

cocotb_stubgen(name, module)

Generate typed cocotb DUT stubs for an HDL library.

Point module at a vhdl_library or verilog_library and the rule produces a PyInfo target you add to any Python rule's deps (most commonly cocotb_test.deps) to make the DUT's ports and signals type-check.

Example — a VHDL DUT tests/foo/dut.vhd:

vhdl_library(
    name = "dut",
    srcs = ["dut.vhd"],
)

cocotb_stubgen(
    name = "dut_stubs",
    module = ":dut",
)

cocotb_test(
    name = "dut_test",
    srcs = ["dut_test.py"],
    module = ":dut",
    deps = [":dut_stubs"],
    sim = "ghdl",
)

One class is emitted per entity / module found in each HDL source, each subclassing cocotb.handle.HierarchyObject so it can stand in as the DUT parameter's type directly. The import path mirrors the HDL source's own package and basename — tests/foo/dut.vhd yields a Dut class importable as:

from tests.foo.dut import Dut

async def test(dut: Dut) -> None:
    dut.clk.value = 0

VHDL ports / generics / architecture signals are typed against cocotb's handle hierarchy (LogicObject, LogicArrayObject, IntegerObject, ...). Verilog ports, parameters and nets fall back to typing.Any — Verilog declarations are effectively untyped once logic / wire / reg are flattened. Instantiations in either language type as the instantiated entity's own stub class.

Verilog is parsed without preprocessing, so ports supplied by a macro (module m(`MY_PORTS);) are omitted rather than guessed at.

The generator is the one rules_cocotb ships and is not swappable. No cocotb_toolchain is required either — stub generation is static analysis and runs no simulator. Registering one contributes only its optional vhdl_libraries, which the generator shipped today ignores; see cocotb_toolchain.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
moduleHDL library (vhdl_library / verilog_library) to stub.Labelrequired