Fix Ocean SKILL simulation failures after schematic edits. Use when: (1) run() returns nil in <1s with no spectre.out, (2) createNetlist() returns nil, (3) sim results are all nil after changing W/L to design variables, (4) netlist file was deleted or is stale, (5) sim run previously worked but now fails after calling `sim setup` again, (6) OSSHNL-109 error after SKILL edit, (7) library not found / ddGetObj returns nil / Virtuoso started from wrong directory. Covers: the resultsDir binding trap (MOST COMMON), OSSHNL-109 extraction timestamp stale error, stale netlists, sim setup disrupting sessions, direct spectre invocation as bypass, library-not-registered diagnosis, and PSF signal naming.
Ocean's run() silently returns nil. All measurement results are nil. Spectre
never runs. No error is reported.
run() completes quickly and returns nil instead of the resultsDir pathspectre.out or stale one in psf directorycreateNetlist(?recreateAll t) returns nilsim setup or changed resultsDir to a different pathThe ADE session binds run() to the resultsDir that was active when the session
was first established from the GUI. Changing it to ANY other path causes run()
to silently return nil.
; ✅ Works — same path as ADE session
resultsDir("/tmp/opt_5t_ota")
run() ; → "/tmp/opt_5t_ota"
; ❌ Breaks run() — different path
resultsDir("/tmp/new_dir")
run() ; → nil (silent failure!)
; ✅ Restore original path, run() works again
resultsDir("/tmp/opt_5t_ota")
run() ; → "/tmp/opt_5t_ota"
Find the canonical resultsDir from the runSimulation script:
cat <netlist_dir>/runSimulation | grep "\-raw"
# → -raw ../../../../../../../../tmp/opt_5t_ota/psf
# Canonical path = /tmp/opt_5t_ota
Fix in virtuoso-cli: sim run no longer auto-sets resultsDir to a temp dir
(that was overriding the ADE session path). If resultsDir is nil, sim run now
returns a clear error message.
Calling virtuoso sim setup sends design("lib" "cell" "view") which can reset
the Ocean session state. After this, run() returns nil.
Symptom: run() worked → called sim setup → run() now returns nil.
Fix: Don't call sim setup again if a working session exists. Check:
virtuoso skill exec 'asiGetSession(hiGetCurrentWindow())'
# → stdobj@0x... means session is alive
Symptom: createNetlist returns nil. si.foregnd.log contains:
ERROR (OSSHNL-109): The cellview '…/schematic' has been modified since the last extraction.
Run Check and Save.
artSimEnvLog shows: generate netlist... ...unsuccessful.
Root cause: dbSave(cv) writes the OA file but does NOT update the extraction
timestamp. schCheck(cv) is what updates it. Calling dbSave without schCheck
leaves the timestamp stale; the next incremental createNetlist sees a mismatch.
Fix: Run schCheck(cv) before dbSave(cv). Or use vcli sim netlist — it
auto-recovers by running schCheck + dbSave and retrying when createNetlist returns nil.
# vcli handles OSSHNL-109 automatically (v0.1.7+)
vcli sim netlist --lib FT0001A_SH --cell ota5t
Manual fix in SKILL:
; Get the cv (3-arg form opens "a" mode in IC23; fallback for Ocean-held cv)
cv = dbOpenCellViewByType("lib" "cell" "view")
unless(cv
cv = car(setof(ocv dbGetOpenCellViews()
and(ocv~>libName=="lib" ocv~>cellName=="cell" ocv~>mode=="a"))))
chk = schCheck(cv)
when(car(chk)==0 dbSave(cv)) ; only save if no check errors
Also note: dbReplaceProp(inst "w" ...) sets the display parameter, NOT the
netlisted simW. For SMIC PDK n12/p12 width changes, use:
cdfFindParamByName(cdfGetInstCDF(inst) "simW")~>value = "1.3u"
After editing a schematic (e.g., adding desVar variables), the netlist becomes stale.
createNetlist() requires an ADE L window open for that cell — without it, returns nil.
Symptom: vcli sim netlist returns an error like:
Library 'FT0001A_SH' is not registered in the current Virtuoso session.
Virtuoso was started from '/home/meow/git/virtuoso-cli'.
Or ddGetObj("FT0001A_SH") returns nil from the bridge.
Root cause: Virtuoso was started from a directory that has no cds.lib including
the target library. The DD database is populated at startup from cds.lib files found
via CDSHOME, site, and user paths — but NOT automatically from arbitrary directories.
Diagnosis: Check Virtuoso's working directory in CDS.log:
grep "Working Directory" ~/CDS.log
# Expected: meowu:/home/meow/projects/ft0001
# Wrong: meowu:/home/meow/git/virtuoso-cli
Fix: Start Virtuoso from the project directory:
cd /home/meow/projects/ft0001 && virtuoso &
Distinguish from OSSHNL-109 (both produce err_count == -1 in vcli):
; Returns "found" if library is registered, nil if not
when(car(setof(l ddGetLibList() l~>name=="FT0001A_SH")) "found")
vcli v0.1.7+ runs this probe automatically and returns an actionable error message.
# Regenerate netlist — auto-recovers from OSSHNL-109 via schCheck+dbSave retry
vcli sim netlist --lib <lib> --cell <cell>
vcli sim netlist --lib <lib> --cell <cell> --recreate # force full recreation
virtuoso skill exec 'resultsDir("/tmp/opt_5t_ota")'
virtuoso sim run --analysis dc --timeout 60
⚠️ Run from the schematic/ directory, NOT from netlist/ — relative paths inside
the netlist resolve from schematic/. Running from netlist/ causes CMI-2011 (cannot open input file).
SCHEMATIC_DIR="/path/to/simulation/cell/spectre/schematic"
PSF_DIR="/tmp/my_results/psf"
mkdir -p "$PSF_DIR"
cd "$SCHEMATIC_DIR" && spectre netlist/input.scs \
+escchars \
+log "$PSF_DIR/spectre.out" \
-format psfxl -raw "$PSF_DIR" \
+mt -maxw 5 -maxn 5
Then read results:
virtuoso skill exec 'openResults("/tmp/my_results/psf")'
virtuoso sim measure --analysis dcOp \
--expr 'getData("I0.NM0:gm" ?result "dcOpInfo")'
Advantages: ~200–300ms, no ADE session dependency, works even when Ocean is broken.
The ADE-generated input.scs may only have DC. Add AC without opening ADE:
sed -i 's/^dcOpInfo info what=oppoint where=rawfile$/dcOpInfo info what=oppoint where=rawfile\nacSweep ac start=1 stop=10G dec=20 annotate=status/' input.scs
input.scs is updated, then virtuoso sim run works againInstances inside a subcircuit instantiated as I0 in the testbench:
| Context | Correct | Wrong |
|---|---|---|
| Device oppoint | getData("I0.NM0:gm" ?result "dcOpInfo") | getData("/NM0:gm") |
| Node voltage (AC) | VF("net1") or VF("VOUT") | VF("/VOUT") |
| DC node voltage | VDC("net1") | — |
Find actual signal names:
strings /tmp/results/psf/acSweep.ac | grep "^I0\."
Or in SKILL: openResults("/psf/path") selectResult('acSweep) VF("net1")
— if it returns srrWave:0x..., the signal name is correct.
grep "Working Directory" ~/CDS.log → is Virtuoso's CWD the project directory?ddGetLibList() from bridge → does it include the target library?cat runSimulation | grep -raw → what is the canonical resultsDir?resultsDir() → does it match the canonical path?run() → returns path (OK) or nil (broken)?.dc/.ac files → simulation produced datasimRunData, artistLogFile, variables_file → simulation failedcat <netlist_dir>/si.foregnd.log → contains OSSHNL-109? → use vcli sim netlist to auto-fix<project>/simulation/<cell>/spectre/schematic/netlist/
├── input.scs # Top-level: parameters, model includes, analyses
├── netlist # Subcircuit from schematic
├── runSimulation # Actual spectre command ADE uses (shows original PSF path)
└── netlistFooter # Testbench instances and stimuli
design("lib" "cell" "view") returns nil when no ADE window is open for that cellsim setup should only be called once per ADE sessionsystem("find / ...") hangs the SKILL daemon — blocked by virtuoso-cli bridgeSee also: SKILL bridge scoping rules in ~/.claude/projects/.../memory/feedback_skill_bridge_scoping.md