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.
Files changed (99) hide show
  1. circuitsilk-0.1.0/LICENSE +21 -0
  2. circuitsilk-0.1.0/PKG-INFO +305 -0
  3. circuitsilk-0.1.0/README.md +267 -0
  4. circuitsilk-0.1.0/circuitsilk.egg-info/PKG-INFO +305 -0
  5. circuitsilk-0.1.0/circuitsilk.egg-info/SOURCES.txt +97 -0
  6. circuitsilk-0.1.0/circuitsilk.egg-info/dependency_links.txt +1 -0
  7. circuitsilk-0.1.0/circuitsilk.egg-info/requires.txt +13 -0
  8. circuitsilk-0.1.0/circuitsilk.egg-info/top_level.txt +2 -0
  9. circuitsilk-0.1.0/ngspice_read/__init__.py +0 -0
  10. circuitsilk-0.1.0/ngspice_read/ngdump-ic.py +46 -0
  11. circuitsilk-0.1.0/ngspice_read/ngspice_read.py +366 -0
  12. circuitsilk-0.1.0/pyproject.toml +55 -0
  13. circuitsilk-0.1.0/setup.cfg +4 -0
  14. circuitsilk-0.1.0/silk/__init__.py +70 -0
  15. circuitsilk-0.1.0/silk/_compat.py +24 -0
  16. circuitsilk-0.1.0/silk/circuit/__init__.py +9 -0
  17. circuitsilk-0.1.0/silk/circuit/circuit_elements.py +344 -0
  18. circuitsilk-0.1.0/silk/circuit/module_test.py +297 -0
  19. circuitsilk-0.1.0/silk/circuit/modules.py +796 -0
  20. circuitsilk-0.1.0/silk/circuit/netlist.py +267 -0
  21. circuitsilk-0.1.0/silk/circuit/spec_report.py +193 -0
  22. circuitsilk-0.1.0/silk/circuit/spice_netlister.py +325 -0
  23. circuitsilk-0.1.0/silk/codegen/__init__.py +4 -0
  24. circuitsilk-0.1.0/silk/codegen/generator.py +560 -0
  25. circuitsilk-0.1.0/silk/db/__init__.py +5 -0
  26. circuitsilk-0.1.0/silk/db/circuit_db.py +1150 -0
  27. circuitsilk-0.1.0/silk/db/cli.py +705 -0
  28. circuitsilk-0.1.0/silk/db/integration.py +472 -0
  29. circuitsilk-0.1.0/silk/db/structure_tracker.py +1238 -0
  30. circuitsilk-0.1.0/silk/elements/__init__.py +9 -0
  31. circuitsilk-0.1.0/silk/elements/analog_devices.yaml +54 -0
  32. circuitsilk-0.1.0/silk/elements/base.py +146 -0
  33. circuitsilk-0.1.0/silk/elements/factory.py +313 -0
  34. circuitsilk-0.1.0/silk/elements/library.py +44 -0
  35. circuitsilk-0.1.0/silk/elements/passives.py +87 -0
  36. circuitsilk-0.1.0/silk/elements/schema.py +350 -0
  37. circuitsilk-0.1.0/silk/examples/__init__.py +0 -0
  38. circuitsilk-0.1.0/silk/examples/compare_outputs.py +116 -0
  39. circuitsilk-0.1.0/silk/examples/factory_api_example.py +114 -0
  40. circuitsilk-0.1.0/silk/examples/ldo_design.py +214 -0
  41. circuitsilk-0.1.0/silk/examples/main.py +105 -0
  42. circuitsilk-0.1.0/silk/examples/parameter_sweep_example.py +226 -0
  43. circuitsilk-0.1.0/silk/examples/source_examples.py +299 -0
  44. circuitsilk-0.1.0/silk/exceptions.py +30 -0
  45. circuitsilk-0.1.0/silk/optimize/__init__.py +6 -0
  46. circuitsilk-0.1.0/silk/optimize/optimizer.py +424 -0
  47. circuitsilk-0.1.0/silk/optimize/parameter_space.py +469 -0
  48. circuitsilk-0.1.0/silk/pdk/__init__.py +15 -0
  49. circuitsilk-0.1.0/silk/pdk/_loader.py +51 -0
  50. circuitsilk-0.1.0/silk/pdk/basepdk.py +284 -0
  51. circuitsilk-0.1.0/silk/pdk/data/skywater_130_device_details.xlsx +0 -0
  52. circuitsilk-0.1.0/silk/pdk/data/skywater_130_device_details.yaml +889 -0
  53. circuitsilk-0.1.0/silk/pdk/data/~$skywater_130_device_details.xlsx +0 -0
  54. circuitsilk-0.1.0/silk/pdk/skywater130.py +37 -0
  55. circuitsilk-0.1.0/silk/signals/__init__.py +16 -0
  56. circuitsilk-0.1.0/silk/signals/base.py +187 -0
  57. circuitsilk-0.1.0/silk/signals/metrics.py +207 -0
  58. circuitsilk-0.1.0/silk/signals/spice.py +104 -0
  59. circuitsilk-0.1.0/silk/simulation/__init__.py +6 -0
  60. circuitsilk-0.1.0/silk/simulation/analysis.py +74 -0
  61. circuitsilk-0.1.0/silk/simulation/corner.py +63 -0
  62. circuitsilk-0.1.0/silk/simulation/runner.py +65 -0
  63. circuitsilk-0.1.0/silk/sources/__init__.py +27 -0
  64. circuitsilk-0.1.0/silk/sources/classes.py +342 -0
  65. circuitsilk-0.1.0/silk/sources/waveforms.py +148 -0
  66. circuitsilk-0.1.0/silk/utils/__init__.py +4 -0
  67. circuitsilk-0.1.0/silk/utils/_utils.py +25 -0
  68. circuitsilk-0.1.0/tests/test_add_method.py +177 -0
  69. circuitsilk-0.1.0/tests/test_analysis.py +213 -0
  70. circuitsilk-0.1.0/tests/test_analysis_types.py +221 -0
  71. circuitsilk-0.1.0/tests/test_circuit_db.py +867 -0
  72. circuitsilk-0.1.0/tests/test_circuit_elements.py +562 -0
  73. circuitsilk-0.1.0/tests/test_circuit_optimizer.py +530 -0
  74. circuitsilk-0.1.0/tests/test_codegen_ports.py +85 -0
  75. circuitsilk-0.1.0/tests/test_corner.py +87 -0
  76. circuitsilk-0.1.0/tests/test_element_library.py +185 -0
  77. circuitsilk-0.1.0/tests/test_elements_base.py +257 -0
  78. circuitsilk-0.1.0/tests/test_elements_factory.py +505 -0
  79. circuitsilk-0.1.0/tests/test_export_schema.py +154 -0
  80. circuitsilk-0.1.0/tests/test_fixtures_smoke.py +69 -0
  81. circuitsilk-0.1.0/tests/test_integration_parameter_space.py +243 -0
  82. circuitsilk-0.1.0/tests/test_load_pdk.py +50 -0
  83. circuitsilk-0.1.0/tests/test_module_test.py +531 -0
  84. circuitsilk-0.1.0/tests/test_ngspice_runner.py +70 -0
  85. circuitsilk-0.1.0/tests/test_parameter_space.py +717 -0
  86. circuitsilk-0.1.0/tests/test_passives.py +295 -0
  87. circuitsilk-0.1.0/tests/test_pdk.py +686 -0
  88. circuitsilk-0.1.0/tests/test_pymodule.py +935 -0
  89. circuitsilk-0.1.0/tests/test_pynetlist.py +2026 -0
  90. circuitsilk-0.1.0/tests/test_sig_sources.py +869 -0
  91. circuitsilk-0.1.0/tests/test_signal_metrics.py +175 -0
  92. circuitsilk-0.1.0/tests/test_signals.py +294 -0
  93. circuitsilk-0.1.0/tests/test_silk_imports.py +115 -0
  94. circuitsilk-0.1.0/tests/test_sim_cache.py +131 -0
  95. circuitsilk-0.1.0/tests/test_spec_report.py +166 -0
  96. circuitsilk-0.1.0/tests/test_spice_netlister.py +377 -0
  97. circuitsilk-0.1.0/tests/test_structure_tracker.py +1471 -0
  98. circuitsilk-0.1.0/tests/test_tracked_netlist.py +610 -0
  99. 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
+ ```