Remote Debugging CocoTB and PyUVM Tests with VSCode

Learn how to set up remote debugging for CocoTB and PyUVM hardware verification tests using VSCode and debugpy. This step-by-step guide shows you how to inspect variables, set breakpoints, and step through PyUVM code execution while running tests on a remote machine.

One of the challenges when working with hardware verification frameworks like CocoTB and PyUVM is setting up a proper debugging environment. In this post, I’ll share my recent experience setting up remote debugging for CocoTB tests using VSCode, which has significantly improved my development workflow.

The Problem

As I’ve been experimenting with PyUVM and CocoTB for hardware verification, I’ve frequently needed to dive deep into the library’s internals to understand how things work. When you’re learning these frameworks, you often need to step through the library code itself, not just your own test code. Print statements can only get you so far. I needed a better way to:

  • Inspect variable values during test execution
  • Set breakpoints at critical points in my test code
  • Step through the execution of PyUVM internals to understand the library better
  • Debug issues by examining what’s happening “under the hood”

I deliberately set up my environment with tests running on a Raspberry Pi (the closest linux machine I had lying around) while editing code on my Mac to simulate a common industry setup. In many professional hardware verification environments, engineers connect to remote Linux machines (often via VNC or SSH) rather than running simulations locally. I wanted to replicate this setup to ensure my debugging solution would work in a professional environment.

The Solution: Remote Debugging with debugpy

Python’s debugpy module provides a clean way to add debugging capabilities to your code, allowing you to connect VSCode as a remote debugger client. Here’s how I set it up:

Step 1: Add debugpy to your CocoTB test

First, I added these crucial lines at the beginning of my test file:

# At the top of test_*.py
import debugpy
debugpy.listen(("0.0.0.0", 5678))
debugpy.wait_for_client()

The code above:

  • Imports the debugpy module
  • Sets up a listener on all network interfaces (0.0.0.0) and port 5678
  • Waits for a debugger client to connect before proceeding

Note: For local debugging on your own machine, you can use “localhost” instead of “0.0.0.0” as the host.

Step 2: Create a Test Runner

I’m trying to move from Makefiles to test_runner scripts in order to check support for regression-like environment, so I created a separate test runner script to launch my simulation:

import os
from pathlib import Path
from cocotb.runner import get_runner

def test_counter_runner():
    # Use Icarus Verilog as the simulator
    sim = os.getenv("SIM", "icarus")

    # Get the project path
    proj_path = Path(__file__).resolve().parent

    # Create the simulation build directory
    sim_build_dir = proj_path / "sim_build"
    sim_build_dir.mkdir(exist_ok=True)

    # Source files
    sources = [
        proj_path / "hdl" / "counter.v",
    ]
    hdl_toplevel = "counter"
    test_module = "test_counter"

    # Get the runner
    runner = get_runner(sim)

    # Optional: Set waveform dumping format
    os.environ["COCOTB_DUMP_WAVE_FORMAT"] = "fst"
    os.environ["IVERILOG_DUMPER"] = "fst"

    # Build the simulation
    runner.build(
        sources=sources,
        hdl_toplevel=hdl_toplevel,
        build_dir=sim_build_dir,
        waves=True,
    )

    # Run the test
    runner.test(
        hdl_toplevel=hdl_toplevel,
        test_module=test_module,
        plusargs=["-fst"],
        build_dir=sim_build_dir,
    )

if __name__ == "__main__":
    test_counter_runner()

Step 3: Configure VSCode for Remote Debugging

In VSCode, I configured a launch configuration in .vscode/launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Remote Attach",
            "type": "python",
            "request": "attach",
            "connect": {
                "host": "localhost",
                "port": 5678
            },
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/path/to/project/on/raspberry/pi"
                }
            ]
        }
    ]
}

Important: Update the remoteRoot to match the path on your remote machine (Raspberry Pi in my case). If debugging locally, you can use the same path for both localRoot and remoteRoot.

Step 4: Workflow

My debugging workflow now looks like this:

  1. Set breakpoints in my test code using VSCode
  2. Run the test runner script on the Raspberry Pi: python test_runner.py
  3. Wait for the message indicating that debugpy is waiting for a client
  4. In VSCode, press the green play button in the Run & Debug panel
  5. The code will execute until it hits a breakpoint, where I can inspect variables, step through code, etc.

Yes, I like automation and this click, wait, click is going to drive me nuts when debugging a bug. I haven’t found a good automated solution for this yet because VSCode has some limitations on cascading tasks as part of Run & Debug flow. I’ll see to it again. This is merely a work-in-progress.

Results

This setup has dramatically improved my PyUVM development experience:

  • I can now inspect complex PyUVM objects at runtime
  • Breakpoints allow me to pause execution at critical points
  • I can step through the test sequence and observe the DUT’s responses
  • The remote debugging capability means I can run tests on more powerful hardware while still having a great debugging experience

Next Steps

This is just the beginning of my journey with CocoTB and PyUVM debugging. Next, I plan to:

  • Explore conditional breakpoints for more complex scenarios
  • Set up debugging for multiple test files
  • Integrate debugging with continuous integration workflows

Stay tuned for more updates as I continue to refine this setup!

If you’re working with hardware verification in Python, I highly recommend giving this setup a try.

Newsletter Updates

Enter your email address below and subscribe to my newsletter

Leave a Reply

Your email address will not be published. Required fields are marked *