remove lib prefix from plugin name
[gnucap-felix.git] / apps / d_mos.model
blobec7330ee9ec3ff81321a2aca696c221de7c9c25c
1 /* $Id: d_mos.model $ -*- C++ -*-
2  * Copyright (C) 2001 Albert Davis
3  * Author: Albert Davis <aldavis@gnu.org>
4  *
5  * This file is part of "Gnucap", the Gnu Circuit Analysis Package
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *------------------------------------------------------------------
22  * data structures and defaults for mos model.
23  * internal units all mks (meters)
24  * but some user input parameters are in cm.
25  *
26  * netlist syntax:
27  * device:  mxxxx d g s b mname <device args> <model card args>
28  * model:   .model mname NMOS <args>
29  *      or  .model mname PMOS <args>
30  */
31 h_headers {
32 #include "d_diode.h"
34 cc_headers {
35 #include "u_limit.h"
36 #include "e_storag.h"
37 #include "d_mos_base.h"
39 /*--------------------------------------------------------------------------*/
40 device BUILT_IN_MOS {
41   parse_name mosfet;
42   model_type BUILT_IN_MOS_BASE;
43   id_letter M;
44   circuit {
45     sync;
46     ports {d g s b};
47     local_nodes {
48       id short_to=d short_if="!OPT::rstray || s->rd == 0.";
49       is short_to=s short_if="!OPT::rstray || s->rs == 0.";
50     }
51     args db BUILT_IN_DIODE {
52       area = double(s->ad);
53       perim = double(c->pd);
54       is_raw = double(s->idsat);
55       cj_raw = double(m->cbd);
56       cjsw_raw = NA;
57       off = true;
58       set_modelname(modelname());
59       attach(model());
60     }
61     args sb BUILT_IN_DIODE {
62       area = double(s->as);
63       perim = double(c->ps);
64       is_raw = double(s->issat);
65       cj_raw = double(m->cbs);
66       cjsw_raw = NA;
67       off = true;
68       set_modelname(modelname());
69       attach(model());
70     }
71     resistor Rs {s is} value="s->rs"
72       omit="!OPT::rstray || s->rs == 0.";
73     resistor Rd {d id} value="s->rd"
74       omit="!OPT::rstray || s->rd == 0.";
75     diode Ddb {b id} args="db" reverse="m->polarity==pP"
76       omit="_n[n_b].n_() == _n[n_d].n_() || s->idsat == 0.";
77     diode Dsb {b is} args="sb" reverse="m->polarity==pP"
78       omit="_n[n_b].n_() == _n[n_s].n_() || s->issat == 0.";
79     
80     capacitor Cgs {g is} value="s->cgso" eval=Cgs
81       omit="!OPT::cstray || _n[n_g].n_() == _n[n_s].n_()";
82     capacitor Cgd {g id} value="s->cgdo" eval=Cgd
83       omit="!OPT::cstray || _n[n_g].n_() == _n[n_d].n_()";
84     capacitor Cgb {g b} value="s->cgbo" eval=Cgb
85       omit="!OPT::cstray || _n[n_b].n_() == _n[n_g].n_()";
86     fpoly_cap Cqgs {g is g b is b id b}
87       state=qgs  // qgate, cgs, cggb, cgsb, cgdb
88       omit="m->cmodel != 0 || !OPT::cstray 
89                 || _n[n_g].n_() == _n[n_is].n_()";
90     fpoly_cap Cqgd {g id g b id b is b}
91       state=qgd  // qgate, cgs, cggb, cgsb, cgdb
92       omit="m->cmodel != 0 || !OPT::cstray 
93                 || _n[n_g].n_() == _n[n_id].n_()";
95     fpoly_cap Cqds {id is g b is b id b}
96       state=qdrn  // qdrn, cds, cdgb, cdsb, cddb
97       omit="m->cmodel != 0 || !OPT::cstray 
98              || _n[n_id].n_() == _n[n_is].n_()";
100     fpoly_cap Cqbs {b is g b is b id b}
101       state=qbs
102       omit="m->cmodel != 0 || !OPT::cstray 
103              || _n[n_b].n_() == _n[n_is].n_()";
105     fpoly_cap Cqbd {b id g b id b is b}
106       state=qbd
107       omit="m->cmodel != 0 || !OPT::cstray 
108              || _n[n_b].n_() == _n[n_id].n_()";
109     cpoly_g Ids {id is  g is  id g
110                 b is  id b} state=idsxxx;
111     cpoly_g Idb {id b  id is  g is  b is}
112       state=idbxxx 
113       omit="!(m->needs_isub) || _n[n_d].n_() == _n[n_b].n_()";
114     cpoly_g Isb {is b  is id  g id  b id}
115       state=isbxxx 
116       omit="!(m->needs_isub) || _n[n_s].n_() == _n[n_b].n_()";
117   }
118   tr_probe {
119     v   = "@n_d[V] - @n_s[V]";
120     vds = "@n_d[V] - @n_s[V]";
121     vgs = "@n_g[V] - @n_s[V]";
122     vbs = "@n_b[V] - @n_s[V]";
123     "vdsi{nt}" = "vds";
124     "vgsi{nt}" = "vgs";
125     "vbsi{nt}" = "vbs";
126     vgd = "@n_g[V] - @n_d[V]";
127     vbd = "@n_b[V] - @n_d[V]";
128     vsd = "@n_s[V] - @n_d[V]";
129     vdm = "(@n_d[V] - @n_s[V] + @n_d[V] - @n_d[V]) / 2.";
130     vgm = "(@n_g[V]  - @n_s[V] + @n_g[V]  - @n_d[V]) / 2.";
131     vbm = "(@n_b[V]  - @n_s[V] + @n_b[V]  - @n_d[V]) / 2.";
132     vsm = "(@n_s[V] - @n_s[V] + @n_s[V] - @n_d[V]) / 2.";
133     vdg = "@n_d[V] - @n_g[V]";
134     vbg = "@n_b[V] - @n_g[V]";
135     vsg = "@n_s[V] - @n_g[V]";
136     vdb = "@n_d[V] - @n_b[V]";
137     vgb = "@n_g[V] - @n_b[V]";
138     vsb = "@n_s[V] - @n_b[V]";
139     vd = "@n_d[V]";
140     vg = "@n_g[V]";
141     vb = "@n_b[V]";
142     vs = "@n_s[V]";
143     "i{d}" = "(_Rd) ? @Rd[I] : (@Ids[I] - @Cgd[I] - @Ddb[I] * m->polarity)";
144     is = "(_Rs) ? @Rs[I] : (-@Ids[I] - @Cgs[I] - @Dsb[I] * m->polarity)";
145     ig = "@Cgs[I] + @Cgd[I] + @Cgb[I]";
146     ib = "- @Ddb[I] * m->polarity - @Dsb[I] * m->polarity - @Cgb[I]";
147     ibd = "@Ddb[I]";
148     ibs = "@Dsb[I]";
149     "cgso{vl}" = "@Cgs[NV]";
150     "cgdo{vl}" = "@Cgd[NV]";
151     "cgbo{vl}" = "@Cgb[NV]";
152     cgst = "@Cgs[EV]";
153     cgdt = "@Cgd[EV]";
154     cgbt = "@Cgb[EV]";
155     "cgs{m}" = "@Cgs[EV] - @Cgs[NV]";
156     "cgd{m}" = "@Cgd[EV] - @Cgd[NV]";
157     "cgb{m}" = "@Cgb[EV] - @Cgb[NV]";
158     cbd = "@Ddb[Cap]";
159     cbs = "@Dsb[Cap]";
160     cgate = "s->cgate";
161     gm = "(reversed) ? gmr : gmf";
162     "gmb{s}" = "(reversed) ? gmbr : gmbf";
163     gbd = "@Ddb[G]";
164     gbs = "@Dsb[G]";
165     vth = "von * m->polarity";
166     ids = "m->polarity * ((reversed) ? -ids : ids)";
167     "idst{ray}" = "- @Cgd[I] + @Ddb[I] * m->polarity";
168     p ="@Rs[P] +@Rd[P] +@Ddb[P] +@Dsb[P] +@Cgs[P] +@Cgd[P] +@Cgb[P] +@Ids[P]";
169     pd="@Rs[PD]+@Rd[PD]+@Ddb[PD]+@Dsb[PD]+@Cgs[PD]+@Cgd[PD]+@Cgb[PD]+@Ids[PD]";
170     ps="@Rs[PS]+@Rd[PS]+@Ddb[PS]+@Dsb[PS]+@Cgs[PS]+@Cgd[PS]+@Cgb[PS]+@Ids[PS]";
171     REgion = "static_cast<double>((!cutoff) + (!subthreshold * 2) 
172         + (saturated * 4) + (sbfwd * 10) + ((vbs > vds) * 20)
173         + (punchthru * 40)) * ((reversed)? -1 : 1)";
174     SUBthreshold = "static_cast<double>(subthreshold)";
175     CUToff = "static_cast<double>(cutoff)";
176     SATurated= "static_cast<double>(saturated)";
177     TRIode = "static_cast<double>(!saturated && !subthreshold)";
178     SBFwd = "static_cast<double>(sbfwd)";
179     DBFwd = "static_cast<double>(vbs > vds)";
180     REVersed = "static_cast<double>(reversed)";
181     status = "static_cast<double>(converged() * 2)";
182   }
183   device {
184     calculated_parameters {
185       // ordinary drain current
186       double ids "" default=0.;
187       double idsxxx;
188       double gds "dids/dvds" default=0.;
189       double gmf "dids/dvgs" default=0.;
190       double gmr "dids/dvgd" default=0.;
191       double gmbf "dids/dvbs" default=0.;
192       double gmbr "dids/dvbd" default=0.;
193       
194       // drain-bulk
195       double idb "" default=0.;
196       double idbxxx "" default=0.;
197       double gdbdb "placeholder" default=0.;
198       double gdbds "disub/dvds" default=0.;
199       double gdbgs "disub/dvgs" default=0.;
200       double gdbbs "disub/dvbs" default=0.;
201       
202       // source-bulk
203       double isb "" default=0.;
204       double isbxxx "" default=0.;
205       double gsbsb "placeholder" default=0.;
206       double gsbsd "disub/dvds" default=0.;
207       double gsbgd "disub/dvgs" default=0.;
208       double gsbbd "disub/dvbs" default=0.;
209       
210       // charge
211       double qgate "raw" default=0.;
212       double cgs  "dqgate_vgs placeholder" default=0.;
213       double cggb "dqgate_vgb" default=0.;
214       double cgsb "dqgate_vsb" default=0.;
215       double cgdb "dqgate_vdb" default=0.;
216       
217       double qgs "forward mode" default=0.;
218       double cgsgs "dqgs_vgs placeholder" default=0.;
219       double cgsgb "dqgs_vgb" default=0.;
220       double cgssb "dqgs_vsb" default=0.;
221       double cgsdb "dqgs_vdb" default=0.;
222       
223       double qgd "reverse mode" default=0.;
224       double cgdgd "dqgd_vgs placeholder" default=0.;
225       double cgdgb "dqgd_vgb" default=0.;
226       double cgdsb "dqgd_vsb" default=0.;
227       double cgddb "dqgd_vdb" default=0.;
228       
230       double qdrn "Qds" default=0.;
231       double cdsds "dqds_vds placeholder" default=0.;
232       double cdgb "dqds_vgb" default=0.;
233       double cdsb "dqds_vsb" default=0.;
234       double cddb "dqds_vdb" default=0.;
236       
237       double qbulk "raw" default=0.;
238       double cbs "dqbs_vbs placeholder" default=0.;
239       double cbgb "dqbs_vbg" default=0.;
240       double cbsb "dqbs_vsb" default=0.;
241       double cbdb "dqbs_vdb" default=0.;
242       
243       double qbs "Qbs forward" default=0.;
244       double cbsbs "dqbs_vbs placeholder" default=0.;
245       double cbsgb "dqbs_vbg" default=0.;
246       double cbssb "dqbs_vsb" default=0.;
247       double cbsdb "dqbs_vdb" default=0.;
248       
249       double qbd "Qbd reverse" default=0.;
250       double cbdbd "dqbd_vbd placeholder" default=0.;
251       double cbdgb "dqbd_vbg" default=0.;
252       double cbdsb "dqbd_vsb" default=0.;
253       double cbddb "dqbd_vdb" default=0.;
255       
256       double gtau "" default=0.;
257       double cqgb "" default=0.;
258       double cqsb "" default=0.;
259       double cqdb "" default=0.;
260       double cqbb "" default=0.;
261       /*      
262       double tconst "" default=0.;
263       double cgb "placeholder" default=0.; // capacitors and charges
264       double qgb "placeholder" default=0.;
265       double qgd "" default=0.;
266       double cgd "" default=0.;
267       double qgs "" default=0.;
268       //double cgs "" default=0.;
269       */
270       double vgs "terminal voltages" default=0.;
271       double vds "" default=0.;
272       double vbs "" default=0.;
273       
274       double vdsat "saturation voltage" default=0.;
275       double vgst "vgs - von." default=0.;
276       double von "actual threshold voltage" default=0.;
277       bool   reversed "flag: Vgs < 0, reverse s & d" default=false;
278       bool   cutoff "flag: in cut off region" default=false;
279       bool   subthreshold "flag: subthreshold region" default=false;
280       bool   saturated "flag: in saturation region" default=false;
281       bool   sbfwd "flag: sb diode fwd biased" default=false;
282       bool   punchthru "flag: punch thru region" default=false;
283     }
284   }
285   common {
286     raw_parameters {
287       double l_in "drawn (optical) channel length"
288         name=L positive default="OPT::defl";
289       double w_in "channel width (drawn)" 
290         name=W positive default="OPT::defw";
291       double ad_in "drain area, drawn"
292         name=AD positive default="OPT::defad"
293         print_test="has_hard_value(ad_in)";
294       double as_in "source area, drawn" 
295         name=AS positive default="OPT::defas"
296         print_test="has_hard_value(as_in)";
297       double pd "drain perimeter" name=PD positive default=0.0
298         print_test="has_hard_value(pd)";
299       double ps "source perimeter" name=PS positive default=0.0
300         print_test="has_hard_value(ps)";
301       double nrd "drain # squares" name=NRD positive default=1.0
302         print_test="has_hard_value(nrd)";
303       double nrs "source # squares" name=NRS positive default=1.0
304         print_test="has_hard_value(nrs)";
305     }
306   }
307   tr_eval {
308     int foo=3;
309   }
310   /*--------------------------------------------------------------------*/
311   eval Cgb {
312     STORAGE* brh = prechecked_cast<STORAGE*>(d);
313     assert(brh);
315     double cap = brh->value();
317     if (m->cmodel != 0) {
318       if (p->vgst < - s->phi) {                 /* accumulation */
319         cap += s->cgate;
320       }else if (p->vgst < 0.) {                 /* depletion */
321         cap += s->cgate * (-p->vgst) / s->phi;
322       }else{                                    /* active, overlap only */
323       }
324     }
325     brh->_y[0].f1 = cap;
326     if (d->_sim->analysis_is_tran_dynamic()) {
327       cap = (brh->_y[0].f1 + brh->_y[1].f1) / 2;
328       brh->_y[0].f0 = (brh->_y[0].x - brh->_y[1].x) * cap + brh->_y[1].f0;
329     }else{
330       assert(d->_sim->analysis_is_static() || d->_sim->analysis_is_restore());
331       brh->_y[0].f0 = brh->_y[0].x * brh->_y[0].f1;
332     }
333     trace3(brh->long_label().c_str(), brh->_y[0].x, brh->_y[0].f0, brh->_y[0].f1);
334   }
335   /*--------------------------------------------------------------------*/
336   eval Cgd {
337     STORAGE* brh = prechecked_cast<STORAGE*>(d);
338     assert(brh);
340     double cap = 0;
341     if (m->cmodel != 0) {
342       assert(p->vdsat >= 0.);
343       assert(p->vds >= 0.);
344       double vbs    = (m->cmodel == 3) ? 0. : p->vbs;
345       double vdbsat = p->vdsat - vbs;
346       double vdb    = p->vds   - vbs;
347       double ddif   = 2. * vdbsat - vdb;
348       
349       if (!p->reversed) { // treat as Cgs
350         if (p->vgst >= 0.) {
351           if (p->vdsat > p->vds) {              /* linear */
352             cap = (2./3.) * s->cgate * (1. - (vdbsat*vdbsat)/(ddif*ddif));
353             if (p->vgst <= .1) {
354               cap *= 10. * p->vgst;     // smooth discontinuity
355             }
356           }
357         }
358       }else{ // treat as Cgs
359         if (p->vgst >= -s->phi/2.) {            /* depletion  or active */
360           cap = (2./3.) * s->cgate;
361           if (p->vdsat > p->vds) {                      /* linear */
362             double ndif   = p->vdsat - p->vds;
363             cap *= 1. - (ndif*ndif)/(ddif*ddif);
364           }
365           if (p->vgst <= 0) {
366             cap *= 1. + p->vgst / (s->phi);
367             cap *= 1. + p->vgst / (s->phi);
368           }
369         }
370       }
371     }
372     cap += brh->value();                /* else overlap only */
373     
374     brh->_y[0].f1 = cap;
375     if (d->_sim->analysis_is_tran_dynamic()) {
376       cap = (brh->_y[0].f1 + brh->_y[1].f1) / 2;
377       brh->_y[0].f0 = (brh->_y[0].x - brh->_y[1].x) * cap + brh->_y[1].f0;
378     }else{
379       assert(d->_sim->analysis_is_static() || d->_sim->analysis_is_restore());
380       brh->_y[0].f0 = brh->_y[0].x * brh->_y[0].f1;
381     }
382     trace3(brh->long_label().c_str(), brh->_y[0].x, brh->_y[0].f0, brh->_y[0].f1);
383   }
384   /*--------------------------------------------------------------------*/
385   eval Cgs {
386     STORAGE* brh = prechecked_cast<STORAGE*>(d);
387     assert(brh);
389     double cap = 0;
390     if (m->cmodel != 0) {
391       assert(p->vdsat >= 0.);
392       assert(p->vds >= 0.);
393       double vbs    = (m->cmodel == 3) ? 0. : p->vbs;
394       double vdbsat = p->vdsat - vbs;
395       double vdb    = p->vds   - vbs;
396       double ddif   = 2. * vdbsat - vdb;
397       
398       if (p->reversed) { // treat as Cgd
399         if (p->vgst >= 0.) {
400           if (p->vdsat > p->vds) {              /* linear */
401             cap = (2./3.) * s->cgate * (1. - (vdbsat*vdbsat)/(ddif*ddif));
402             if (p->vgst <= .1) {
403               cap *= 10. * p->vgst;     // smooth discontinuity
404             }
405           }
406         }
407       }else{ // treat as Cgs
408         if (p->vgst >= -s->phi/2.) {            /* depletion  or active */
409           cap = (2./3.) * s->cgate;
410           if (p->vdsat > p->vds) {                      /* linear */
411             double ndif   = p->vdsat - p->vds;
412             cap *= 1. - (ndif*ndif)/(ddif*ddif);
413           }
414           if (p->vgst <= 0) {
415             cap *= 1. + p->vgst / (s->phi);
416             cap *= 1. + p->vgst / (s->phi);
417           }
418         }
419       }
420     }
421     cap += brh->value();                /* else overlap only */
422     
423     brh->_y[0].f1 = cap;
424     if (d->_sim->analysis_is_tran_dynamic()) {
425       cap = (brh->_y[0].f1 + brh->_y[1].f1) / 2;
426       brh->_y[0].f0 = (brh->_y[0].x - brh->_y[1].x) * cap + brh->_y[1].f0;
427     }else{
428       assert(d->_sim->analysis_is_static() || d->_sim->analysis_is_restore());
429       brh->_y[0].f0 = brh->_y[0].x * brh->_y[0].f1;
430     }
431     trace3(brh->long_label().c_str(), brh->_y[0].x, brh->_y[0].f0, brh->_y[0].f1);
432   }
433   /*--------------------------------------------------------------------*/
434   function reverse_if_needed() {
435     if (vds < 0) {
436       error(bTRACE, long_label() + ": reversing\n");
437       error(bTRACE, "before: vds=%g vgs=%g vbs=%g\n", vds, vgs, vbs);
438       reversed = !reversed;
439       vgs -= vds;
440       vbs -= vds;
441       vds = -vds;
442       error(bTRACE, "after: vds=%g vgs=%g vbs=%g\n", vds, vgs, vbs);
443       if (OPT::dampstrategy & dsREVERSE) {
444         _sim->_fulldamp = true;
445         untested();
446         error(bTRACE, long_label() + ":reverse damp\n");
447       }
448       if (!(OPT::mosflags & 0040)) {
449         vbs = std::min(vbs,0.);
450       }else{
451         untested();
452       }
453     }
454   }
455   /*--------------------------------------------------------------------*/
457 /*--------------------------------------------------------------------------*/
458 cc_direct {
459 /*--------------------------------------------------------------------------*/
460 bool DEV_BUILT_IN_MOS::tr_needs_eval()const
462   if (is_q_for_eval()) {
463     untested();
464     return false;
465   }else if (!converged()) {
466     return true;
467   }else{
468     const COMMON_BUILT_IN_MOS* c = prechecked_cast<const COMMON_BUILT_IN_MOS*>(common());
469     assert(c);
470     const MODEL_BUILT_IN_MOS_BASE* m=prechecked_cast<const MODEL_BUILT_IN_MOS_BASE*>(c->model());
471     assert(m);
472     polarity_t polarity = m->polarity;
473     node_t& eff_s((reversed) ? _n[n_id] : _n[n_is]);
474     node_t& eff_d((reversed) ? _n[n_is] : _n[n_id]);
475     return !(conchk(vds,polarity*(eff_d.v0()-eff_s.v0()),OPT::vntol)
476              && conchk(vgs, polarity*(_n[n_g].v0()-eff_s.v0()),
477                        OPT::vntol)
478              && conchk(vbs, polarity*(_n[n_b].v0()-eff_s.v0()),
479                        OPT::vntol));
480   }
482 /*--------------------------------------------------------------------------*/
483 bool DEV_BUILT_IN_MOS::do_tr()
485   const COMMON_BUILT_IN_MOS* c = prechecked_cast<const COMMON_BUILT_IN_MOS*>(common());
486   assert(c);
487   const MODEL_BUILT_IN_MOS_BASE* m = prechecked_cast<const MODEL_BUILT_IN_MOS_BASE*>(c->model());
488   assert(m);
490   bool was_cutoff = cutoff;
491   bool was_subthreshold = subthreshold;
492   bool was_saturated = saturated;
493   bool was_reversed = reversed;
494   bool was_sbfwd = sbfwd;
495   polarity_t polarity = m->polarity;
497   if (_sim->is_initial_step()) {
498     reversed = false;
499     vds = vgs = vbs = 0.;
500   }else{
501     double Vds, Vgs, Vbs;
502     if (reversed) {
503       Vds = polarity * volts_limited(_n[n_is],_n[n_id]);
504       Vgs = polarity * volts_limited(_n[n_g],_n[n_id]);
505       Vbs = polarity * volts_limited(_n[n_b],_n[n_id]);
506     }else{
507       Vds = polarity * volts_limited(_n[n_id],_n[n_is]);
508       Vgs = polarity * volts_limited(_n[n_g],_n[n_is]);
509       Vbs = polarity * volts_limited(_n[n_b],_n[n_is]);
510     }
511     vgs = fet_limit_vgs(Vgs, vgs, von);
512     if (_n[n_d].n_() == _n[n_g].n_()) {
513       vds = Vds + (vgs - Vgs);
514     }else{
515       // Spice hacks Vds here, but my tests show that it often makes
516       // convergence worse, and never improves it.
517       // I am guessing that it does help when drain and gate are connected,
518       // and Spice does it here in case they are and cannot be determined
519       // whether they are or not.
520       // The hack maintains Vdg after Vgs limiting.
521       //Vds = Vds + (vgs - Vgs);
522       vds = fet_limit_vds(Vds, vds);
523     }
524     vbs = std::min(Vbs, 0.);
525     //vbs = pnj_limit(double Vbs, double vbs, double vt, double vcrit);
526     //vds = Vds;
527     //vgs = Vgs;
528     //vbs = Vbs;
529   }
531   assert(qgate == qgate);
532   assert(qgs == qgs);
533   assert(qgd == qgd);
534   assert(qdrn == qdrn);
535   assert(qbulk == qbulk);
536   assert(qbs == qbs);
537   assert(qbd == qbd);
539   m->tr_eval(this);
541   assert(qgate == qgate);
542   assert(qgs == qgs);
543   assert(qgd == qgd);
544   assert(qdrn == qdrn);
545   assert(qbulk == qbulk);
546   assert(qbs == qbs);
547   assert(qbd == qbd);
549   if (reversed) {
550     idsxxx = ids + vds*gds + vgs*gmr + vbs*gmbr;
551     isbxxx = isb - vds*gsbsd - vgs*gsbgd - vbs*gsbbd;
552     idbxxx = 0.;
553   }else{
554     idsxxx = ids - vds*gds - vgs*gmf - vbs*gmbf;
555     idbxxx = idb - vds*gdbds - vgs*gdbgs - vbs*gdbbs;
556     isbxxx = 0.;
557   }
558   ids *= polarity;
559   idsxxx *= polarity;
560   assert(subckt());
561   set_converged(subckt()->do_tr());
562   
563   trace3(long_label().c_str(), vds, vgs, vbs);
564   trace4("", ids, gmf, gds, gmbf);
565   trace4("", ids, gmr, gds, gmbr);
566   if (was_cutoff != cutoff  ||  was_subthreshold != subthreshold  
567         ||  was_saturated != saturated  ||  was_reversed != reversed  
568         ||  was_sbfwd != sbfwd) {
569     if (OPT::dampstrategy & dsDEVREGION) {
570       _sim->_fulldamp = true;
571     }else{
572     }
573     #if defined(DO_TRACE)
574       error(bTRACE,"%s: region change\n", long_label().c_str());
575     #endif
576   }else{
577   }
578   return converged();
581 /*--------------------------------------------------------------------------*/
582 /*--------------------------------------------------------------------------*/