circuitsilk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- circuitsilk-0.1.0/LICENSE +21 -0
- circuitsilk-0.1.0/PKG-INFO +305 -0
- circuitsilk-0.1.0/README.md +267 -0
- circuitsilk-0.1.0/circuitsilk.egg-info/PKG-INFO +305 -0
- circuitsilk-0.1.0/circuitsilk.egg-info/SOURCES.txt +97 -0
- circuitsilk-0.1.0/circuitsilk.egg-info/dependency_links.txt +1 -0
- circuitsilk-0.1.0/circuitsilk.egg-info/requires.txt +13 -0
- circuitsilk-0.1.0/circuitsilk.egg-info/top_level.txt +2 -0
- circuitsilk-0.1.0/ngspice_read/__init__.py +0 -0
- circuitsilk-0.1.0/ngspice_read/ngdump-ic.py +46 -0
- circuitsilk-0.1.0/ngspice_read/ngspice_read.py +366 -0
- circuitsilk-0.1.0/pyproject.toml +55 -0
- circuitsilk-0.1.0/setup.cfg +4 -0
- circuitsilk-0.1.0/silk/__init__.py +70 -0
- circuitsilk-0.1.0/silk/_compat.py +24 -0
- circuitsilk-0.1.0/silk/circuit/__init__.py +9 -0
- circuitsilk-0.1.0/silk/circuit/circuit_elements.py +344 -0
- circuitsilk-0.1.0/silk/circuit/module_test.py +297 -0
- circuitsilk-0.1.0/silk/circuit/modules.py +796 -0
- circuitsilk-0.1.0/silk/circuit/netlist.py +267 -0
- circuitsilk-0.1.0/silk/circuit/spec_report.py +193 -0
- circuitsilk-0.1.0/silk/circuit/spice_netlister.py +325 -0
- circuitsilk-0.1.0/silk/codegen/__init__.py +4 -0
- circuitsilk-0.1.0/silk/codegen/generator.py +560 -0
- circuitsilk-0.1.0/silk/db/__init__.py +5 -0
- circuitsilk-0.1.0/silk/db/circuit_db.py +1150 -0
- circuitsilk-0.1.0/silk/db/cli.py +705 -0
- circuitsilk-0.1.0/silk/db/integration.py +472 -0
- circuitsilk-0.1.0/silk/db/structure_tracker.py +1238 -0
- circuitsilk-0.1.0/silk/elements/__init__.py +9 -0
- circuitsilk-0.1.0/silk/elements/analog_devices.yaml +54 -0
- circuitsilk-0.1.0/silk/elements/base.py +146 -0
- circuitsilk-0.1.0/silk/elements/factory.py +313 -0
- circuitsilk-0.1.0/silk/elements/library.py +44 -0
- circuitsilk-0.1.0/silk/elements/passives.py +87 -0
- circuitsilk-0.1.0/silk/elements/schema.py +350 -0
- circuitsilk-0.1.0/silk/examples/__init__.py +0 -0
- circuitsilk-0.1.0/silk/examples/compare_outputs.py +116 -0
- circuitsilk-0.1.0/silk/examples/factory_api_example.py +114 -0
- circuitsilk-0.1.0/silk/examples/ldo_design.py +214 -0
- circuitsilk-0.1.0/silk/examples/main.py +105 -0
- circuitsilk-0.1.0/silk/examples/parameter_sweep_example.py +226 -0
- circuitsilk-0.1.0/silk/examples/source_examples.py +299 -0
- circuitsilk-0.1.0/silk/exceptions.py +30 -0
- circuitsilk-0.1.0/silk/optimize/__init__.py +6 -0
- circuitsilk-0.1.0/silk/optimize/optimizer.py +424 -0
- circuitsilk-0.1.0/silk/optimize/parameter_space.py +469 -0
- circuitsilk-0.1.0/silk/pdk/__init__.py +15 -0
- circuitsilk-0.1.0/silk/pdk/_loader.py +51 -0
- circuitsilk-0.1.0/silk/pdk/basepdk.py +284 -0
- circuitsilk-0.1.0/silk/pdk/data/skywater_130_device_details.xlsx +0 -0
- circuitsilk-0.1.0/silk/pdk/data/skywater_130_device_details.yaml +889 -0
- circuitsilk-0.1.0/silk/pdk/data/~$skywater_130_device_details.xlsx +0 -0
- circuitsilk-0.1.0/silk/pdk/skywater130.py +37 -0
- circuitsilk-0.1.0/silk/signals/__init__.py +16 -0
- circuitsilk-0.1.0/silk/signals/base.py +187 -0
- circuitsilk-0.1.0/silk/signals/metrics.py +207 -0
- circuitsilk-0.1.0/silk/signals/spice.py +104 -0
- circuitsilk-0.1.0/silk/simulation/__init__.py +6 -0
- circuitsilk-0.1.0/silk/simulation/analysis.py +74 -0
- circuitsilk-0.1.0/silk/simulation/corner.py +63 -0
- circuitsilk-0.1.0/silk/simulation/runner.py +65 -0
- circuitsilk-0.1.0/silk/sources/__init__.py +27 -0
- circuitsilk-0.1.0/silk/sources/classes.py +342 -0
- circuitsilk-0.1.0/silk/sources/waveforms.py +148 -0
- circuitsilk-0.1.0/silk/utils/__init__.py +4 -0
- circuitsilk-0.1.0/silk/utils/_utils.py +25 -0
- circuitsilk-0.1.0/tests/test_add_method.py +177 -0
- circuitsilk-0.1.0/tests/test_analysis.py +213 -0
- circuitsilk-0.1.0/tests/test_analysis_types.py +221 -0
- circuitsilk-0.1.0/tests/test_circuit_db.py +867 -0
- circuitsilk-0.1.0/tests/test_circuit_elements.py +562 -0
- circuitsilk-0.1.0/tests/test_circuit_optimizer.py +530 -0
- circuitsilk-0.1.0/tests/test_codegen_ports.py +85 -0
- circuitsilk-0.1.0/tests/test_corner.py +87 -0
- circuitsilk-0.1.0/tests/test_element_library.py +185 -0
- circuitsilk-0.1.0/tests/test_elements_base.py +257 -0
- circuitsilk-0.1.0/tests/test_elements_factory.py +505 -0
- circuitsilk-0.1.0/tests/test_export_schema.py +154 -0
- circuitsilk-0.1.0/tests/test_fixtures_smoke.py +69 -0
- circuitsilk-0.1.0/tests/test_integration_parameter_space.py +243 -0
- circuitsilk-0.1.0/tests/test_load_pdk.py +50 -0
- circuitsilk-0.1.0/tests/test_module_test.py +531 -0
- circuitsilk-0.1.0/tests/test_ngspice_runner.py +70 -0
- circuitsilk-0.1.0/tests/test_parameter_space.py +717 -0
- circuitsilk-0.1.0/tests/test_passives.py +295 -0
- circuitsilk-0.1.0/tests/test_pdk.py +686 -0
- circuitsilk-0.1.0/tests/test_pymodule.py +935 -0
- circuitsilk-0.1.0/tests/test_pynetlist.py +2026 -0
- circuitsilk-0.1.0/tests/test_sig_sources.py +869 -0
- circuitsilk-0.1.0/tests/test_signal_metrics.py +175 -0
- circuitsilk-0.1.0/tests/test_signals.py +294 -0
- circuitsilk-0.1.0/tests/test_silk_imports.py +115 -0
- circuitsilk-0.1.0/tests/test_sim_cache.py +131 -0
- circuitsilk-0.1.0/tests/test_spec_report.py +166 -0
- circuitsilk-0.1.0/tests/test_spice_netlister.py +377 -0
- circuitsilk-0.1.0/tests/test_structure_tracker.py +1471 -0
- circuitsilk-0.1.0/tests/test_tracked_netlist.py +610 -0
- circuitsilk-0.1.0/tests/test_variable_factory.py +238 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Levant Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: circuitsilk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python framework for analog circuit design automation targeting the SkyWater 130nm open-source PDK
|
|
5
|
+
Author: Levant Labs
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/levantlabs/silk
|
|
8
|
+
Project-URL: Repository, https://github.com/levantlabs/silk
|
|
9
|
+
Project-URL: Documentation, https://github.com/levantlabs/silk/blob/main/docs/quickstart.md
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/levantlabs/silk/issues
|
|
11
|
+
Keywords: spice,analog,eda,sky130,ngspice,circuit,netlist
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: numpy
|
|
27
|
+
Requires-Dist: matplotlib
|
|
28
|
+
Requires-Dist: pyyaml
|
|
29
|
+
Requires-Dist: pandas
|
|
30
|
+
Provides-Extra: ui
|
|
31
|
+
Requires-Dist: gradio; extra == "ui"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
35
|
+
Requires-Dist: build; extra == "dev"
|
|
36
|
+
Requires-Dist: twine; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# circuitsilk
|
|
40
|
+
|
|
41
|
+
**circuitsilk** (`import silk`) is a Python framework for analog circuit design automation
|
|
42
|
+
targeting the SkyWater 130nm open-source PDK. It lets you describe circuits programmatically,
|
|
43
|
+
run ngspice simulations, sweep design spaces, and track versions in a local database.
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from silk import Module, load_pdk
|
|
47
|
+
from silk.simulation import Transient
|
|
48
|
+
|
|
49
|
+
pdk = load_pdk('sky130') # reads $PDK_ROOT env var
|
|
50
|
+
ckt = Module('PDK_skywater130', 'out', 'diffpair.cir', pdkDetails=pdk)
|
|
51
|
+
|
|
52
|
+
mn1 = pdk.nmos1p8('mn1', d='voutn', g='vinp', s='tail', b='gnd', w=4.0, l=0.15)
|
|
53
|
+
mp1 = pdk.pmos1p8('mp1', d='voutp', g='voutp', s='vdd', b='vdd', w=4.0, l=0.15)
|
|
54
|
+
ckt.add(mn1, mp1)
|
|
55
|
+
ckt.addSimType(Transient(step=1e-9, stop=100e-9))
|
|
56
|
+
ckt.simulate(corner='tt')
|
|
57
|
+
vout = ckt.loadSignal('v(voutp)')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install circuitsilk # PyPI (when published)
|
|
64
|
+
# — or from source —
|
|
65
|
+
git clone https://github.com/...
|
|
66
|
+
cd silk
|
|
67
|
+
pip install -e ".[dev]"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**System requirements:**
|
|
71
|
+
|
|
72
|
+
- Python 3.9+
|
|
73
|
+
- ngspice (for simulation) — `sudo apt install ngspice` on Debian/Ubuntu
|
|
74
|
+
- SkyWater 130nm PDK models at `$PDK_ROOT` (for `load_pdk`)
|
|
75
|
+
|
|
76
|
+
The `PDK_ROOT` environment variable should point to a directory that contains
|
|
77
|
+
`libraries/sky130_fd_pr/latest/models/sky130.lib.spice`.
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
See [docs/quickstart.md](docs/quickstart.md) for a step-by-step walkthrough.
|
|
82
|
+
|
|
83
|
+
Working examples live in `silk/examples/`:
|
|
84
|
+
|
|
85
|
+
| File | What it shows |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `silk/examples/main.py` | Differential pair with factory API |
|
|
88
|
+
| `silk/examples/factory_api_example.py` | Full factory API: devices, passives, SPICE inspection |
|
|
89
|
+
| `silk/examples/parameter_sweep_example.py` | Design-space sweep with `Space`/`Variable` |
|
|
90
|
+
| `silk/examples/ldo_design.py` | Parameterized LDO with `Module` + `PyNetlist` DB tracking |
|
|
91
|
+
| `silk/examples/source_examples.py` | Voltage/current source waveforms |
|
|
92
|
+
|
|
93
|
+
## Core concepts
|
|
94
|
+
|
|
95
|
+
### `Module` — the circuit object
|
|
96
|
+
|
|
97
|
+
`Module` is the central design object. It holds devices, sources, passives, and
|
|
98
|
+
simulation commands and generates SPICE netlists.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from silk import Module
|
|
102
|
+
ckt = Module('PDK_skywater130', 'out_dir', 'my_circuit.cir', pdkDetails=pdk)
|
|
103
|
+
ckt.add(device1, device2) # add pre-constructed device objects
|
|
104
|
+
ckt.addSource(vsource) # add a voltage or current source
|
|
105
|
+
ckt.addPassive(capacitor) # add R, C, or L
|
|
106
|
+
ckt.addSimType(Transient(...)) # set the simulation type
|
|
107
|
+
ckt.simulate(corner='tt') # generate netlist + run ngspice + load results
|
|
108
|
+
sig = ckt.loadSignal('v(out)') # retrieve a waveform
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Factory API — device instantiation
|
|
112
|
+
|
|
113
|
+
Devices are instantiated directly from the PDK object. Pins and parameters are
|
|
114
|
+
keyword arguments — IDE autocomplete works on them.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
mn = pdk.nmos1p8('mn', d='out', g='in', s='gnd', b='gnd', w=1.0, l=0.35, m=4)
|
|
118
|
+
mp = pdk.pmos1p8('mp', d='out', g='in', s='vdd', b='vdd', w=2.0, l=0.35)
|
|
119
|
+
|
|
120
|
+
# Parameters can be updated by direct attribute assignment after construction:
|
|
121
|
+
mn.w = 2.0
|
|
122
|
+
mn.d = 'new_out'
|
|
123
|
+
print(mn.to_spice()) # inspect the SPICE line
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### PDK loading
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
# Option 1: load_pdk (uses $PDK_ROOT env var or ~/pdk)
|
|
130
|
+
from silk import load_pdk
|
|
131
|
+
pdk = load_pdk('sky130')
|
|
132
|
+
|
|
133
|
+
# Option 2: explicit paths
|
|
134
|
+
import os
|
|
135
|
+
from silk.pdk import PDK_skywater130
|
|
136
|
+
pdk = PDK_skywater130(
|
|
137
|
+
os.path.join(os.path.dirname(__file__), 'silk', 'pdk', 'data',
|
|
138
|
+
'skywater_130_device_details.yaml'),
|
|
139
|
+
libraryLocation='/path/to/sky130.lib.spice',
|
|
140
|
+
)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Simulation types
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from silk.simulation import Transient, AC, DC, Noise, Corner
|
|
147
|
+
|
|
148
|
+
ckt.addSimType(Transient(step=1e-9, stop=100e-9))
|
|
149
|
+
ckt.addSimType(AC('dec', 100, 1e3, 1e9))
|
|
150
|
+
ckt.addSimType(DC(source='vin', start=0, stop=1.8, step=0.01))
|
|
151
|
+
|
|
152
|
+
# Corner is a str-subclass enum — plain strings also work
|
|
153
|
+
ckt.simulate(corner=Corner.TT)
|
|
154
|
+
ckt.simulate(corner='ff') # equivalent
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Sources
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from silk import sources
|
|
161
|
+
|
|
162
|
+
vs = sources.VoltageSource('vdd', positive='vdd', negative='gnd', dc=1.8)
|
|
163
|
+
cs = sources.CurrentSource('ibias', positive='vdd', negative='vnbias', dc=100e-6)
|
|
164
|
+
|
|
165
|
+
# Waveforms
|
|
166
|
+
vs_pulse = sources.VoltageSource('vin', positive='in', negative='gnd',
|
|
167
|
+
pulse=sources.Pulse(v1=0, v2=1.8, td=0,
|
|
168
|
+
tr=100e-12, tf=100e-12,
|
|
169
|
+
pw=5e-9, per=10e-9))
|
|
170
|
+
vs_sine = sources.VoltageSource('vin', positive='in', negative='gnd',
|
|
171
|
+
sine=sources.Sine(voffset=0, vampl=1, freq=1e6))
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Passives
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from silk.elements import passives
|
|
178
|
+
|
|
179
|
+
r = passives.Resistor('r1', pos='out', neg='gnd', resistance=10e3)
|
|
180
|
+
c = passives.Capacitor('c1', pos='out', neg='gnd', capacitance=100e-12)
|
|
181
|
+
l = passives.Inductor('l1', pos='a', neg='b', inductance=1e-9)
|
|
182
|
+
ckt.addPassive(r)
|
|
183
|
+
ckt.addPassive(c)
|
|
184
|
+
ckt.addPassive(l)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Ideal elements (ElementLibrary)
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from silk.elements import elements
|
|
191
|
+
|
|
192
|
+
r = elements.resistor('r1', p='out', n='gnd', value=10e3)
|
|
193
|
+
c = elements.capacitor('c1', p='out', n='gnd', value=100e-15)
|
|
194
|
+
vs = elements.vsource('vdd', p='vdd', n='gnd', dc=1.8)
|
|
195
|
+
ckt.add(r, c, vs)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Design-space exploration
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
from silk import ModuleVariable, VarType
|
|
202
|
+
from silk.optimize import Space, Variable, Optimizer
|
|
203
|
+
|
|
204
|
+
# Create variables with bounds
|
|
205
|
+
w_n = pdk.nmos1p8.w.variable(name='w_n', value=1.0, bounds=(0.42, 20.0))
|
|
206
|
+
w_p = pdk.pmos1p8.w.variable(name='w_p', value=2.0, bounds=(0.42, 20.0))
|
|
207
|
+
l = pdk.nmos1p8.l.variable(name='l', value=0.15, bounds=(0.15, 1.0))
|
|
208
|
+
|
|
209
|
+
# Pass ModuleVariable objects directly as device parameters
|
|
210
|
+
mn = pdk.nmos1p8('mn', d='out', g='in', s='gnd', b='gnd', w=w_n, l=l)
|
|
211
|
+
mp = pdk.pmos1p8('mp', d='out', g='in', s='vdd', b='vdd', w=w_p, l=l)
|
|
212
|
+
|
|
213
|
+
# Build a ParameterSpace and sample it
|
|
214
|
+
space = Space([w_n, w_p, l])
|
|
215
|
+
points = space.sample(20, method='lhs') # Latin hypercube sampling
|
|
216
|
+
# also: method='random', 'sobol', 'grid'
|
|
217
|
+
|
|
218
|
+
for pt in points:
|
|
219
|
+
space.apply(pt) # updates variable .value fields
|
|
220
|
+
ckt.generateNetlist(corner='tt') # picks up new values automatically
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Schema export (GUI / code-gen integration)
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from silk import export_schema, module_schema
|
|
227
|
+
import json
|
|
228
|
+
|
|
229
|
+
# Export all PDK devices as a machine-readable dict
|
|
230
|
+
schema = export_schema(pdk)
|
|
231
|
+
print(json.dumps(schema, indent=2))
|
|
232
|
+
|
|
233
|
+
# Export a single Module's interface
|
|
234
|
+
mod_schema = module_schema(my_module)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Database / version tracking
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from silk.db import Database, TrackedModule, DesignStage
|
|
241
|
+
|
|
242
|
+
db = Database('designs.db')
|
|
243
|
+
tracked = TrackedModule(
|
|
244
|
+
'PDK_skywater130', 'out', 'ldo.cir', pdkDetails=pdk,
|
|
245
|
+
circuit_name='ldo_nmos', version='1.0',
|
|
246
|
+
stage=DesignStage.DEV, db_path='designs.db',
|
|
247
|
+
)
|
|
248
|
+
tracked.create_circuit_version(description='Initial attempt')
|
|
249
|
+
# ... build circuit ...
|
|
250
|
+
tracked.store_results(results, corner='tt', temperature=27)
|
|
251
|
+
tracked.promote() # DEV → STABLE → POST_LAYOUT → TAPEOUT
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Code generation
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
from silk.codegen import Generator
|
|
258
|
+
|
|
259
|
+
gen = Generator(pdk)
|
|
260
|
+
code = gen.generate(my_module)
|
|
261
|
+
print(code)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Full API reference
|
|
265
|
+
|
|
266
|
+
See [docs/api-reference.md](docs/api-reference.md).
|
|
267
|
+
|
|
268
|
+
## Backward compatibility
|
|
269
|
+
|
|
270
|
+
Old `pynetlist.*` class names are still importable via `silk._compat`:
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
from silk._compat import PyModule, PySignal, ParameterSpace # deprecated
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The `PyNetlist` class is available at `silk.circuit.netlist.PyNetlist` as a
|
|
277
|
+
thin subclass of `Module` with optional legacy DB tracking.
|
|
278
|
+
|
|
279
|
+
## Package layout
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
silk/
|
|
283
|
+
__init__.py top-level re-exports
|
|
284
|
+
exceptions.py CircuitError hierarchy
|
|
285
|
+
_compat.py backward-compat aliases for old Py* names
|
|
286
|
+
|
|
287
|
+
circuit/ Module, ModuleTestbench, schema export
|
|
288
|
+
pdk/ PDK_skywater130, BasePDK, load_pdk
|
|
289
|
+
elements/ ElementLibrary, passives, AnalogElement
|
|
290
|
+
sources/ VoltageSource, CurrentSource, waveforms
|
|
291
|
+
signals/ Signal, NgspiceSignal, metrics
|
|
292
|
+
simulation/ Transient, AC, DC, Noise, Corner, NgspiceRunner
|
|
293
|
+
optimize/ Space, Variable, Optimizer
|
|
294
|
+
db/ Database, TrackedModule, DesignStage
|
|
295
|
+
codegen/ Generator
|
|
296
|
+
utils/ internal helpers
|
|
297
|
+
examples/ runnable example scripts
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Development
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
pip install -e ".[dev]"
|
|
304
|
+
pytest tests/ -q
|
|
305
|
+
```
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# circuitsilk
|
|
2
|
+
|
|
3
|
+
**circuitsilk** (`import silk`) is a Python framework for analog circuit design automation
|
|
4
|
+
targeting the SkyWater 130nm open-source PDK. It lets you describe circuits programmatically,
|
|
5
|
+
run ngspice simulations, sweep design spaces, and track versions in a local database.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from silk import Module, load_pdk
|
|
9
|
+
from silk.simulation import Transient
|
|
10
|
+
|
|
11
|
+
pdk = load_pdk('sky130') # reads $PDK_ROOT env var
|
|
12
|
+
ckt = Module('PDK_skywater130', 'out', 'diffpair.cir', pdkDetails=pdk)
|
|
13
|
+
|
|
14
|
+
mn1 = pdk.nmos1p8('mn1', d='voutn', g='vinp', s='tail', b='gnd', w=4.0, l=0.15)
|
|
15
|
+
mp1 = pdk.pmos1p8('mp1', d='voutp', g='voutp', s='vdd', b='vdd', w=4.0, l=0.15)
|
|
16
|
+
ckt.add(mn1, mp1)
|
|
17
|
+
ckt.addSimType(Transient(step=1e-9, stop=100e-9))
|
|
18
|
+
ckt.simulate(corner='tt')
|
|
19
|
+
vout = ckt.loadSignal('v(voutp)')
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install circuitsilk # PyPI (when published)
|
|
26
|
+
# — or from source —
|
|
27
|
+
git clone https://github.com/...
|
|
28
|
+
cd silk
|
|
29
|
+
pip install -e ".[dev]"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**System requirements:**
|
|
33
|
+
|
|
34
|
+
- Python 3.9+
|
|
35
|
+
- ngspice (for simulation) — `sudo apt install ngspice` on Debian/Ubuntu
|
|
36
|
+
- SkyWater 130nm PDK models at `$PDK_ROOT` (for `load_pdk`)
|
|
37
|
+
|
|
38
|
+
The `PDK_ROOT` environment variable should point to a directory that contains
|
|
39
|
+
`libraries/sky130_fd_pr/latest/models/sky130.lib.spice`.
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
See [docs/quickstart.md](docs/quickstart.md) for a step-by-step walkthrough.
|
|
44
|
+
|
|
45
|
+
Working examples live in `silk/examples/`:
|
|
46
|
+
|
|
47
|
+
| File | What it shows |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `silk/examples/main.py` | Differential pair with factory API |
|
|
50
|
+
| `silk/examples/factory_api_example.py` | Full factory API: devices, passives, SPICE inspection |
|
|
51
|
+
| `silk/examples/parameter_sweep_example.py` | Design-space sweep with `Space`/`Variable` |
|
|
52
|
+
| `silk/examples/ldo_design.py` | Parameterized LDO with `Module` + `PyNetlist` DB tracking |
|
|
53
|
+
| `silk/examples/source_examples.py` | Voltage/current source waveforms |
|
|
54
|
+
|
|
55
|
+
## Core concepts
|
|
56
|
+
|
|
57
|
+
### `Module` — the circuit object
|
|
58
|
+
|
|
59
|
+
`Module` is the central design object. It holds devices, sources, passives, and
|
|
60
|
+
simulation commands and generates SPICE netlists.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from silk import Module
|
|
64
|
+
ckt = Module('PDK_skywater130', 'out_dir', 'my_circuit.cir', pdkDetails=pdk)
|
|
65
|
+
ckt.add(device1, device2) # add pre-constructed device objects
|
|
66
|
+
ckt.addSource(vsource) # add a voltage or current source
|
|
67
|
+
ckt.addPassive(capacitor) # add R, C, or L
|
|
68
|
+
ckt.addSimType(Transient(...)) # set the simulation type
|
|
69
|
+
ckt.simulate(corner='tt') # generate netlist + run ngspice + load results
|
|
70
|
+
sig = ckt.loadSignal('v(out)') # retrieve a waveform
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Factory API — device instantiation
|
|
74
|
+
|
|
75
|
+
Devices are instantiated directly from the PDK object. Pins and parameters are
|
|
76
|
+
keyword arguments — IDE autocomplete works on them.
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
mn = pdk.nmos1p8('mn', d='out', g='in', s='gnd', b='gnd', w=1.0, l=0.35, m=4)
|
|
80
|
+
mp = pdk.pmos1p8('mp', d='out', g='in', s='vdd', b='vdd', w=2.0, l=0.35)
|
|
81
|
+
|
|
82
|
+
# Parameters can be updated by direct attribute assignment after construction:
|
|
83
|
+
mn.w = 2.0
|
|
84
|
+
mn.d = 'new_out'
|
|
85
|
+
print(mn.to_spice()) # inspect the SPICE line
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### PDK loading
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# Option 1: load_pdk (uses $PDK_ROOT env var or ~/pdk)
|
|
92
|
+
from silk import load_pdk
|
|
93
|
+
pdk = load_pdk('sky130')
|
|
94
|
+
|
|
95
|
+
# Option 2: explicit paths
|
|
96
|
+
import os
|
|
97
|
+
from silk.pdk import PDK_skywater130
|
|
98
|
+
pdk = PDK_skywater130(
|
|
99
|
+
os.path.join(os.path.dirname(__file__), 'silk', 'pdk', 'data',
|
|
100
|
+
'skywater_130_device_details.yaml'),
|
|
101
|
+
libraryLocation='/path/to/sky130.lib.spice',
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Simulation types
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from silk.simulation import Transient, AC, DC, Noise, Corner
|
|
109
|
+
|
|
110
|
+
ckt.addSimType(Transient(step=1e-9, stop=100e-9))
|
|
111
|
+
ckt.addSimType(AC('dec', 100, 1e3, 1e9))
|
|
112
|
+
ckt.addSimType(DC(source='vin', start=0, stop=1.8, step=0.01))
|
|
113
|
+
|
|
114
|
+
# Corner is a str-subclass enum — plain strings also work
|
|
115
|
+
ckt.simulate(corner=Corner.TT)
|
|
116
|
+
ckt.simulate(corner='ff') # equivalent
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Sources
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from silk import sources
|
|
123
|
+
|
|
124
|
+
vs = sources.VoltageSource('vdd', positive='vdd', negative='gnd', dc=1.8)
|
|
125
|
+
cs = sources.CurrentSource('ibias', positive='vdd', negative='vnbias', dc=100e-6)
|
|
126
|
+
|
|
127
|
+
# Waveforms
|
|
128
|
+
vs_pulse = sources.VoltageSource('vin', positive='in', negative='gnd',
|
|
129
|
+
pulse=sources.Pulse(v1=0, v2=1.8, td=0,
|
|
130
|
+
tr=100e-12, tf=100e-12,
|
|
131
|
+
pw=5e-9, per=10e-9))
|
|
132
|
+
vs_sine = sources.VoltageSource('vin', positive='in', negative='gnd',
|
|
133
|
+
sine=sources.Sine(voffset=0, vampl=1, freq=1e6))
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Passives
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from silk.elements import passives
|
|
140
|
+
|
|
141
|
+
r = passives.Resistor('r1', pos='out', neg='gnd', resistance=10e3)
|
|
142
|
+
c = passives.Capacitor('c1', pos='out', neg='gnd', capacitance=100e-12)
|
|
143
|
+
l = passives.Inductor('l1', pos='a', neg='b', inductance=1e-9)
|
|
144
|
+
ckt.addPassive(r)
|
|
145
|
+
ckt.addPassive(c)
|
|
146
|
+
ckt.addPassive(l)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Ideal elements (ElementLibrary)
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from silk.elements import elements
|
|
153
|
+
|
|
154
|
+
r = elements.resistor('r1', p='out', n='gnd', value=10e3)
|
|
155
|
+
c = elements.capacitor('c1', p='out', n='gnd', value=100e-15)
|
|
156
|
+
vs = elements.vsource('vdd', p='vdd', n='gnd', dc=1.8)
|
|
157
|
+
ckt.add(r, c, vs)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Design-space exploration
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from silk import ModuleVariable, VarType
|
|
164
|
+
from silk.optimize import Space, Variable, Optimizer
|
|
165
|
+
|
|
166
|
+
# Create variables with bounds
|
|
167
|
+
w_n = pdk.nmos1p8.w.variable(name='w_n', value=1.0, bounds=(0.42, 20.0))
|
|
168
|
+
w_p = pdk.pmos1p8.w.variable(name='w_p', value=2.0, bounds=(0.42, 20.0))
|
|
169
|
+
l = pdk.nmos1p8.l.variable(name='l', value=0.15, bounds=(0.15, 1.0))
|
|
170
|
+
|
|
171
|
+
# Pass ModuleVariable objects directly as device parameters
|
|
172
|
+
mn = pdk.nmos1p8('mn', d='out', g='in', s='gnd', b='gnd', w=w_n, l=l)
|
|
173
|
+
mp = pdk.pmos1p8('mp', d='out', g='in', s='vdd', b='vdd', w=w_p, l=l)
|
|
174
|
+
|
|
175
|
+
# Build a ParameterSpace and sample it
|
|
176
|
+
space = Space([w_n, w_p, l])
|
|
177
|
+
points = space.sample(20, method='lhs') # Latin hypercube sampling
|
|
178
|
+
# also: method='random', 'sobol', 'grid'
|
|
179
|
+
|
|
180
|
+
for pt in points:
|
|
181
|
+
space.apply(pt) # updates variable .value fields
|
|
182
|
+
ckt.generateNetlist(corner='tt') # picks up new values automatically
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Schema export (GUI / code-gen integration)
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from silk import export_schema, module_schema
|
|
189
|
+
import json
|
|
190
|
+
|
|
191
|
+
# Export all PDK devices as a machine-readable dict
|
|
192
|
+
schema = export_schema(pdk)
|
|
193
|
+
print(json.dumps(schema, indent=2))
|
|
194
|
+
|
|
195
|
+
# Export a single Module's interface
|
|
196
|
+
mod_schema = module_schema(my_module)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Database / version tracking
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from silk.db import Database, TrackedModule, DesignStage
|
|
203
|
+
|
|
204
|
+
db = Database('designs.db')
|
|
205
|
+
tracked = TrackedModule(
|
|
206
|
+
'PDK_skywater130', 'out', 'ldo.cir', pdkDetails=pdk,
|
|
207
|
+
circuit_name='ldo_nmos', version='1.0',
|
|
208
|
+
stage=DesignStage.DEV, db_path='designs.db',
|
|
209
|
+
)
|
|
210
|
+
tracked.create_circuit_version(description='Initial attempt')
|
|
211
|
+
# ... build circuit ...
|
|
212
|
+
tracked.store_results(results, corner='tt', temperature=27)
|
|
213
|
+
tracked.promote() # DEV → STABLE → POST_LAYOUT → TAPEOUT
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Code generation
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from silk.codegen import Generator
|
|
220
|
+
|
|
221
|
+
gen = Generator(pdk)
|
|
222
|
+
code = gen.generate(my_module)
|
|
223
|
+
print(code)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Full API reference
|
|
227
|
+
|
|
228
|
+
See [docs/api-reference.md](docs/api-reference.md).
|
|
229
|
+
|
|
230
|
+
## Backward compatibility
|
|
231
|
+
|
|
232
|
+
Old `pynetlist.*` class names are still importable via `silk._compat`:
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
from silk._compat import PyModule, PySignal, ParameterSpace # deprecated
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The `PyNetlist` class is available at `silk.circuit.netlist.PyNetlist` as a
|
|
239
|
+
thin subclass of `Module` with optional legacy DB tracking.
|
|
240
|
+
|
|
241
|
+
## Package layout
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
silk/
|
|
245
|
+
__init__.py top-level re-exports
|
|
246
|
+
exceptions.py CircuitError hierarchy
|
|
247
|
+
_compat.py backward-compat aliases for old Py* names
|
|
248
|
+
|
|
249
|
+
circuit/ Module, ModuleTestbench, schema export
|
|
250
|
+
pdk/ PDK_skywater130, BasePDK, load_pdk
|
|
251
|
+
elements/ ElementLibrary, passives, AnalogElement
|
|
252
|
+
sources/ VoltageSource, CurrentSource, waveforms
|
|
253
|
+
signals/ Signal, NgspiceSignal, metrics
|
|
254
|
+
simulation/ Transient, AC, DC, Noise, Corner, NgspiceRunner
|
|
255
|
+
optimize/ Space, Variable, Optimizer
|
|
256
|
+
db/ Database, TrackedModule, DesignStage
|
|
257
|
+
codegen/ Generator
|
|
258
|
+
utils/ internal helpers
|
|
259
|
+
examples/ runnable example scripts
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Development
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
pip install -e ".[dev]"
|
|
266
|
+
pytest tests/ -q
|
|
267
|
+
```
|