circuitgenome 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.
- circuitgenome-0.1.0/LICENSE +21 -0
- circuitgenome-0.1.0/PKG-INFO +464 -0
- circuitgenome-0.1.0/README.md +412 -0
- circuitgenome-0.1.0/circuitgenome/__init__.py +4 -0
- circuitgenome-0.1.0/circuitgenome/cli.py +126 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/__init__.py +13 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/bias_pruning.py +121 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/cmfb_compatibility.py +69 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/config/opamp_modules.yaml +830 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/config/opamp_topologies.yaml +437 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/loader.py +103 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/models.py +151 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/net_aliasing.py +74 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/netlist.py +159 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/output_compatibility.py +75 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/polarity_compatibility.py +50 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/synthesizer.py +296 -0
- circuitgenome-0.1.0/circuitgenome/synthesizer/tail_current_compatibility.py +92 -0
- circuitgenome-0.1.0/circuitgenome/visualizer/__init__.py +0 -0
- circuitgenome-0.1.0/circuitgenome/visualizer/app.py +115 -0
- circuitgenome-0.1.0/circuitgenome/visualizer/graph.py +142 -0
- circuitgenome-0.1.0/circuitgenome.egg-info/PKG-INFO +464 -0
- circuitgenome-0.1.0/circuitgenome.egg-info/SOURCES.txt +29 -0
- circuitgenome-0.1.0/circuitgenome.egg-info/dependency_links.txt +1 -0
- circuitgenome-0.1.0/circuitgenome.egg-info/entry_points.txt +2 -0
- circuitgenome-0.1.0/circuitgenome.egg-info/requires.txt +5 -0
- circuitgenome-0.1.0/circuitgenome.egg-info/top_level.txt +1 -0
- circuitgenome-0.1.0/pyproject.toml +45 -0
- circuitgenome-0.1.0/setup.cfg +4 -0
- circuitgenome-0.1.0/tests/test_synthesizer.py +1367 -0
- circuitgenome-0.1.0/tests/test_visualizer.py +185 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Analog ML
|
|
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,464 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: circuitgenome
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python toolkit for analog circuit topology synthesis and recognition, focused on op-amp design.
|
|
5
|
+
Author: Analog ML
|
|
6
|
+
Maintainer: Analog ML
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2026 Analog ML
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Homepage, https://github.com/analog-ml/CircuitGenome
|
|
30
|
+
Project-URL: Repository, https://github.com/analog-ml/CircuitGenome
|
|
31
|
+
Project-URL: Issues, https://github.com/analog-ml/CircuitGenome/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/analog-ml/CircuitGenome/blob/main/CHANGELOG.md
|
|
33
|
+
Keywords: analog,circuit-design,spice,eda,op-amp,topology-synthesis
|
|
34
|
+
Classifier: Development Status :: 3 - Alpha
|
|
35
|
+
Classifier: Intended Audience :: Science/Research
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Operating System :: OS Independent
|
|
38
|
+
Classifier: Programming Language :: Python :: 3
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
|
|
44
|
+
Requires-Python: >=3.9
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
License-File: LICENSE
|
|
47
|
+
Requires-Dist: pyyaml>=6.0
|
|
48
|
+
Provides-Extra: viz
|
|
49
|
+
Requires-Dist: streamlit>=1.30; extra == "viz"
|
|
50
|
+
Requires-Dist: pyvis>=0.3; extra == "viz"
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
|
|
53
|
+
# CircuitGenome
|
|
54
|
+
|
|
55
|
+
A Python toolkit for analog circuit topology synthesis and recognition, focused on op-amp design.
|
|
56
|
+
|
|
57
|
+
## Modules
|
|
58
|
+
|
|
59
|
+
### 1. Topology Synthesizer *(available)*
|
|
60
|
+
Constructs complete op-amp circuits from modular building blocks. Given a topology configuration (number of stages, output type), it enumerates every valid combination of module variants and emits SPICE netlists.
|
|
61
|
+
|
|
62
|
+
### 2. Subcircuit Recognizer *(coming soon)*
|
|
63
|
+
Takes a flat SPICE netlist and identifies structural subcircuits (differential pairs, cascode mirrors, etc.) at multiple hierarchy levels.
|
|
64
|
+
|
|
65
|
+
### 3. Functional Block Recognizer *(coming soon)*
|
|
66
|
+
Takes a flat SPICE netlist and identifies which functional roles (input stage, load, bias, compensation, etc.) each part of the circuit plays.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Installation
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install -e .
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Requires Python 3.9+ and PyYAML.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Topology Synthesizer
|
|
81
|
+
|
|
82
|
+
The synthesizer works by combining **module variants** according to a **topology template**. Each module category has a fixed port interface; variants differ only in their internal implementation.
|
|
83
|
+
|
|
84
|
+
### Module categories
|
|
85
|
+
|
|
86
|
+
| Category | Variants |
|
|
87
|
+
|---|---|
|
|
88
|
+
| Input pair | PMOS/NMOS differential pair, with/without source degeneration, inverter-based |
|
|
89
|
+
| Load | Resistor (VDD-side / GND-side), PMOS/NMOS active (current mirror), PMOS/NMOS current source, folded cascode (PMOS/NMOS-input, single-output & differential-output), telescopic cascode (PMOS/NMOS) |
|
|
90
|
+
| Tail current | Current mirror (PMOS/NMOS), cascode current mirror (PMOS/NMOS), resistor (VDD-side / GND-side) |
|
|
91
|
+
| Bias generation | Diode-connected MOSFET ladder, magic battery (current mirror), resistor ladder |
|
|
92
|
+
| CMFB | Resistive-sense 5T OTA, differential-difference amplifier (DDA) — present only when `load` has a differential-output cascode (`output_cardinality: "differential"`) |
|
|
93
|
+
| Compensation | Miller cap, Miller cap + nulling resistor, indirect |
|
|
94
|
+
| Second stage | Common-source, common-drain (source follower), differential OTA |
|
|
95
|
+
|
|
96
|
+
**Input pair**
|
|
97
|
+
|
|
98
|
+

