Menu ▾ ▴

#878 MESA (NMF/PMF, levels 2-4): drain current of an instance depends on netlist order; `inverse` flag in MESAload is never reset

v1.0 (example)
open-fixed
None
5
2026-10-12
2026-10-12
No

(Separate ticket from the HFET1 one. Same pattern, different device.)

Version / platform

  • ngspice git master 3ef069fb1f04177a153f342a32d941fc20ff047e ("Fixes bug 876", 2026-10-09), reports itself as ngspice-47+
  • macOS 27.0.1 (arm64), Apple clang 21.0.0, bison 3.8.2
  • configure --with-x=no --disable-debug --enable-cider=no --enable-xspice=no --with-readline=no --disable-openmp

Input

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 vs actual

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.

Cause

src/spicelib/devices/mesa/mesaload.c, MESAload():

  • line 90: int inverse = FALSE; is set once per call, outside the model and instance loops.
  • lines 309-312: if(vds < 0) { vds = -vds; inverse = TRUE; }
  • lines 315-319: mesa1/mesa2/mesa3 are called with inverse?vgd:vgs.
  • lines 320-324: 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.

Fix

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).

Discussion

  • Holger Vogt

    Holger Vogt - 2026-10-12
    • Description has changed:

    Diff:

    
    
    • status: --> open-accepted
    • assigned_to: Holger Vogt
    • Group: --> v1.0 (example)
    • Priority: --> 5
     
  • Holger Vogt

    Holger Vogt - 2026-10-12
    • status: open-accepted --> open-fixed
     
  • Holger Vogt

    Holger Vogt - 2026-10-12

    Fix on git branch pre-master-48

     

Log in to post a comment.