Python framework for analog circuit design automation targeting the SkyWater 130nm open-source PDK
Project description
circuitsilk
circuitsilk (import silk) is a Python framework for analog circuit design automation
targeting the SkyWater 130nm open-source PDK. It lets you describe circuits programmatically,
run ngspice simulations, sweep design spaces, and track versions in a local database.
from silk import Module, load_pdk
from silk.simulation import Transient
pdk = load_pdk('sky130') # reads $PDK_ROOT env var
ckt = Module('PDK_skywater130', 'out', 'diffpair.cir', pdkDetails=pdk)
mn1 = pdk.nmos1p8('mn1', d='voutn', g='vinp', s='tail', b='gnd', w=4.0, l=0.15)
mp1 = pdk.pmos1p8('mp1', d='voutp', g='voutp', s='vdd', b='vdd', w=4.0, l=0.15)
ckt.add(mn1, mp1)
ckt.addSimType(Transient(step=1e-9, stop=100e-9))
ckt.simulate(corner='tt')
vout = ckt.loadSignal('v(voutp)')
Installation
pip install circuitsilk # PyPI (when published)
# — or from source —
git clone https://github.com/...
cd silk
pip install -e ".[dev]"
System requirements:
- Python 3.9+
- ngspice (for simulation) —
sudo apt install ngspiceon Debian/Ubuntu - SkyWater 130nm PDK models at
$PDK_ROOT(forload_pdk)
The PDK_ROOT environment variable should point to a directory that contains
libraries/sky130_fd_pr/latest/models/sky130.lib.spice.
Quick start
See docs/quickstart.md for a step-by-step walkthrough.
Working examples live in silk/examples/:
| File | What it shows |
|---|---|
silk/examples/main.py |
Differential pair with factory API |
silk/examples/factory_api_example.py |
Full factory API: devices, passives, SPICE inspection |
silk/examples/parameter_sweep_example.py |
Design-space sweep with Space/Variable |
silk/examples/ldo_design.py |
Parameterized LDO with Module + PyNetlist DB tracking |
silk/examples/source_examples.py |
Voltage/current source waveforms |
Core concepts
Module — the circuit object
Module is the central design object. It holds devices, sources, passives, and
simulation commands and generates SPICE netlists.
from silk import Module
ckt = Module('PDK_skywater130', 'out_dir', 'my_circuit.cir', pdkDetails=pdk)
ckt.add(device1, device2) # add pre-constructed device objects
ckt.addSource(vsource) # add a voltage or current source
ckt.addPassive(capacitor) # add R, C, or L
ckt.addSimType(Transient(...)) # set the simulation type
ckt.simulate(corner='tt') # generate netlist + run ngspice + load results
sig = ckt.loadSignal('v(out)') # retrieve a waveform
Factory API — device instantiation
Devices are instantiated directly from the PDK object. Pins and parameters are keyword arguments — IDE autocomplete works on them.
mn = pdk.nmos1p8('mn', d='out', g='in', s='gnd', b='gnd', w=1.0, l=0.35, m=4)
mp = pdk.pmos1p8('mp', d='out', g='in', s='vdd', b='vdd', w=2.0, l=0.35)
# Parameters can be updated by direct attribute assignment after construction:
mn.w = 2.0
mn.d = 'new_out'
print(mn.to_spice()) # inspect the SPICE line
PDK loading
# Option 1: load_pdk (uses $PDK_ROOT env var or ~/pdk)
from silk import load_pdk
pdk = load_pdk('sky130')
# Option 2: explicit paths
import os
from silk.pdk import PDK_skywater130
pdk = PDK_skywater130(
os.path.join(os.path.dirname(__file__), 'silk', 'pdk', 'data',
'skywater_130_device_details.yaml'),
libraryLocation='/path/to/sky130.lib.spice',
)
Simulation types
from silk.simulation import Transient, AC, DC, Noise, Corner
ckt.addSimType(Transient(step=1e-9, stop=100e-9))
ckt.addSimType(AC('dec', 100, 1e3, 1e9))
ckt.addSimType(DC(source='vin', start=0, stop=1.8, step=0.01))
# Corner is a str-subclass enum — plain strings also work
ckt.simulate(corner=Corner.TT)
ckt.simulate(corner='ff') # equivalent
Sources
from silk import sources
vs = sources.VoltageSource('vdd', positive='vdd', negative='gnd', dc=1.8)
cs = sources.CurrentSource('ibias', positive='vdd', negative='vnbias', dc=100e-6)
# Waveforms
vs_pulse = sources.VoltageSource('vin', positive='in', negative='gnd',
pulse=sources.Pulse(v1=0, v2=1.8, td=0,
tr=100e-12, tf=100e-12,
pw=5e-9, per=10e-9))
vs_sine = sources.VoltageSource('vin', positive='in', negative='gnd',
sine=sources.Sine(voffset=0, vampl=1, freq=1e6))
Passives
from silk.elements import passives
r = passives.Resistor('r1', pos='out', neg='gnd', resistance=10e3)
c = passives.Capacitor('c1', pos='out', neg='gnd', capacitance=100e-12)
l = passives.Inductor('l1', pos='a', neg='b', inductance=1e-9)
ckt.addPassive(r)
ckt.addPassive(c)
ckt.addPassive(l)
Ideal elements (ElementLibrary)
from silk.elements import elements
r = elements.resistor('r1', p='out', n='gnd', value=10e3)
c = elements.capacitor('c1', p='out', n='gnd', value=100e-15)
vs = elements.vsource('vdd', p='vdd', n='gnd', dc=1.8)
ckt.add(r, c, vs)
Design-space exploration
from silk import ModuleVariable, VarType
from silk.optimize import Space, Variable, Optimizer
# Create variables with bounds
w_n = pdk.nmos1p8.w.variable(name='w_n', value=1.0, bounds=(0.42, 20.0))
w_p = pdk.pmos1p8.w.variable(name='w_p', value=2.0, bounds=(0.42, 20.0))
l = pdk.nmos1p8.l.variable(name='l', value=0.15, bounds=(0.15, 1.0))
# Pass ModuleVariable objects directly as device parameters
mn = pdk.nmos1p8('mn', d='out', g='in', s='gnd', b='gnd', w=w_n, l=l)
mp = pdk.pmos1p8('mp', d='out', g='in', s='vdd', b='vdd', w=w_p, l=l)
# Build a ParameterSpace and sample it
space = Space([w_n, w_p, l])
points = space.sample(20, method='lhs') # Latin hypercube sampling
# also: method='random', 'sobol', 'grid'
for pt in points:
space.apply(pt) # updates variable .value fields
ckt.generateNetlist(corner='tt') # picks up new values automatically
Schema export (GUI / code-gen integration)
from silk import export_schema, module_schema
import json
# Export all PDK devices as a machine-readable dict
schema = export_schema(pdk)
print(json.dumps(schema, indent=2))
# Export a single Module's interface
mod_schema = module_schema(my_module)
Database / version tracking
from silk.db import Database, TrackedModule, DesignStage
db = Database('designs.db')
tracked = TrackedModule(
'PDK_skywater130', 'out', 'ldo.cir', pdkDetails=pdk,
circuit_name='ldo_nmos', version='1.0',
stage=DesignStage.DEV, db_path='designs.db',
)
tracked.create_circuit_version(description='Initial attempt')
# ... build circuit ...
tracked.store_results(results, corner='tt', temperature=27)
tracked.promote() # DEV → STABLE → POST_LAYOUT → TAPEOUT
Code generation
from silk.codegen import Generator
gen = Generator(pdk)
code = gen.generate(my_module)
print(code)
Full API reference
Backward compatibility
Old pynetlist.* class names are still importable via silk._compat:
from silk._compat import PyModule, PySignal, ParameterSpace # deprecated
The PyNetlist class is available at silk.circuit.netlist.PyNetlist as a
thin subclass of Module with optional legacy DB tracking.
Package layout
silk/
__init__.py top-level re-exports
exceptions.py CircuitError hierarchy
_compat.py backward-compat aliases for old Py* names
circuit/ Module, ModuleTestbench, schema export
pdk/ PDK_skywater130, BasePDK, load_pdk
elements/ ElementLibrary, passives, AnalogElement
sources/ VoltageSource, CurrentSource, waveforms
signals/ Signal, NgspiceSignal, metrics
simulation/ Transient, AC, DC, Noise, Corner, NgspiceRunner
optimize/ Space, Variable, Optimizer
db/ Database, TrackedModule, DesignStage
codegen/ Generator
utils/ internal helpers
examples/ runnable example scripts
Development
pip install -e ".[dev]"
pytest tests/ -q
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file circuitsilk-0.1.0.tar.gz.
File metadata
- Download URL: circuitsilk-0.1.0.tar.gz
- Upload date:
- Size: 211.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c253e919f62e8e25cd4aaf39b238dfe7f1fc8d282cd497690ce2a775147715d
|
|
| MD5 |
ba904dc0458306a8171ed18ebede1501
|
|
| BLAKE2b-256 |
746118761bc32364d15e690c351ced8f71c05b6c51661c321bf275e57e75038e
|
File details
Details for the file circuitsilk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: circuitsilk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 135.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
102150d0ffab924134c5490e20516c23639143199ec633c572345b61e59330ac
|
|
| MD5 |
568464e97247acfa28713d35168a7029
|
|
| BLAKE2b-256 |
f227bd2a35a0baac76700875f056e39d48f2c08b70891f6d12fcb90cab525b94
|