|
|
99
|
+
|
|
100
|
+
**Load**
|
|
101
|
+
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
**Tail current**
|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+
**Bias generation**
|
|
109
|
+
|
|
110
|
+

|
|
111
|
+
|
|
112
|
+
**CMFB**
|
|
113
|
+
|
|
114
|
+

|
|
115
|
+
|
|
116
|
+
### Topology templates
|
|
117
|
+
|
|
118
|
+
| Name | Stages | Output | Compensation |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| `one_stage_opamp` | 1 | Single-ended | — |
|
|
121
|
+
| `two_stage_opamp_single_ended` | 2 | Single-ended | — |
|
|
122
|
+
| `two_stage_opamp_fully_differential` | 2 | Fully differential | — |
|
|
123
|
+
| `three_stage_opamp_nmc_single_ended` | 3 | Single-ended | Nested Miller (NMC) |
|
|
124
|
+
| `three_stage_opamp_rnmc_single_ended` | 3 | Single-ended | Reversed Nested Miller (RNMC) |
|
|
125
|
+
| `three_stage_opamp_nmc_fully_differential` | 3 | Fully differential | Nested Miller (NMC) |
|
|
126
|
+
| `three_stage_opamp_rnmc_fully_differential` | 3 | Fully differential | Reversed Nested Miller (RNMC) |
|
|
127
|
+
|
|
128
|
+
Of the 5 × 12 × 6 = 360 possible `input_pair` / `load` / `tail_current`
|
|
129
|
+
combinations, only 144 have compatible PMOS/NMOS polarities (see "Polarity
|
|
130
|
+
compatibility filter" below) — the rest are filtered out by
|
|
131
|
+
`enumerate_circuits`. Of those 144, 72 use `inverter_based_input`, whose
|
|
132
|
+
self-biased design never references its `tail` port: the "Tail-current
|
|
133
|
+
compatibility filter" below collapses those 72 combinations' 6
|
|
134
|
+
`tail_current` choices down to 1 canonical choice (72 -> 12), leaving **84**
|
|
135
|
+
effective combinations (the 72 combinations using a `differential_pair_*`
|
|
136
|
+
variant are unaffected). Of those 84, the "Output-cardinality compatibility
|
|
137
|
+
filter" below further splits them by which output type the `load` supports:
|
|
138
|
+
**70** are valid for single-ended topologies and **56** are valid for
|
|
139
|
+
fully-differential topologies. A 1-stage topology therefore yields
|
|
140
|
+
**210 unique circuits** (70 × 3). A 2-stage single-ended topology yields
|
|
141
|
+
**1890 circuits** (70 × 3 × 3 × 3); a 2-stage fully-differential topology
|
|
142
|
+
also has a `cmfb` slot, but (per the "CMFB compatibility filter" below) only
|
|
143
|
+
the 14-of-56 combinations using a `"differential"`-cardinality `load` keep
|
|
144
|
+
both `cmfb` variants -- 28 + 42 = 70 effective load/cmfb combinations, so it
|
|
145
|
+
yields **17 010 circuits** (70 × 3⁵). Each 3-stage single-ended topology adds
|
|
146
|
+
two more `second_stage` slots (gm2, gm3) and two `compensation` slots (Cm1,
|
|
147
|
+
Cm2), yielding **17 010 circuits** (70 × 3⁵). Each 3-stage
|
|
148
|
+
fully-differential topology duplicates those four slots per output path
|
|
149
|
+
(keeping the single `cmfb` slot), yielding **1 377 810 circuits** (70 × 3⁹).
|
|
150
|
+
|
|
151
|
+
### Polarity compatibility filter
|
|
152
|
+
|
|
153
|
+
A circuit only has a real DC current path if its `input_pair`, `load`, and
|
|
154
|
+
`tail_current` agree on polarity. For example, `differential_pair_nmos`
|
|
155
|
+
draws current out of `out1`/`out2` into the tail, so it needs a `load` that
|
|
156
|
+
*sources* current into `out1`/`out2` from vdd and a `tail_current` that
|
|
157
|
+
*sinks* the tail node to gnd — pairing it with `active_load_nmos` (which also
|
|
158
|
+
sinks to gnd) or `current_mirror_tail_pmos` (which also sources into the
|
|
159
|
+
tail) leaves a node with no current path.
|
|
160
|
+
|
|
161
|
+
Each `input_pair`, `load`, and `tail_current` variant declares a `polarity`
|
|
162
|
+
field in `opamp_modules.yaml`: `pmos_input`, `nmos_input`, or omitted for
|
|
163
|
+
variants that work with either (`inverter_based_input`, and currently all
|
|
164
|
+
`bias_generation` variants). `enumerate_circuits` skips any combination where
|
|
165
|
+
`load`/`tail_current`'s `polarity` (if set) doesn't match `input_pair`'s. To
|
|
166
|
+
extend the filter to a new or edited variant, just add the matching
|
|
167
|
+
`polarity:` tag in YAML — no code changes needed
|
|
168
|
+
(`circuitgenome/synthesizer/polarity_compatibility.py`).
|
|
169
|
+
|
|
170
|
+
### Output-cardinality compatibility filter
|
|
171
|
+
|
|
172
|
+
`load.in1`/`in2` (the folding nodes fed by `input_pair.out1`/`out2`) and
|
|
173
|
+
`load.out`/`out1`/`out2` (the load's actual output node(s)) are wired to
|
|
174
|
+
*separate* nets by every topology. Whether the output-side ports get a net at
|
|
175
|
+
all depends on the topology's `output_type`: `load.out1`/`out2` are wired to
|
|
176
|
+
`net_loadout1`/`net_loadout2` only in `fully_differential` topologies (sensed
|
|
177
|
+
by `cmfb`/`second_stage*`/`comp*`), and `load.out`/`out2` are wired to the
|
|
178
|
+
stage's output node only in `single_ended` topologies.
|
|
179
|
+
|
|
180
|
+
Folded-cascode/telescopic-cascode loads with a single output
|
|
181
|
+
(`folded_cascode_load_*_input_single_output`,
|
|
182
|
+
`telescopic_cascode_load_{pmos,nmos}`) declare `out` as mandatory, so they'd
|
|
183
|
+
be left floating in a `fully_differential` topology. Folded-cascode loads
|
|
184
|
+
with differential outputs (`folded_cascode_load_*_input_differential_output`)
|
|
185
|
+
declare `out1`/`out2` as mandatory cascode-output nodes, so they'd be left
|
|
186
|
+
floating in a `single_ended` topology (where `net_loadout1`/`net_loadout2`
|
|
187
|
+
aren't defined).
|
|
188
|
+
|
|
189
|
+
These 6 `load` variants declare an `output_cardinality` field in
|
|
190
|
+
`opamp_modules.yaml`: `"single"` (compatible only with `single_ended`) or
|
|
191
|
+
`"differential"` (compatible only with `fully_differential`); the other 6
|
|
192
|
+
`load` variants (resistor/active/current-source) declare `out1`/`out2` as
|
|
193
|
+
`alias_of: in1`/`in2` — a net-merge pass (`net_aliasing.py`) collapses their
|
|
194
|
+
`out1`/`out2` net back onto `in1`/`in2`'s after assembly, restoring a single
|
|
195
|
+
shared in/out node regardless of `output_type`. They're untagged and
|
|
196
|
+
compatible with either. `enumerate_circuits` skips any combination where
|
|
197
|
+
`load`'s `output_cardinality` (if set) doesn't match the topology's
|
|
198
|
+
`output_type`. To extend the filter to a new or edited `load` variant, just
|
|
199
|
+
add the matching `output_cardinality:` tag in YAML — no code changes needed
|
|
200
|
+
(`circuitgenome/synthesizer/output_compatibility.py`).
|
|
201
|
+
|
|
202
|
+
### CMFB compatibility filter
|
|
203
|
+
|
|
204
|
+
`fully_differential` topologies have a `cmfb` slot, wired
|
|
205
|
+
`cmfb.out -> net_cmfb_out -> load.bias_cmfb`. Of the 12 `load` variants, only
|
|
206
|
+
the 2 tagged `output_cardinality: "differential"`
|
|
207
|
+
(`folded_cascode_load_*_input_differential_output`) declare `bias_cmfb` as a
|
|
208
|
+
real consumer (gating `mn3`/`mn4` or `mp1`/`mp2`); the other 10 declare it
|
|
209
|
+
`optional` and never reference it, so `net_cmfb_out` would drive nothing.
|
|
210
|
+
|
|
211
|
+
For a `load` whose `output_cardinality` isn't `"differential"`,
|
|
212
|
+
`enumerate_circuits` only allows the canonical `resistive_sense_cmfb` variant
|
|
213
|
+
through (avoiding a duplicate-circuit enumeration of `dda_cmfb`), then prunes
|
|
214
|
+
it to an empty placeholder — it contributes no devices, `cmfb.bias` is no
|
|
215
|
+
longer a needed bias rail, and the `vcm_ref` external port is left
|
|
216
|
+
unconnected for these circuits. To extend: tag a new or edited `load` variant
|
|
217
|
+
with `output_cardinality: "differential"` (and give it a real `bias_cmfb`
|
|
218
|
+
consumer) to make it a genuine `cmfb` consumer — no code changes needed
|
|
219
|
+
(`circuitgenome/synthesizer/cmfb_compatibility.py`).
|
|
220
|
+
|
|
221
|
+
### Tail-current compatibility filter
|
|
222
|
+
|
|
223
|
+
Every topology has a `tail_current` slot, wired `input_pair.tail ->
|
|
224
|
+
net_tail <- tail_current.out`. Of the 5 `input_pair` variants, only the 4
|
|
225
|
+
`differential_pair_*` variants reference their `tail` port from a device
|
|
226
|
+
terminal; `inverter_based_input` — two back-to-back CMOS inverters — is
|
|
227
|
+
self-biased by design and never references `tail`, so without this filter
|
|
228
|
+
`net_tail` would be a floating, single-terminal node and `tail_current` would
|
|
229
|
+
drive nothing.
|
|
230
|
+
|
|
231
|
+
For an `input_pair` that doesn't reference `tail`, `enumerate_circuits` only
|
|
232
|
+
allows the canonical `current_mirror_tail_pmos` variant through (avoiding a
|
|
233
|
+
duplicate-circuit enumeration of the other 5 `tail_current` variants), then
|
|
234
|
+
prunes it to an empty placeholder — it contributes no devices, `net_tail` is
|
|
235
|
+
no longer floating, and `tail_current.bias` is no longer a needed bias rail.
|
|
236
|
+
To extend: wire a new or edited `input_pair` variant's tail-side device
|
|
237
|
+
terminal(s) to `tail` to make it a genuine `tail_current` consumer — no code
|
|
238
|
+
changes needed (`circuitgenome/synthesizer/tail_current_compatibility.py`).
|
|
239
|
+
|
|
240
|
+
### Three-stage compensation schemes
|
|
241
|
+
|
|
242
|
+
Both 3-stage templates reuse the existing `second_stage` modules for the
|
|
243
|
+
second (gm2) and third (gm3) gain stages, and the existing `compensation`
|
|
244
|
+
modules for the two Miller capacitors Cm1/Cm2 — no new module variants are
|
|
245
|
+
required.
|
|
246
|
+
|
|
247
|
+
- **Nested Miller (NMC)** — both Cm1 and Cm2 return to the final output node:
|
|
248
|
+
Cm1 spans gm2+gm3 (outer loop), Cm2 spans gm3 only (inner loop).
|
|
249
|
+
- **Reversed Nested Miller (RNMC)** — Cm1 spans gm3 only (gm2's output to the
|
|
250
|
+
final output), while Cm2 spans gm2 only (gm1's output to gm2's output)
|
|
251
|
+
instead of returning to the final output. This reduces output-node loading,
|
|
252
|
+
which is useful when gm3 is a low-gain buffer.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## CLI Usage
|
|
257
|
+
|
|
258
|
+
### List available topologies
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
circuitgenome synthesize --list-topologies
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
one_stage_opamp (stages=1, output=single_ended)
|
|
266
|
+
two_stage_opamp_single_ended (stages=2, output=single_ended)
|
|
267
|
+
two_stage_opamp_fully_differential (stages=2, output=fully_differential)
|
|
268
|
+
three_stage_opamp_nmc_single_ended (stages=3, output=single_ended, compensation=nested_miller)
|
|
269
|
+
three_stage_opamp_rnmc_single_ended (stages=3, output=single_ended, compensation=reversed_nested_miller)
|
|
270
|
+
three_stage_opamp_nmc_fully_differential (stages=3, output=fully_differential, compensation=nested_miller)
|
|
271
|
+
three_stage_opamp_rnmc_fully_differential (stages=3, output=fully_differential, compensation=reversed_nested_miller)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### List available module variants
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
circuitgenome synthesize --list-modules
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Generate circuits
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# All 1-stage single-ended variants, flat SPICE
|
|
284
|
+
circuitgenome synthesize --stages 1 --output-dir ./circuits/
|
|
285
|
+
|
|
286
|
+
# All 2-stage single-ended variants, both flat and hierarchical SPICE
|
|
287
|
+
circuitgenome synthesize --stages 2 --output-type single_ended --format both --output-dir ./circuits/
|
|
288
|
+
|
|
289
|
+
# Dry run — count circuits without writing files
|
|
290
|
+
circuitgenome synthesize --stages 2 --dry-run
|
|
291
|
+
|
|
292
|
+
# Specific topology by name
|
|
293
|
+
circuitgenome synthesize --topology two_stage_opamp_fully_differential --output-dir ./circuits/
|
|
294
|
+
|
|
295
|
+
# 3-stage, nested Miller compensation, single-ended
|
|
296
|
+
circuitgenome synthesize --topology three_stage_opamp_nmc_single_ended --output-dir ./circuits/
|
|
297
|
+
|
|
298
|
+
# Dry run — count all 3-stage variants (NMC + RNMC, single-ended + fully differential)
|
|
299
|
+
circuitgenome synthesize --stages 3 --dry-run
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Visualize topologies
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
circuitgenome visualize
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Launches a Streamlit web UI for browsing topologies and module variants: pick
|
|
309
|
+
a topology, swap each slot's module variant, and see the resulting block
|
|
310
|
+
diagram (and SPICE netlist, for valid combinations) update live. Requires the
|
|
311
|
+
`viz` extra:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
pip install circuitgenome[viz]
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+

|
|
318
|
+
|
|
319
|
+
#### CLI options
|
|
320
|
+
|
|
321
|
+
| Flag | Description | Default |
|
|
322
|
+
|---|---|---|
|
|
323
|
+
| `--stages 1\|2\|3` | Filter by number of stages | all |
|
|
324
|
+
| `--output-type single_ended\|fully_differential` | Filter by output type | all |
|
|
325
|
+
| `--topology NAME` | Use one specific topology | all |
|
|
326
|
+
| `--format flat\|hierarchical\|both` | SPICE output format | `flat` |
|
|
327
|
+
| `--output-dir PATH` | Directory for output files | `.` |
|
|
328
|
+
| `--dry-run` | Count circuits without writing | off |
|
|
329
|
+
| `--list-topologies` | Print topology names and exit | — |
|
|
330
|
+
| `--list-modules` | Print module variants and exit | — |
|
|
331
|
+
|
|
332
|
+
### Output format
|
|
333
|
+
|
|
334
|
+
Each generated circuit gets its own `.ckt` file. For `--format both`, two files are written per circuit:
|
|
335
|
+
|
|
336
|
+
**Flat SPICE** (`circuit_0001_flat.ckt`) — all devices in a single `.subckt` block:
|
|
337
|
+
|
|
338
|
+
```spice
|
|
339
|
+
.subckt circuit_0001 ibias in1 in2 out vdd! gnd!
|
|
340
|
+
m1_input_pair net_diff1 in1 net_tail net_tail pmos
|
|
341
|
+
m2_input_pair net_mid in2 net_tail net_tail pmos
|
|
342
|
+
r1_load vdd! net_diff1 1k
|
|
343
|
+
r2_load vdd! net_mid 1k
|
|
344
|
+
m1_tail_current net_tail_bias net_tail_bias vdd! vdd! pmos
|
|
345
|
+
m2_tail_current net_tail net_tail_bias vdd! vdd! pmos
|
|
346
|
+
mp1_bias_gen ibias ibias vdd! vdd! pmos
|
|
347
|
+
mn1_bias_gen net_bias1 net_bias1 gnd! gnd! nmos
|
|
348
|
+
mn2_bias_gen net_bias2 net_bias2 gnd! gnd! nmos
|
|
349
|
+
mn3_bias_gen net_bias3 net_bias3 gnd! gnd! nmos
|
|
350
|
+
mn4_bias_gen net_bias4 net_bias4 gnd! gnd! nmos
|
|
351
|
+
c1_compensation net_mid out 1p
|
|
352
|
+
mn1_second_stage out net_mid gnd! gnd! nmos
|
|
353
|
+
mp1_second_stage out net_bias1 vdd! vdd! pmos
|
|
354
|
+
.ends
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Hierarchical SPICE** (`circuit_0001_hier.ckt`) — one `.subckt` per module, top-level uses `X` instances:
|
|
358
|
+
|
|
359
|
+
```spice
|
|
360
|
+
.subckt differential_pair_pmos in1 in2 out1 out2 tail vdd gnd
|
|
361
|
+
m1 out1 in1 tail tail pmos
|
|
362
|
+
m2 out2 in2 tail tail pmos
|
|
363
|
+
.ends
|
|
364
|
+
|
|
365
|
+
.subckt resistor_load_vdd in1 in2 out1 out2 vdd gnd
|
|
366
|
+
r1 vdd in1 1k
|
|
367
|
+
r2 vdd in2 1k
|
|
368
|
+
.ends
|
|
369
|
+
|
|
370
|
+
* ... (one block per module variant used)
|
|
371
|
+
|
|
372
|
+
.subckt circuit_0001 ibias in1 in2 out vdd! gnd!
|
|
373
|
+
Xinput_pair in1 in2 net_diff1 net_mid net_tail vdd! gnd! differential_pair_pmos
|
|
374
|
+
Xload net_diff1 net_mid net_diff1 net_mid vdd! gnd! resistor_load_vdd
|
|
375
|
+
Xtail_current net_tail net_tail_bias vdd! gnd! current_mirror_tail_pmos
|
|
376
|
+
Xbias_gen ibias net_bias1 net_bias2 net_bias3 net_bias4 vdd! gnd! diode_connected_mosfet_bias
|
|
377
|
+
Xcompensation net_mid out miller_cap
|
|
378
|
+
Xsecond_stage net_mid out net_bias1 vdd! gnd! common_source
|
|
379
|
+
.ends
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Python API
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
from circuitgenome import synthesize
|
|
388
|
+
from circuitgenome.synthesizer import to_flat_spice, to_hierarchical_spice
|
|
389
|
+
|
|
390
|
+
# Generate all 2-stage single-ended circuits
|
|
391
|
+
circuits = synthesize({"stages": 2, "output_type": "single_ended"})
|
|
392
|
+
print(f"{len(circuits)} circuits generated")
|
|
393
|
+
|
|
394
|
+
# Inspect the first circuit
|
|
395
|
+
c = circuits[0]
|
|
396
|
+
print(c.topology) # "two_stage_opamp_single_ended"
|
|
397
|
+
print(c.variant_map) # {"input_pair": <ModuleVariant>, "load": <ModuleVariant>, ...}
|
|
398
|
+
|
|
399
|
+
# Serialize to SPICE
|
|
400
|
+
flat = to_flat_spice(c, name="my_opamp")
|
|
401
|
+
hier = to_hierarchical_spice(c, name="my_opamp")
|
|
402
|
+
|
|
403
|
+
# Use a specific topology by name
|
|
404
|
+
circuits = synthesize({"topology": "one_stage_opamp"})
|
|
405
|
+
|
|
406
|
+
# All 3-stage single-ended circuits using Reversed Nested Miller Compensation
|
|
407
|
+
circuits = synthesize({
|
|
408
|
+
"stages": 3,
|
|
409
|
+
"output_type": "single_ended",
|
|
410
|
+
"compensation_scheme": "reversed_nested_miller",
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
# Load custom module/topology definitions
|
|
414
|
+
from circuitgenome.synthesizer.loader import load_modules, load_topologies
|
|
415
|
+
from circuitgenome.synthesizer import enumerate_circuits
|
|
416
|
+
|
|
417
|
+
modules = load_modules("path/to/my_modules.yaml")
|
|
418
|
+
topologies = load_topologies("path/to/my_topologies.yaml")
|
|
419
|
+
for circuit in enumerate_circuits(topologies[0], modules):
|
|
420
|
+
print(to_flat_spice(circuit))
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## Extending with custom modules
|
|
426
|
+
|
|
427
|
+
Add new variants to `circuitgenome/synthesizer/config/opamp_modules.yaml`:
|
|
428
|
+
|
|
429
|
+
```yaml
|
|
430
|
+
- name: my_custom_input_pair
|
|
431
|
+
category: input_pair
|
|
432
|
+
display_name: "My Custom Input Pair"
|
|
433
|
+
ports:
|
|
434
|
+
- {name: in1, role: input}
|
|
435
|
+
- {name: in2, role: input}
|
|
436
|
+
- {name: out1, role: output}
|
|
437
|
+
- {name: out2, role: output}
|
|
438
|
+
- {name: tail, role: supply_in}
|
|
439
|
+
- {name: vdd, role: supply}
|
|
440
|
+
- {name: gnd, role: supply}
|
|
441
|
+
devices:
|
|
442
|
+
- {ref: m1, type: pmos, d: out1, g: in1, s: tail, b: tail}
|
|
443
|
+
- {ref: m2, type: pmos, d: out2, g: in2, s: tail, b: tail}
|
|
444
|
+
- {ref: m3, type: nmos, d: out1, g: in1, s: gnd, b: gnd}
|
|
445
|
+
- {ref: m4, type: nmos, d: out2, g: in2, s: gnd, b: gnd}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
The new variant is picked up automatically — no code changes needed.
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## Running tests
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
python3 -m pytest tests/ -v
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## References
|
|
461
|
+
|
|
462
|
+
- *A Data-Driven Analog Circuit Synthesizer with Automatic Topology Selection and Sizing*
|
|
463
|
+
- *FUBOCO: Structure Synthesis of Basic Op-Amps by FUnctional BlOck COmposition*
|
|
464
|
+
- *A Functional Block Decomposition Method for Automatic Op-Amp Design*
|