virtuoso-bridge-lite

Control remote Cadence Virtuoso from any machine over SSH. No VNC, no X11. Python + SSH + AI agents.

Python Virtuoso SSH

⚡ SKILL Execution

Send any SKILL command to a running Virtuoso and get results back as Python dicts.

▦ Layout & Schematic

Python API for creating, modifying, and reading cellviews. Context managers handle open/save.

⚙ Spectre Simulation

Upload netlists, run simulations remotely, parse PSF results — all from Python.

⚗ Circuit Optimization

Automated parameter tuning via Spectre-in-the-loop. TuRBO, scipy, or any optimizer.

Architecture

Architecture

Quick Start

pip install -e .
virtuoso-bridge init        # generates .env
# edit .env → set VB_REMOTE_HOST=my-server
virtuoso-bridge start
from virtuoso_bridge import VirtuosoClient

client = VirtuosoClient.from_env()
result = client.execute_skill("1+2")
print(result)  # {'ok': True, 'result': {'output': '3', ...}}

API Reference

VirtuosoClient — SKILL execution

MethodDescription
execute_skill(code)Run any SKILL expression, return result dict
load_il(path)Upload & load a .il file in Virtuoso
execute_operations(cmds)Run a batch of SKILL commands
get_current_design()Returns (lib, cell, view) of active cellview
open_window(lib, cell)Open a cellview in Virtuoso GUI
save_current_cellview()Save the active cellview
upload_file(local, remote)Upload a file to the remote machine
download_file(remote, local)Download a file from the remote machine
run_shell_command(cmd)Run a shell command on the remote host
test_connection()Ping the daemon to check connectivity

Layout editing

with client.layout.edit("myLib", "myCell") as layout:
    layout.add_rect("M1", "drawing", (0, 0, 1, 0.5))
    layout.add_path("M2", "drawing", [(0,0),(1,0)], width=0.1)
    layout.add_label("M1", "pin", (0.5, 0.25), "VDD")
    layout.add_instance("tsmcN28", "nch_ulvt_mac", (0,0), "M0")
    layout.add_via("M1_M2", (0.5, 0.25))
    layout.add_polygon("M3", "drawing", [(0,0),(1,0),(1,1)])
    shapes = layout.get_shapes()

Schematic editing

with client.schematic.edit("myLib", "myCell") as sch:
    sch.add_instance("analogLib", "vdc", (0,0), "V0", params={"vdc": "0.9"})
    sch.add_wire([(0, 0), (0, 0.5)])
    sch.add_pin("VDD", "inputOutput", (0, 1.0))

Spectre simulation

from virtuoso_bridge.spectre.runner import SpectreSimulator

sim = SpectreSimulator.from_env(work_dir="./output")
result = sim.run_simulation("tb_inv.scs", {})

print(result.status)          # ExecutionStatus.SUCCESS
print(result.data.keys())     # ['time', 'VOUT', 'VIN', ...]
print(result.data["VOUT"][:5]) # first 5 voltage samples

SSHClient — independent SSH layer

from virtuoso_bridge import SSHClient, VirtuosoClient

# Create tunnel independently
tunnel = SSHClient.from_env()
tunnel.warm()

# Create bridge from tunnel
bridge = VirtuosoClient.from_tunnel(tunnel)
bridge.execute_skill("1+2")

# Or local mode — no tunnel needed
bridge = VirtuosoClient.local(port=65432)