Functional Block Recognizer¶
The Functional Block Recognizer (FBR) is the second half of the recognizer pipeline (Layer 2). It takes the — possibly overlapping — candidates reported by the Subcircuit Recognizer and assigns each recognized structure to its functional role, resolving ambiguity by connectivity scoring. It runs in two modes:
Topology mode (
assign_slots()) — with aTopologyTemplate, each template slot (input_pair,load, …) is assigned its best-matching SR candidate, recovering the synthesizer’svariant_mapshape.Topology-free mode (
group_by_category()) — without a template, structures are grouped bycircuit_blockandcategoryusing external-port adjacency as the disambiguation signal, for recognition of arbitrary netlists with unknown net names.
Together, SR + FBR support round-trip recognition of every topology template the synthesizer produces.
Deep dive: the recognizer walkthrough is a figure-rich tour of the recognizer code itself (see Code Walkthroughs).
Entry points¶
assign_slots()— topology-guided slot assignment.group_by_category()— topology-free grouping.
Functional block recognition (Layer 2)¶
FBR operates in two modes depending on whether a topology template is available.
Topology mode¶
assign_slots() takes
SR’s output plus a
TopologyTemplate and assigns each
Slot in topology.slots to its
best-matching SR candidate:
Filter SR’s candidates to those whose
categorymatches the slot’scategory.Score each remaining candidate by how many of its resolved
pinsagree withslot_connections()for that slot (the topology’s static{port: expected global net}wiring).Assign the highest-scoring candidate.
Connectivity scoring runs even for categories with only one slot, since SR may
report multiple overlapping candidates per category regardless of how many slots
need that category. The output,
FunctionalBlockRecognitionResult, is
shaped like variant_map ({slot_name: SlotAssignment}), plus any
unassigned candidate structures and unrecognized_devices passed through from
SR:
FunctionalBlockRecognitionResult(
slot_assignments={
"input_pair": SlotAssignment("input_pair", "differential_pair_pmos", ip_struct),
"load": SlotAssignment("load", "active_load_nmos", load_struct),
"tail_current": SlotAssignment("tail_current", "current_mirror_tail_pmos", tail_struct),
"bias_gen": SlotAssignment("bias_gen", "constructed_bias", bias_struct),
},
unassigned_structures=[...], # overlapping SR candidates that lost the scoring
unrecognized_devices=[], # empty on a clean round trip
)
Each SlotAssignment carries the slot name, the winning pattern’s name (equal
to the synthesized variant’s name on a correct round trip), and the
RecognizedStructure itself (the
*_struct placeholders above).
Topology-free mode¶
Without a template, FBR knows neither the circuit’s net names nor which structure
fills which role — it has only SR’s candidates, each tagged with a
circuit_block and a category. category says what kind of block a
structure is (input_pair, load, …); circuit_block says which part
of the op-amp it belongs to — the first stage (gain_stage_1), a later gain
stage (gain_stage_2), the bias network (bias), compensation
(compensation), CMFB (cmfb), or the output buffer
(output_stage_block). Both tags are authored statically on the SR pattern in
opamp_patterns.yaml (the input-pair/load/tail patterns carry
gain_stage_1, the second-stage patterns gain_stage_2) and copied onto
every match, so they are available with no template. Stage numbers beyond the
YAML tags — gain_stage_3 and up — aren’t authored; Pass 3 below derives them
by splitting a block that holds several stages.
group_by_category()
buckets the candidates circuit_block → category and ranks the candidates
in each category so the first one is the best guess. The ranking signal is
external-port adjacency — how many of a structure’s pins connect directly to
a subcircuit external port — which works because real functional blocks touch the
circuit’s I/O and bias ports in predictable ways.
That raw signal misranks a few cases, so three passes correct it before the result is returned.
Pass 1 — filter out spurious gain-stage matches. SR’s patterns overlap, so a
bias transistor or an input-pair device can be re-matched by a gain-stage
pattern. FBR drops any gain_stage_* candidate whose in or bias pin
lands on an external port — a real gain stage takes its input from an internal
net (the previous stage’s output), not from ibias or a signal input. In
single-category gain-stage blocks it additionally drops any candidate containing
an NMOS whose source isn’t gnd!, which marks a cascode intermediate device
rather than a rail-to-rail stage.
Example
A bias-reference NMOS is re-matched by the common_source pattern with its
gate (the in pin) on the external ibias port. A real gain stage’s
in is an internal net, so the candidate is dropped.
Pass 2 — rank the multi-category block (gain_stage_1). gain_stage_1 holds
three categories at once — input_pair, load, tail_current — and here
the raw external-port score is inverted: bias devices gate on ibias and sit
on the supply rails, so they outscore the real functional devices. FBR corrects
this in dependency order:
input_pair — ranked by the number of distinct external ports its
in1/in2touch. The true pair has both signal inputs on two distinct ports (score 2); a bias mirror hasin1 = in2 = ibias(score 1); a spurious stage pair has them on internal nets (score 0).load — candidates with
in1,in2, orbias1on an external port are dropped; among the rest, FBR prefers those whosein1/in2match the winning input pair’sout1/out2(following the signal chain).tail_current — candidates whose
outis an external port are dropped; among the rest, FBR prefers the one whoseoutmatches the input pair’stailnet.
Example
A bias mirror pair (both gates on ibias) scores 1, while the true
differential pair (in1/in2 on two distinct signal ports) scores 2 — so
ranking by distinct external ports lifts the real pair above the bias mirror.
Pass 3 — split a block that holds several stages. A multi-stage op-amp lands
its gain stages in one single-category block. FBR splits a gain_stage_* block
that still has more than one candidate into consecutive gain_stage_N groups
ordered by ascending external-port adjacency, so the stage driving the external
output ends up in the highest-numbered group.
Example
A three-stage op-amp’s gain_stage_2 holds two common_source
candidates. The one whose out is an internal net stays gain_stage_2;
the one whose out reaches the external output port is promoted to
gain_stage_3.
The output,
CategoryGroupResult, is the
circuit_block → category → [candidates] mapping, best guess first in each
category.