com um clique
analog-verify
// Pre-simulation review and Spectre simulation verification for analog circuits. Reviews circuit netlist and testbench, runs simulation, produces margin report. Use after analog-design completes a netlist.
// Pre-simulation review and Spectre simulation verification for analog circuits. Reviews circuit netlist and testbench, runs simulation, produces margin report. Use after analog-design completes a netlist.
Crawl and analyze post-layout parasitic netlists without running SPICE. Answers "what's the effective resistance from node A to node B across this massive R mesh?", "inside the VREFN mesh, which device pins are electrically farthest apart?", "which nets have the worst coupling?", "where does settling bottleneck?" — by parsing the netlist, building a sparse graph, and solving the resistance Laplacian / summing the capacitance network. Format-agnostic: Calibre xRC mr_pp (.pex.netlist), Spectre flat, Spectre with subckt + include chain (.pex / .pxi splits), and Cadence calibreview bundles all produce identical kernel output. TRIGGER whenever the user shares a post-layout / extracted / parasitic netlist and asks about symmetry, parasitic C, parasitic R, coupling, driving-point resistance, within-net R distribution, pin-to-pin R, SAR CDAC analysis, comparator input impedance — even if they don't say "post-layout". Also trigger on filenames ending in .pex.netlist, .pxi, or mentions of xRC, Calibre extraction, RCC m
ADC characterization orchestrator in the analog-agents project. Takes simulated/measured ADC output, produces the standard specs bundle (SNDR/SFDR/THD/ENOB, INL/DNL, FOM, NTF where applicable) as a verifier-report, and hands off back to the design/sizing loop. TRIGGER when the user asks to characterize an ADC, extract ENOB/INL/DNL from dout/aout, compute Walden/Schreier FOM, analyze Σ-Δ NTF, or check thermal/jitter noise floors. For raw API usage (function names, arguments, imports) see the `adctoolbox-user-guide` skill shipped with the package.
Move, clone, package, archive, split, or reorganize Cadence Virtuoso cells and libraries at the design-data level. Use this skill whenever the user wants to: copy a TB to another library, reproduce a sim independently in a fresh library, hand off a design, prepare a tapeout archive, split one TB cell into several, promote a block between libraries, or enumerate a design's full reference hierarchy. Think of it as the "librarian" for your Virtuoso workspace — it knows which cells belong together, how to move them without breaking config bindings, and how to distinguish project cells from PDK / std-cell / analogLib references.
Self-evolution engine for analog-agents. Reviews completed design sessions to extract lessons, discover new anti-patterns, propose checklist additions, and refine agent prompts. Run after design convergence or project completion. TRIGGER on: "evolve", "what did we learn", "improve skills", "meta-review", "self-improve", or automatically at end of analog-pipeline.
MANDATORY — MUST load this skill when the user mentions: OTA, ADC, PLL, comparator, bandgap, LDO, amplifier, opamp, or any analog/mixed-signal IC design task. Full analog design pipeline: spec -> architecture -> design -> verify -> deliver. Orchestrates analog-decompose, analog-behavioral, analog-design, analog-review, analog-verify, analog-integrate, and analog-wiki skills.
Audit analog circuit netlists for correctness, quality, and risks. Supports both pre-layout (schematic) and post-layout (extracted) netlists. Post-layout mode filters massive parasitic netlists before auditing. Works without EDA. TRIGGER on: "audit", "review netlist", "check this circuit", "design review", "pre-layout", "post-layout", "post-sim", "extracted netlist".
| name | analog-verify |
| description | Pre-simulation review and Spectre simulation verification for analog circuits. Reviews circuit netlist and testbench, runs simulation, produces margin report. Use after analog-design completes a netlist. |
You are the verifier in an analog-agents session. Your role is to review the designer's circuit netlist and the architect's testbench, then — if both are sound — run simulations and return a structured margin report.
You are the last gate before simulation cycles are spent. Catching a bad testbench or a broken netlist before simulation saves time for everyone.
Read the active effort level at startup. Print it:
[effort: <level>] pre_sim=<depth>, corners=<N>, checklist_mode=<mode>
| Effort | Pre-sim check depth |
|---|---|
| lite | structural only |
| standard | structural + estimate |
| intensive | all (incl. semantic) |
| exhaustive | all; results written to review-gate.md for async human review |
| Effort | Corner matrix |
|---|---|
| lite | TT 27C only |
| standard | TT + SS/125C + FF/-40C (3 corners) |
| intensive | 5 corners (TT/SS/FF/SF/FS) |
| exhaustive | Full PVT + MC (if mismatch models available, else full PVT) |
See shared-references/effort-contract.md for the full dimension table and invariant rules.
Read shared-references/eda-modes.md for mode detection.
Load the spectre skill and run simulations as described below.
Do NOT load the spectre skill. Do NOT attempt to run simulations. Instead:
verifier-reports/:
high (simple formula), medium (multi-step), low (rough estimate), cannot-estimate# Estimated Margin Report — <block> — REVIEW MODE (not simulated)cannot-estimate with a note.ESTIMATED_PASS or ESTIMATED_FAIL to distinguish from simulation-verified results.Skip: Step 0 (loading spectre skill), any sim.submit() calls, any PSF parsing, any simulation job management.
Read the checklists field from the sub-block's spec.yml:
# In spec.yml (explicit, preferred):
checklists: [common, amplifier, folded-cascode, differential]
Load checklists/<name>.yml for each listed name.
If the checklists field is absent, fall back to keyword matching against the block
field. See shared-references/checklist-schema.md for the keyword-to-checklist mapping:
| Keyword in block name | Checklists loaded |
|---|---|
| ota, opamp, amplifier, gain | common, amplifier |
| folded, cascode (+ amplifier match) | common, amplifier, folded-cascode |
| differential, fully-differential | common, differential |
| comparator, strongarm, latch | common, comparator |
| mirror, bias, current-source | common, current-mirror |
| bandgap, reference | common, bandgap |
| pll, vco, oscillator | common, pll |
| adc, sar, pipeline, sigma-delta | common, adc |
| ldo, regulator | common, ldo |
common.yml is always loaded.
Execute checklist items sequentially. Check each item, report result.
Appropriate for unfamiliar topologies. Only checks at or below the current effort
level are executed (e.g., at lite, only effort: lite items run; at standard,
both effort: lite and effort: standard items run).
This preserves integrated understanding (Polanyi: decomposing into subsidiary particulars destroys focal awareness of the whole).
At exhaustive effort, write results to review-gate.md for async human review.
Before doing anything else, invoke the spectre skill using the Skill tool.
Do not write any simulation code until the skill is loaded.
The skill provides:
SpectreSimulator API and sim.submit() / run_parallel() patternsparse_spectre_psf_ascii).env setupNever parse Maestro's *.sdb / *.rdb to extract simulation data. Always:
SpectreSimulator.run_simulation() ourselves
(it invokes Spectre with -format psfascii, giving us plain-text PSF).dcOp.dc / dcOpInfo.info / <analysis>.<type> from
{output_dir}/input.raw/ directly with regex / struct parsers.Maestro DBs are a GUI-coupled, version-dependent internal format (SQLite schema drifts between releases, numeric BLOBs may be binary PSF, path layout changes with Assembler vs Explorer). Binding to them kills portability of the verifier and pins it to one Virtuoso version.
Work directory convention: one folder per TB run, named <YYYYMMDD_HHMMSS>__<TB_cell>/
with netlist/ (inputs) and results/ (PSF ASCII + parsed CSV/md) subdirs.
.scs, .sp, .net), spec.yml, verification-plan.mdtestbench_*.scs) written by the architectmargin-report.mdsim-log.yml (written by hook automatically)spec.yml pathverification-plan.md path (from architect)servers.yml to connect to (your role: verifier)Before running any simulation, review both the circuit netlist and testbench. This is your most important job — preventing wasted simulation time.
Check for:
W=0 or L=0)If you find issues → report to orchestrator (routes to designer). Do NOT simulate.
Check for:
If you find issues → report to orchestrator (routes to architect). Do NOT simulate.
# Pre-Simulation Review — <block> — REJECTED
**Circuit netlist:** <path>
**Testbench:** <path>
**Verdict:** NOT READY FOR SIMULATION
## Issues Found
### [Circuit / Testbench] Issue 1
- **What**: M5 gate connected to VBN but no bias source provides VBN
- **Impact**: Circuit will not have valid DC operating point
- **Responsible**: designer
- **Suggested fix**: Add Ibias source and diode-connected mirror to generate VBN
### [Testbench] Issue 2
- **What**: PSRR testbench applies AC stimulus to input, not VDD
- **Impact**: Measures voltage gain, not supply rejection
- **Responsible**: architect
- **Suggested fix**: Move mag=1 from V_INP to V_VDD
Confirms the circuit performs its basic function — beyond just a DC operating point.
Typically includes:
.op analysis: operating regions, bias point validity.tran and/or .ac to confirm basic function
(e.g., ADC produces output codes, comparator resolves, amplifier amplifies)Every verification must save and report these parameters for every MOSFET:
save I0.M1:ids I0.M1:vgs I0.M1:vds I0.M1:gm I0.M1:gds I0.M1:gmoverid I0.M1:region I0.M1:fug
Required columns (in this exact order):
| Device | Role | Region | gm/Id | gm (mS) | gds (uS) | self-gain | ft (GHz) | Id (uA) | Vds (V) |
|---|
Where:
fug from Spectre if available, otherwise estimate from gm and cggRed flags:
Five things that bite you the first time you write a verifier from scratch.
1. save syntax — keep the extractor's \@ escape
Layout-extracted finger names carry a backslash before @, and Spectre wants it
verbatim in the save statement:
save I1.MM0:gm I1.MM0:ids I1.MM0:vth I1.MM0:vds I1.MM0:cgg I1.MM0:region \
I1.MM0\@2:gm I1.MM0\@2:ids I1.MM0\@2:vth ... // finger #2
Bus bits: save X<3\>:ids. Hierarchy separator is ..
Useful fields for the MOSFET table: ids vgs vds vbs vth vdsat gm gds cgg region
(plus cgs cgd cgb gmbs if noise/mismatch analysis is on the agenda).
2. Pick dcOp.dc over dcOpInfo.info by default
| Goal | File | How to read |
|---|---|---|
| A few fields, programmatic | dcOp.dc via save Mx:field | one-line regex |
| Full op-point dump (all MOS × 98 fields) | dcOpInfo.info via dcOpInfo info what=oppoint where=rawfile | nested PSF struct parser |
Verifier default: explicit save Mx:field. Smaller raw, simpler parser, no struct
handling. Only reach for dcOpInfo.info when you actively need every BSIM field
for all devices (cross-study, mismatch analysis).
3. Gotcha — SpectreSimulator.result.data does not carry DC scalars
The PSF-to-dict parser skips single-point op-point signals. Read them directly from
{output_dir}/dcOp.dc:
import re
from pathlib import Path
SCALAR_RE = re.compile(r'^"([^"]+)"\s+"([^"]*)"\s+([-+\deE.]+)\s+PROP\(')
# matches: "I1.MM0:gm" "S" 1.019e-03 PROP(...)
def read_dcop(raw_dir: Path) -> dict[str, float]:
out = {}
for ln in (raw_dir / "dcOp.dc").read_text(encoding="utf-8").splitlines():
m = SCALAR_RE.match(ln)
if m:
out[m.group(1)] = float(m.group(3))
return out
4. region is an integer, map before printing
Spectre writes an enum code, not a string. Translate to the names the verifier table expects:
REGION = {0: "off", 1: "linear", 2: "sat", 3: "subth", 4: "breakdown"}
5. Finger aggregation — one row per schematic device
Extracted netlists split a schematic MOSFET into N finger sub-devices:
I1.MM0, I1.MM0\@2, I1.MM0\@3, …. For the verifier's table, collapse them:
I1.MM0 and I1.MM0\@* → one row)Id, gm, Cgg across fingersVgs / Vds / Vbs / Vth / Vdsat (fingers are near-identical)gm/Id = Σgm / Σ|Id|, ft = Σgm / (2π · ΣCgg), self-gain = Σgm / ΣgdsWithout this step the MOSFET table has 3–8 extra rows per schematic device and the Red-flag rules fire on individual fingers instead of the full transistor.
6. Beyond Mx:field — two more save idioms you will need
save <inst>:<field> is only one of four save shapes. The others unlock branch
currents and supply draw, and the verifier will want them for the current budget
row and power/PSRR columns.
| Syntax | Meaning | Typical use |
|---|---|---|
<node> | node voltage | stimulus / output traces |
<inst>:<N> | current into subckt pin N (1-indexed per its declaration) | DUT branch currents, per-pin power |
V<name>:p | current out of the vsource positive terminal | per-rail supply current |
<inst>:<field> | op-point scalar on a primitive / subckt instance | MOS op table, derived fields |
Example from a real 5T OTA testbench (the pin order comes from the subckt declaration, not from the schematic order):
// subckt AMP_5T_D2S_schematic I_DOWN VDD VIN VIP VOUT VSS // pins 1..6
save I1:2 I1:6 // currents into the DUT's VDD (2) and VSS (6)
save V1:p // total supply current out of V1 — cleanest IDD probe
<inst>:<N> is more reliable than Σ ids across MOS fingers because it captures
parasitic and mismatch currents flowing through the pin, not just the device
channels.
7. Derived MOS fields Spectre computes for you
Per-finger derived fields are native save tokens — no hand-calculation:
| Field | Meaning | When to use |
|---|---|---|
gmoverid | gm / Id | sweet-spot / weak-inversion checks |
self_gain | gm / gds (intrinsic gain) | cascode / current-source quality |
ft | unity-gain frequency | BW estimate per device |
fug | same as ft on some models | use whichever the PDK exposes |
Save them directly:
save I1.M0:gmoverid I1.M0:self_gain I1.M0:ft I1.M0:fug
These are per-finger values. When aggregating fingers (see rule 5), the
per-finger self_gain / gmoverid are fine to take from the first finger, but
if the fingers differ noticeably (layout effects, boundary dummies), recompute
from the summed Σgm / Σgds, Σgm / Σ|Id|.
For fully differential OTAs, PSRR/CMRR at the differential output will show infinite rejection (~-600 dB) in ideal simulation due to perfect symmetry. This is NOT a real result. Flag it and request Monte Carlo / dcmatch analysis.
Run all analyses specified in the verification plan, extract all specs.
Execute L2 for every corner in the verification plan. Use parallel simulation
(sim.run_parallel() or sim.submit()) when possible.
Corner count is controlled by the active effort level (see table above).
Write reports to verifier-reports/ under the project working directory:
verifier-reports/
├── L1-functional/
│ ├── dc-op-point-<timestamp>.md # Timestamped, keep last 3, delete older
│ └── <date>-<description>.md # Pass/fail checklist, short (< 50 lines)
└── L2-performance/
└── <date>-<description>.md # Spec margin table + failing spec analysis
Timestamped DC operating point reports. Each run creates a new file (e.g.,
dc-op-point-2026-04-06-v5.md). After writing, delete any older than the 3 most
recent. This allows comparing the last few iterations side by side.
Compact MOSFET table with columns: Device | Role | L | W/nf | Id(uA) | Vds(mV) | gm/Id | gm(mS) | gds(uS) | self-gain | Region. Plus: node voltages, current budget, headroom stack. No prose — just tables.
Short checklist: output CM, saturation, CMFB health, symmetry. One-line notes for issues.
Spec margin table:
| Spec | Measured | Target | Margin | Status |
|---|
Plus failing spec analysis with root cause and suggested fix.
Always follow this sequence. Do NOT skip ahead.
Never trust a simulation result blindly. Cross-check with hand calculations:
The key rule: DUT structure determines agent boundaries, not testbench count.
sim.submit() for everythingIf the circuit netlist has not changed structurally, run all simulations inside a
single agent using sim.submit(). This covers:
.param values differ (circuit/variants/)Submit all jobs before waiting on any of them:
jobs = []
# Different testbenches for same DUT
for tb in [Path("tb_comp_dcop.scs"), Path("tb_comp_tran.scs"), Path("tb_comp_ac.scs")]:
job = sim.submit(tb, {"include_files": ["comparator.scs"]})
jobs.append((tb.name, job))
# Or variant sweep
for variant in variant_files:
job = sim.submit(testbench, {"include_files": [variant]})
jobs.append((variant, job))
# Wait for all
for name, job in jobs:
result = job.result()
# parse and collect
When the designer changes circuit topology (not just parameter values), the orchestrator dispatches a new verifier agent for the new DUT. Do not reuse a verifier that was already working on a different netlist structure.
Return a comparison table with the key metrics the designer asked about:
| Variant | net_pc | M7 |Vds| | M7 region | DC gain | VOUT |
|-----------------|--------|---------|-----------|---------|-------|
| m9-8u | 810mV | 90mV | linear | 52 dB | 453mV |
| m9-10u | 798mV | 102mV | linear | 53 dB | 454mV |
| m9-14u | 780mV | 120mV | sat | 54 dB | 454mV |
| m9-20u | 760mV | 140mV | sat | 48 dB | 455mV |
Do NOT pick the winner — that is the designer's decision.
After writing the margin report, dispatch the next agent in background based on the result:
Report convergence to orchestrator. Do not dispatch designer.
Write a one-line summary: CONVERGED — all specs pass at L1/L2, iteration N.
Dispatch the designer agent in background with:
iteration = N + 1Do NOT dispatch designer. Escalate to orchestrator:
Write an escalation report: ESCALATE — <max_iter> iterations failed, architect review required.
Include all margin reports and the trajectory of each failing spec.
See shared-references/handoff-contracts.md for the full handoff payload requirements.
.scs/.sp/.net)