Quickstart

pytest-cocotb is a pytest plugin that lets you drive cocotb HDL simulations from pytest. HDL is compiled once per session, and each test function launches the simulator with its own cocotb test module.

Installation

pip install -e .

Minimal example

Given a simple counter RTL file rtl/counter.sv:

module counter (
  input  logic       clk,
  input  logic       rst,
  output logic [7:0] count
);
  always_ff @(posedge clk)
    if (rst) count <= '0;
    else     count <= count + 1;
endmodule

Write a cocotb testbench in cocotb_counter.py:

import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge

@cocotb.test()
async def counter_basic(dut):
    clock = Clock(dut.clk, 10, unit="ns")
    cocotb.start_soon(clock.start())

    dut.rst.value = 1
    for _ in range(3):
        await RisingEdge(dut.clk)
    dut.rst.value = 0

    await RisingEdge(dut.clk)
    prev = int(dut.count.value)
    await RisingEdge(dut.clk)
    curr = int(dut.count.value)
    assert curr == prev + 1

Then write a pytest test that uses the test_session fixture:

def test_counter_basic(test_session):
    test_session.run(test_module="cocotb_counter")

Single-file tests

The test_session fixture defaults test_module to the current pytest file’s __name__. This means you can put cocotb coroutines and pytest tests in the same file and omit the test_module argument entirely:

# test_counter.py
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge

@cocotb.test()
async def counter_basic(dut):
    clock = Clock(dut.clk, 10, unit="ns")
    cocotb.start_soon(clock.start())

    dut.rst.value = 1
    for _ in range(3):
        await RisingEdge(dut.clk)
    dut.rst.value = 0

    await RisingEdge(dut.clk)
    prev = int(dut.count.value)
    await RisingEdge(dut.clk)
    curr = int(dut.count.value)
    assert curr == prev + 1

def test_counter(test_session):
    test_session.run()  # uses this file as the cocotb test module

Running

pytest --simulator verilator --hdl-toplevel counter --sources rtl/counter.sv

Setting defaults

To avoid repeating CLI flags on every invocation, add them to addopts in any of pytest’s configuration files.

pytest.ini

[pytest]
addopts = --simulator verilator --hdl-toplevel counter --sources rtl/counter.sv

pyproject.toml

[tool.pytest.ini_options]
addopts = "--simulator verilator --hdl-toplevel counter --sources rtl/counter.sv"

setup.cfg

[tool:pytest]
addopts = --simulator verilator --hdl-toplevel counter --sources rtl/counter.sv