Version: pre-master-48 3adcd96a0. First bad commit: af240ba02, which adds the sweep, built on each side (parent 81f5b2c6d) with nothing else changed. Before it the same deck stops the dc with "not in the circuit" and the second op is untouched.
The sweep itself is a useful addition, and its rows are right here. The problem comes after it ends.
Expected: the op after the sweep equals the op before it.
3adcd96a0:
From reading the code, which I have not stepped through: the sweep saves the instance value, already scaled, and restores it through DCTsetInstParam() in dctrcurv.c, which calls DEVparam. mos1par.c multiplies a new w by scale there. The deck shows the result; the path is my reading.
A second point: the sweep does not rebin. With two cards split at w=3u, row w=5u gives -3.21578e-04 from a sweep starting at w=2u, and the same device written at w=5u gives -7.35168e-05. The two cards differ only in vth0, 0.4 and 0.7. The decks are attached.
I have not tested a fix, so I have no patch to offer.
I checked this with help from an AI coding assistant (Claude); I have reviewed the results.
Ananth
Hi Ananth,
I can reproduce the first point with your deck on current master (5156616b8): after the sweep @m1[w] reads 1e-12 and the second op gives i(vd) = -1.26010e-10 instead of -1.25000e-04. Without .option scale the deck is unchanged, as you reported.
Your reading of the path is right. In dctrcurv.c the save for a PARAM_CODE sweep variable goes through DEVask, which returns the instance value already multiplied by scale (TRCVvSave, around line 230). At the end of the sweep DCTsetInstParam() hands that saved value back to DEVparam (around line 616), and mos1par.c applies scale again on MOS1_W; same for L, AD, AS, PD, PS on every MOS level that scales geometry.
Attached is a patch against master. After DCTsetInstParam(start) it reads the value back with DEVask: the ratio asked/start is the effective scale factor of that parameter (1 for an unscaled parameter, scale for geometry), and TRCVvSave is divided by it so the final restore lands on the original value. It is generic, no per-device parameter list. The factor is left at 1 when start or the read-back value is 0, so a sweep starting exactly at 0 is not covered. It adds tests/regression/dcsweep-param-scale/ (w, l and @r1[resistance]), which fails on the unpatched binary and passes with the patch. make check: 62 PASS, 0 FAIL. With the patch your deck gives @m1[w] = 1e-06 and i(vd) = -1.25000e-04 after the sweep.
I left the second point (rebinning during the sweep) alone; happy to look at it separately if useful.
I used an AI coding assistant for part of the analysis and the patch; I reviewed and tested everything before posting.
Clement Saillant