Cocotb (Python) Verification

Unlock the power of Python for digital logic verification. Cocotb lets you write rigorous testbenches using the language you already love, connecting seamlessly to standard simulators.

What is Cocotb?

Cocotb (Coroutine Cosimulation Testbench) is a CO-simulation library that enables connecting Python testbenches to industry-standard HDL simulators (like Icarus Verilog, Verilator, Questa, VCS).

Unlike traditionally converting Python to Verilog, Cocotb drives the simulator at runtime through the VPI/VHPI/FLI interface. This allows you to use the full power of the Python ecosystem (NumPy, SciPy, TensorFlow) directly in your verification environment.

Why Python for Verification?

Feature SystemVerilog (UVM) Cocotb (Python)
Boilerplate Heavy (Classes, factories, macros) Minimal (Standard functions)
Compiling Re-compile on every change No re-compile (Runtime only)
Data Types Static, limited (queues) Dynamic (Lists, Dicts, NumPy, AI/ML)
Learning Curve Steep (Months) Easy (Days)

Quick Example

import cocotb
from cocotb.triggers import RisingEdge, Timer
@cocotb.test()
async def simple_dff_test(dut):
    """Test that the DFF captures data on rising edge"""
    # generate a clock
    cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
    # Reset
    dut.rst.value = 1
    await RisingEdge(dut.clk)
    dut.rst.value = 0
    # Driver
    dut.d.value = 1
    await RisingEdge(dut.clk)
    # Monitor/Check
    assert dut.q.value == 1, "DFF failed to capture 1!"

Essential Shortcuts & Methods

Master these triggers to control simulation time effectively:

  • await RisingEdge(dut.clk): Wait for the positive edge of the clock.
  • await FallingEdge(dut.clk): Wait for the negative edge.
  • await Timer(10, units='ns'): Wait for a specific duration.
  • await ReadOnly(): Wait for the signal values to settle (like PLI cbReadOnly).

Driving Signals

Use dut.signal.value = 1 to drive. Use val = dut.signal.value.integer to read as a Python integer.

Registers & Regression

Register Access: Instead of a complex RAL, iterate through Python dictionaries to configure your design.

# Simple Register Config
reg_map = {0x00: 0x1, 0x04: 0xDEADBEEF}
for addr, data in reg_map.items():
    await bus_driver.write(addr, data)

Regression Testing: Use the TestFactory to generate multiple test cases from a single function automatically.

Curriculum