Extending CircuitGenome¶
All module variants and topology templates are defined in plain YAML files inside the package. No code changes are required to add new variants or topologies — edit (or replace) the YAML and the synthesizer picks them up automatically.
Adding a module variant¶
Open circuitgenome/synthesizer/config/opamp_modules.yaml and append an
entry under the modules list.
Required fields:
Field |
Description |
|---|---|
|
Unique snake_case identifier. |
|
One of the eight canonical categories: |
|
Human-readable label shown in |
|
List of port objects |
|
List of device objects (see below). |
Optional variant tags (all default to unset; see the Overview for the electrical rationale and the filters that consume them):
Field |
Description |
|---|---|
|
|
|
|
|
Reason string that parks the variant: it stays loadable (recognizer,
visualizer) but |
|
Reason string for a variant whose wiring is functionally correct but
whose DC bias does not close on the default (low-voltage) spec class
(e.g. the stacked-diode cascode tails, issue #111). Dropped from
enumeration unless |
Device fields:
Field |
Values / description |
|---|---|
|
Reference designator within the module (e.g. |
|
|
MOSFET terminals |
|
Resistor terminals |
|
Capacitor terminals |
|
Terminal values are local net names inside the module. Names that match
a port name are replaced by the global net during synthesis. All other names
become internal nets prefixed with the slot name (e.g.
input_pair_internal_node).
Example — CMOS inverter-pair input stage¶
- name: cmos_inverter_pair
category: input_pair
display_name: "CMOS Inverter-Pair Input Stage"
ports:
- {name: in1, role: input}
- {name: in2, role: input}
- {name: out1, role: output}
- {name: out2, role: output}
- {name: tail, role: optional}
- {name: vdd, role: supply}
- {name: gnd, role: supply}
devices:
- {ref: mp1, type: pmos, d: out1, g: in1, s: vdd, b: vdd}
- {ref: mn1, type: nmos, d: out1, g: in1, s: gnd, b: gnd}
- {ref: mp2, type: pmos, d: out2, g: in2, s: vdd, b: vdd}
- {ref: mn2, type: nmos, d: out2, g: in2, s: gnd, b: gnd}
Port roles¶
Role |
Meaning |
|---|---|
|
Signal input. |
|
Signal output. |
|
Power rail ( |
|
Driven supply node (e.g. tail current output driving the diff pair). |
|
Port exists in the canonical interface but this variant does not use it. Unconnected in the topology template. |
Adding a topology template¶
Open circuitgenome/synthesizer/config/opamp_topologies.yaml and append an
entry under the topologies list.
Required fields:
Field |
Description |
|---|---|
|
Unique identifier. |
|
Dict with |
|
Ordered list of top-level subcircuit port names (SPICE order). |
|
List of |
|
List of |
Supply ports (vdd / gnd) on every slot auto-connect to vdd! /
gnd! even if not listed in connections.
Note
Standard 3-stage op-amps using Nested Miller (NMC) and Reversed Nested
Miller (RNMC) compensation already ship as built-in templates —
three_stage_opamp_nmc_single_ended,
three_stage_opamp_rnmc_single_ended, and their fully-differential
counterparts. See Overview for details. The example below shows
a third compensation arrangement (one Miller cap per stage, in cascade)
to illustrate the general schema for adding your own variants.
Example — 3-stage op-amp with cascade (single-Miller-per-stage) compensation¶
- name: three_stage_opamp_cascade_miller
config:
output_type: single_ended
stages: 3
compensation_scheme: cascade_miller
external_ports: [ibias, in1, in2, out, vdd!, gnd!]
slots:
- {name: input_pair, category: input_pair}
- {name: load, category: load}
- {name: tail_current, category: tail_current}
- {name: bias_gen, category: bias_generation}
- {name: comp_1, category: compensation}
- {name: second_stage, category: amplification_stage}
- {name: comp_2, category: compensation}
- {name: third_stage, category: amplification_stage}
connections:
- {slot: input_pair, port: in1, net: in1}
- {slot: input_pair, port: in2, net: in2}
- {slot: input_pair, port: out1, net: net_diff1}
- {slot: input_pair, port: out2, net: net_mid1}
- {slot: input_pair, port: tail, net: net_tail}
- {slot: load, port: in1, net: net_diff1}
- {slot: load, port: in2, net: net_mid1}
- {slot: load, port: out1, net: net_diff1}
- {slot: load, port: out2, net: net_mid1}
- {slot: load, port: out, net: net_mid1}
- {slot: load, port: bias1, net: net_bias1}
- {slot: load, port: bias2, net: net_bias2}
- {slot: load, port: bias3, net: net_bias3}
- {slot: load, port: bias_cmfb, net: net_bias4}
- {slot: tail_current, port: out, net: net_tail}
- {slot: tail_current, port: bias, net: net_bias7}
- {slot: tail_current, port: bias_casc, net: net_bias8}
- {slot: bias_gen, port: ibias, net: ibias}
- {slot: bias_gen, port: out1, net: net_bias1}
- {slot: bias_gen, port: out2, net: net_bias2}
- {slot: bias_gen, port: out3, net: net_bias3}
- {slot: bias_gen, port: out4, net: net_bias4}
- {slot: bias_gen, port: out5, net: net_bias5}
- {slot: bias_gen, port: out6, net: net_bias6}
- {slot: bias_gen, port: out7, net: net_bias7}
- {slot: bias_gen, port: out8, net: net_bias8}
- {slot: second_stage, port: in, net: net_mid1}
- {slot: second_stage, port: out, net: net_mid2}
- {slot: second_stage, port: bias, net: net_bias5}
- {slot: comp_1, port: in, net: net_mid1}
- {slot: comp_1, port: out, net: net_mid2}
- {slot: third_stage, port: in, net: net_mid2}
- {slot: third_stage, port: out, net: out}
- {slot: third_stage, port: bias, net: net_bias6}
- {slot: comp_2, port: in, net: net_mid2}
- {slot: comp_2, port: out, net: out}
Using custom files at runtime¶
Pass paths directly to the Python API:
from circuitgenome.synthesizer.loader import load_modules, load_topologies
from circuitgenome.synthesizer import enumerate_circuits
modules = load_modules("my_modules.yaml")
topologies = load_topologies("my_topologies.yaml")
for circuit in enumerate_circuits(topologies[0], modules):
print(circuit.name)