(Separate ticket from the HFET1 one. Same pattern, different device.)
Two identical MESFETs, each biased by its own voltage sources. z1 has vds = -1 V, z2 has vds = +1 V. Order B is order A with the two Z lines swapped.
MESA level 2 instance-order test, order A
vd1 d1 0 dc -1
vd2 d2 0 dc 1
vg g 0 dc 0
z1 d1 g 0 mf l=1u w=20u
z2 d2 g 0 mf l=1u w=20u
.model mf nmf level=2 vto=-0.5 rd=20 rs=20
.control
op
print i(vd1) i(vd2)
.endc
.end
The level 3 and level 4 decks are the same with level=3 / level=4.
Expected: both orders give the same currents, equal to each device run alone.
Actual (ngspice -b), i(vd2):
| level | z2 alone | order A (z1 line first) | order B (z2 line first) |
|---|---|---|---|
| 2 | -4.59625e-04 | -4.59625e-04 | -5.06804e-09 |
| 3 | -2.39344e-03 | -2.39344e-03 | -2.13166e-08 |
| 4 | -5.81874e-04 | -5.81874e-04 | -4.89680e-09 |
i(vd1) is unaffected (2.551233e-02, 2.567796e-02, 2.551190e-02 for levels 2/3/4, in every case). In order B, z2 is evaluated with vgd = -1 V in place of vgs = 0 V, so it is wrongly cut off and its current falls by five orders of magnitude.
src/spicelib/devices/mesa/mesaload.c, MESAload():
int inverse = FALSE; is set once per call, outside the model and instance loops.if(vds < 0) { vds = -vds; inverse = TRUE; }inverse?vgd:vgs.if(inverse) { cdrain = -cdrain; vds = -vds; SWAP(capgs, capgd) }Nothing resets inverse inside the instance loop. Once one instance with vds < 0 has been loaded, every instance loaded after it in the same MESAload call (also instances of later models) uses vgd instead of vgs, has its drain current negated and gets Cgs/Cgd swapped. The result therefore depends on instance order. This is the same defect as in HFETAload (hfet1/hfetload.c), reported separately as bug #877.
Reset the flag per instance (patch against 3ef069f attached, mesaload-inverse.patch):
--- a/src/spicelib/devices/mesa/mesaload.c
+++ b/src/spicelib/devices/mesa/mesaload.c
@@ -87,7 +87,7 @@ MESAload(GENmodel *inModel, CKTcircuit *ckt)
double vts;
double von;
double ccorr;
- int inverse = FALSE;
+ int inverse;
int icheck;
int ichk1;
int error;
@@ -114,6 +114,7 @@ MESAload(GENmodel *inModel, CKTcircuit *ckt)
* initialization
*/
icheck = 1;
+ inverse = FALSE;
if( ckt->CKTmode & MODEINITSMSIG) {
vgs = *(ckt->CKTstate0 + here->MESAvgs);
vgd = *(ckt->CKTstate0 + here->MESAvgd);
With the patch, both orders give the single-device values at all three levels: i(vd2) = -4.59625e-04 (level 2), -2.39344e-03 (level 3), -5.81874e-04 (level 4).
Shipped tests: no reference output in tests/mesa changes. Unpatched and patched master give byte-identical batch output for mesa.cir, mesa11, mesa13, mesa14, mesa15, mesa21, mesgout, mesinv and mesosc. In mesosc and mesinv no instance ever reaches vds < 0. mesa12.cir and mesa-12.cir have a single MESA instance, so they cannot be affected (both ran past a 20 s limit with either binary).
The bug was found and analysed with AI assistance. It was confirmed by building ngspice master and running it unpatched and patched on the decks above.
Related: bug #877 (same defect in HFETAload).
Diff:
Fix on git branch pre-master-48