1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1988 Jaijeet S Roychowdhury
4 Modified: 2000 AlansFixes
5 **********/
6 
7 #include "ngspice/ngspice.h"
8 #include "ngspice/distodef.h"
9 #include "ngspice/devdefs.h"
10 #include "ngspice/cktdefs.h"
11 #include "mos2defs.h"
12 #include "ngspice/trandefs.h"
13 #include "ngspice/const.h"
14 #include "ngspice/sperror.h"
15 #include "ngspice/suffix.h"
16 
17 /* assuming silicon - make definition for epsilon of silicon */
18 #define EPSSIL (11.7 * 8.854214871e-12)
19 
20 static double sig1[4] = {1.0, -1.0, 1.0, -1.0};
21 static double sig2[4] = {1.0,  1.0,-1.0, -1.0};
22 
23 int
MOS2dSetup(GENmodel * inModel,CKTcircuit * ckt)24 MOS2dSetup(GENmodel *inModel, CKTcircuit *ckt)
25         /* actually load the current value into the
26          * sparse matrix previously provided
27          */
28 {
29     MOS2model *model = (MOS2model *)inModel;
30     MOS2instance *here;
31     double Beta;
32     double DrainSatCur;
33     double EffectiveLength;
34     double GateBulkOverlapCap;
35     double GateDrainOverlapCap;
36     double GateSourceOverlapCap;
37     double OxideCap;
38     double SourceSatCur;
39     double arg;
40     double cdrain;
41     double ebd;
42     double evbs;
43     double sarg;
44     double sargsw;
45     double vbd;
46     double vbs;
47     double vds;
48     double vdsat;
49     double vgb;
50     double vgd;
51     double vgs;
52     double von;
53     double vt;      /* K * T / Q */
54     double lcapgs2;
55     double lcapgd2;
56     double lcapgb2;
57     double lcapgs3;
58     double lcapgd3;
59     double lcapgb3;
60     double lgbs, lgbs2, lgbs3;
61     double lgbd, lgbd2, lgbd3;
62             double vgst;
63 	double lcapbs, lcapbs2, lcapbs3;
64 	double lcapbd, lcapbd2, lcapbd3;
65 	double gm2, gb2, gds2;
66 	double gmb, gmds, gbds;
67 	double gm3, gb3, gds3;
68 	double gm2b, gm2ds, gmb2, gmds2, gbds2, gb2ds;
69 	double gmbds;
70 		Dderivs d_cdrain;
71 	/*remove compiler warnings */
72 	d_cdrain.value = 0.0;
73 	d_cdrain.d1_p = 0.0;
74 	d_cdrain.d1_q = 0.0;
75 	d_cdrain.d1_r = 0.0;
76 	d_cdrain.d2_p2 = 0.0;
77 	d_cdrain.d2_q2 = 0.0;
78 	d_cdrain.d2_r2 = 0.0;
79 	d_cdrain.d2_pq = 0.0;
80 	d_cdrain.d2_qr = 0.0;
81 	d_cdrain.d2_pr = 0.0;
82 	d_cdrain.d3_p3 = 0.0;
83 	d_cdrain.d3_q3 = 0.0;
84 	d_cdrain.d3_r3 = 0.0;
85 	d_cdrain.d3_p2q = 0.0;
86 	d_cdrain.d3_p2r = 0.0;
87 	d_cdrain.d3_pq2 = 0.0;
88 	d_cdrain.d3_q2r = 0.0;
89 	d_cdrain.d3_pr2 = 0.0;
90 	d_cdrain.d3_qr2 = 0.0;
91 	d_cdrain.d3_pqr = 0.0;
92 
93     /*  loop through all the MOS2 device models */
94     for( ; model != NULL; model = MOS2nextModel(model)) {
95 
96         /* loop through all the instances of the model */
97         for (here = MOS2instances(model); here != NULL ;
98                 here=MOS2nextInstance(here)) {
99 
100             vt = CONSTKoverQ * here->MOS2temp;
101 
102             EffectiveLength=here->MOS2l - 2*model->MOS2latDiff;
103 
104              if( (here->MOS2tSatCurDens == 0) ||
105                     (here->MOS2drainArea == 0) ||
106                     (here->MOS2sourceArea == 0)) {
107                 DrainSatCur = here->MOS2m * here->MOS2tSatCur;
108                 SourceSatCur = here->MOS2m * here->MOS2tSatCur;
109             } else {
110                 DrainSatCur = here->MOS2tSatCurDens *
111                         here->MOS2m * here->MOS2drainArea;
112                 SourceSatCur = here->MOS2tSatCurDens *
113                         here->MOS2m * here->MOS2sourceArea;
114             }
115             GateSourceOverlapCap = model->MOS2gateSourceOverlapCapFactor *
116                     here->MOS2m * here->MOS2w;
117             GateDrainOverlapCap = model->MOS2gateDrainOverlapCapFactor *
118                     here->MOS2m * here->MOS2w;
119             GateBulkOverlapCap = model->MOS2gateBulkOverlapCapFactor *
120                     here->MOS2m * EffectiveLength;
121             Beta = here->MOS2tTransconductance * here->MOS2m *
122                     here->MOS2w/EffectiveLength;
123             OxideCap = model->MOS2oxideCapFactor * EffectiveLength *
124                     here->MOS2m * here->MOS2w;
125 
126 
127 
128 
129 
130                     /* general iteration */
131 
132 
133                     vbs = model->MOS2type * (
134                         *(ckt->CKTrhsOld+here->MOS2bNode) -
135                         *(ckt->CKTrhsOld+here->MOS2sNodePrime));
136                     vgs = model->MOS2type * (
137                         *(ckt->CKTrhsOld+here->MOS2gNode) -
138                         *(ckt->CKTrhsOld+here->MOS2sNodePrime));
139                     vds = model->MOS2type * (
140                         *(ckt->CKTrhsOld+here->MOS2dNodePrime) -
141                         *(ckt->CKTrhsOld+here->MOS2sNodePrime));
142 
143                 /* now some common crunching for some more useful quantities */
144 
145 
146                     vbd=vbs-vds;
147                     vgd=vgs-vds;
148 
149             /* now all the preliminaries are over - we can start doing the             * real work
150              */
151 
152             vgb = vgs - vbs;
153 
154             /* bulk-source and bulk-drain doides here we just evaluate
155              * the ideal diode current and the correspoinding
156              * derivative (conductance).  */
157 	    if(vbs <= 0) {
158                 lgbs = SourceSatCur/vt;
159                 lgbs += ckt->CKTgmin;
160 		lgbs2 = lgbs3 = 0;
161             } else {
162                 evbs = exp(MIN(MAX_EXP_ARG,vbs/vt));
163                 lgbs = SourceSatCur*evbs/vt + ckt->CKTgmin;
164 		lgbs2 = model->MOS2type *0.5 * (lgbs - ckt->CKTgmin)/vt;
165 		lgbs3 = model->MOS2type *lgbs2/(vt*3);
166 
167             }
168             if(vbd <= 0) {
169                 lgbd = DrainSatCur/vt;
170                 lgbd += ckt->CKTgmin;
171 		lgbd2 = lgbd3 = 0;
172             } else {
173                 ebd = exp(MIN(MAX_EXP_ARG,vbd/vt));
174                 lgbd = DrainSatCur*ebd/vt +ckt->CKTgmin;
175 		lgbd2 = model->MOS2type *0.5 * (lgbd - ckt->CKTgmin)/vt;
176 		lgbd3 = model->MOS2type *lgbd2/(vt*3);
177             }
178 
179             if(vds >= 0) {
180                 /* normal mode */
181                 here->MOS2mode = 1;
182             } else {
183                 /* inverse mode */
184                 here->MOS2mode = -1;
185             }
186             {
187             /* moseq2(vds,vbs,vgs,gm,gds,gmbs,qg,qc,qb,
188              *        cggb,cgdb,cgsb,cbgb,cbdb,cbsb)
189              */
190             /* note:  cgdb, cgsb, cbdb, cbsb never used */
191 
192             /*
193              *     this routine evaluates the drain current, its derivatives and             *     the charges associated with the gate, channel and bulk             *     for mosfets             *
194              */
195 
196             double arg1;
197             double sarg1;
198             double a4[4],b4[4],x4[8],poly4[8];
199             double beta1;
200             double sphi = 0.0;    /* square root of phi */
201             double sphi3 = 0.0;   /* square root of phi cubed */
202             double barg;
203             double factor;
204             double eta;
205             double vbin;
206             double argd = 0.0;
207             double args = 0.0;
208             double argss;
209             double argsd;
210             double argxs;
211             double argxd;
212             double gamasd;
213             double xwd;
214             double xws;
215             double gammad;
216             double cfs;
217             double cdonco;
218             double xn;
219             double argg = 0.0;
220             double sarg3;
221             double sbiarg;
222             double body;
223             double udenom;
224             double gammd2;
225             double argv;
226             double vgsx;
227             double ufact;
228             double ueff;
229             double a1;
230             double a3;
231             double a;
232             double b1;
233             double b3;
234             double b;
235             double c1;
236             double c;
237             double d1;
238             double fi;
239             double p0;
240             double p2;
241             double p3;
242             double p4;
243             double p;
244             double r3;
245             double r;
246             double ro;
247             double s2;
248             double s;
249             double v1;
250             double v2;
251             double xv;
252             double y3;
253             double delta4;
254             double xvalid = 0.0;
255             double bsarg = 0.0;
256             double bodys = 0.0;
257             double sargv;
258             double xlfact;
259             double xdv;
260             double xlv;
261             double xls;
262             double clfact;
263             double xleff;
264             double deltal;
265             double xwb;
266             double vdson;
267             double cdson;
268             double expg;
269             double xld;
270 	double xlamda = model->MOS2lambda;
271 	Dderivs d_xleff, d_delta1;
272 	Dderivs d_xlfact;
273 	Dderivs d_xlv, d_xls;
274 	Dderivs d_bsarg, d_bodys, d_vdsat, d_sargv;
275 	Dderivs d_delta4, d_a4[3], d_b4[3], d_x4[3], d_poly4[3];
276 	Dderivs d_xvalid;
277 	Dderivs d_ro, d_fi, d_y3, d_p3, d_p4, d_a3, d_b3;
278 	Dderivs d_r3, d_s2, d_pee, d_p0, d_p2;
279 	Dderivs d_b1, d_c1, d_d1, d_a, d_b, d_c, d_arr, d_s;
280 	Dderivs d_xv, d_a1;
281 	Dderivs d_v1, d_v2;
282 	Dderivs d_argv,d_gammd2;
283 	Dderivs d_ufact;
284 	Dderivs d_udenom;
285 	Dderivs d_sarg3, d_body;
286 	Dderivs d_vgst;
287 	Dderivs d_argg;
288 	Dderivs d_cdonco,d_tmp,d_xn;
289 	Dderivs d_dbargs,d_dbargd,d_dgddvb;
290 	Dderivs d_dbxwd,d_dbxws;
291 	Dderivs d_dsrgdb, d_dbrgdb;
292 	Dderivs d_gamasd, d_gammad, d_args, d_argd;
293 	Dderivs d_argxs, d_argxd;
294 	Dderivs d_argss, d_argsd;
295 	Dderivs d_xwd, d_xws;
296 	Dderivs d_zero;
297 	Dderivs d_vbin;
298 	Dderivs d_barg;
299 	Dderivs d_sarg;
300 	Dderivs d_phiMinVbs;
301     Dderivs d_p, d_q, d_r;
302     Dderivs d_von, d_dummy, d_vgsx, d_arg, d_dumarg;
303     Dderivs d_ueff, d_beta1, d_clfact, d_xlamda,d_mos2gds;
304     Dderivs d_vdson, d_cdson, d_expg;
305     double dsrgdb, dbrgdb, dbxwd, dbxws, dbargs = 0.0, dbargd = 0.0;
306     double dgddvb;
307 
308 
309 /* from now on, p=vgs, q=vbs, r=vds  */
310 
311 /*
312  * 'local' variables - these switch d & s around appropriately
313  * so that we don't have to worry about vds < 0
314  */
315 
316 	double lvbs = here->MOS2mode==1?vbs:vbd;
317 	double lvds = here->MOS2mode*vds;
318 	double lvgs = here->MOS2mode==1?vgs:vgd;
319 	double phiMinVbs = here->MOS2tPhi - lvbs;
320 	double tmp; /* a temporary variable, not used for more than */
321 		    /* about 10 lines at a time */
322 	int iknt;
323 	int jknt;
324 	int i;
325 	int j;
326 
327 	/*
328 	 *  compute some useful quantities
329          */
330 d_p.value = 0.0;
331 d_p.d1_p = 1.0;
332 d_p.d1_q = 0.0;
333 d_p.d1_r = 0.0;
334 d_p.d2_p2 = 0.0;
335 d_p.d2_q2 = 0.0;
336 d_p.d2_r2 = 0.0;
337 d_p.d2_pq = 0.0;
338 d_p.d2_qr = 0.0;
339 d_p.d2_pr = 0.0;
340 d_p.d3_p3 = 0.0;
341 d_p.d3_q3 = 0.0;
342 d_p.d3_r3 = 0.0;
343 d_p.d3_p2r = 0.0;
344 d_p.d3_p2q = 0.0;
345 d_p.d3_q2r = 0.0;
346 d_p.d3_pq2 = 0.0;
347 d_p.d3_pr2 = 0.0;
348 d_p.d3_qr2 = 0.0;
349 d_p.d3_pqr = 0.0;
350 	EqualDeriv(&d_q,&d_p);
351 	EqualDeriv(&d_r,&d_p);
352 	EqualDeriv(&d_zero,&d_p);
353     d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0;
354     d_q.d1_q = d_r.d1_r = 1.0;
355 
356 	EqualDeriv(&d_phiMinVbs,&d_q);
357 	d_phiMinVbs.value = phiMinVbs;
358 	d_phiMinVbs.d1_q = -  d_phiMinVbs.d1_q;
359 
360 	if (lvbs <= 0.0) {
361 	    sarg1 = sqrt(phiMinVbs);
362 	    SqrtDeriv(&d_sarg, &d_phiMinVbs);
363 	    dsrgdb = -0.5/sarg1;
364 	    InvDeriv(&d_dsrgdb,&d_sarg);
365 	    TimesDeriv(&d_dsrgdb,&d_dsrgdb,-0.5);
366 
367 	} else {
368 	    sphi = sqrt(here->MOS2tPhi); /*const*/
369 	    sphi3 = here->MOS2tPhi*sphi; /*const*/
370 	    sarg1 = sphi/(1.0+0.5*lvbs/here->MOS2tPhi);
371 	    EqualDeriv(&d_sarg,&d_q); d_sarg.value = lvbs;
372 	    TimesDeriv(&d_sarg,&d_sarg,0.5/here->MOS2tPhi);
373 	    d_sarg.value += 1.0;
374 	    InvDeriv(&d_sarg,&d_sarg);
375 	    TimesDeriv(&d_sarg,&d_sarg,sphi);
376 	    dsrgdb = -0.5*sarg1*sarg1/sphi3;
377 	    MultDeriv(&d_dsrgdb,&d_sarg,&d_sarg);
378 	    TimesDeriv(&d_dsrgdb,&d_dsrgdb,-0.5/sphi3);
379 	    /* tmp = sarg/sphi3; */
380 	}
381 	if ((lvds-lvbs) >= 0) {
382 	    barg = sqrt(phiMinVbs+lvds);
383 	    EqualDeriv(&d_barg,&d_phiMinVbs);
384 	    d_barg.value += lvds; d_barg.d1_r += 1.0;
385 	    SqrtDeriv(&d_barg,&d_barg);
386 	    dbrgdb = -0.5/barg;
387 	    InvDeriv(&d_dbrgdb,&d_barg);
388 	    TimesDeriv(&d_dbrgdb,&d_dbrgdb,-0.5);
389 	} else {
390 	    sphi = sqrt(here->MOS2tPhi); /* added by HT 050523 */
391 	    sphi3 = here->MOS2tPhi*sphi; /* added by HT 050523 */
392 	    barg = sphi/(1.0+0.5*(lvbs-lvds)/here->MOS2tPhi);
393 	    EqualDeriv(&d_barg,&d_q); d_barg.value = lvbs - lvds;
394 	    d_barg.d1_r -= 1.0;
395 	    TimesDeriv(&d_barg,&d_barg,0.5/here->MOS2tPhi);
396 	    d_barg.value += 1.0;
397 	    InvDeriv(&d_barg,&d_barg);
398 	    TimesDeriv(&d_barg,&d_barg,sphi);
399 	    dbrgdb = -0.5*barg*barg/sphi3;
400 	    MultDeriv(&d_dbrgdb,&d_barg,&d_barg);
401 	    TimesDeriv(&d_dbrgdb,&d_dbrgdb,-0.5/sphi3);
402 	    /* tmp = barg/sphi3; */
403 	}
404 	/*
405 	 *  calculate threshold voltage (von)
406 	 *     narrow-channel effect
407 	 */
408 
409 	/*XXX constant per device */
410 	factor = 0.125*model->MOS2narrowFactor*2.0*M_PI*EPSSIL/
411 	    OxideCap*EffectiveLength;
412 	/*XXX constant per device */
413 	eta = 1.0+factor;
414 	vbin = here->MOS2tVbi*model->MOS2type+factor*phiMinVbs;
415 	/* mistake! fixed Dec 7 '89
416 	 TimesDeriv(&d_vbin,&d_phiMinVbs,here->MOS2tVbi*
417 		    model->MOS2type+factor);
418 		    */
419 	 TimesDeriv(&d_vbin,&d_phiMinVbs,factor);
420 	 d_vbin.value += here->MOS2tVbi*model->MOS2type;
421 
422 	if ((model->MOS2gamma > 0.0) ||
423 		(model->MOS2substrateDoping > 0.0)) {
424 	    xwd = model->MOS2xd*barg;
425 	    xws = model->MOS2xd*sarg1;
426 	    TimesDeriv(&d_xwd,&d_barg,model->MOS2xd);
427 	    TimesDeriv(&d_xws,&d_sarg,model->MOS2xd);
428 
429 	    /*
430 	     *     short-channel effect with vds .ne. 0.0           */
431 
432 	    argss = 0.0;
433 	    argsd = 0.0;
434 	    EqualDeriv(&d_argss,&d_zero);
435 	    EqualDeriv(&d_argsd,&d_zero);
436 	    if (model->MOS2junctionDepth > 0) {
437 		tmp = 2.0/model->MOS2junctionDepth; /*const*/
438 		argxs = 1.0+xws*tmp;
439 		TimesDeriv(&d_argxs,&d_xws,tmp);
440 		d_argxs.value += 1.0;
441 		argxd = 1.0+xwd*tmp;
442 		TimesDeriv(&d_argxd,&d_xwd,tmp);
443 		d_argxd.value += 1.0;
444 		args = sqrt(argxs);
445 		SqrtDeriv(&d_args,&d_argxs);
446 		argd = sqrt(argxd);
447 		SqrtDeriv(&d_argd,&d_argxd);
448 		tmp = .5*model->MOS2junctionDepth/EffectiveLength;
449 		argss = tmp * (args-1.0);
450 		TimesDeriv(&d_argss,&d_args,tmp);
451 		d_argss.value -= tmp;
452 		argsd = tmp * (argd-1.0);
453 		TimesDeriv(&d_argsd,&d_argd,tmp);
454 		d_argsd.value -= tmp;
455 	    }
456 	    gamasd = model->MOS2gamma*(1.0-argss-argsd);
457 	    PlusDeriv(&d_gamasd,&d_argss,&d_argsd);
458 	    d_gamasd.value -= 1.0;
459 	    TimesDeriv(&d_gamasd,&d_gamasd,-model->MOS2gamma);
460 	    dbxwd = model->MOS2xd*dbrgdb;
461 	    dbxws = model->MOS2xd*dsrgdb;
462 	    TimesDeriv(&d_dbxwd,&d_dbrgdb,model->MOS2xd);
463 	    TimesDeriv(&d_dbxws,&d_dsrgdb,model->MOS2xd);
464 	    if (model->MOS2junctionDepth > 0) {
465 		tmp = 0.5/EffectiveLength;
466 		dbargs = tmp*dbxws/args;
467 		dbargd = tmp*dbxwd/argd;
468 		DivDeriv(&d_dbargs,&d_dbxws,&d_args);
469 		DivDeriv(&d_dbargd,&d_dbxwd,&d_argd);
470 		TimesDeriv(&d_dbargs,&d_dbargs,tmp);
471 		TimesDeriv(&d_dbargd,&d_dbargd,tmp);
472 	    }
473 	    dgddvb = -model->MOS2gamma*(dbargs+dbargd);
474 	    PlusDeriv(&d_dgddvb,&d_dbargs,&d_dbargd);
475 	    TimesDeriv(&d_dgddvb,&d_dgddvb,-model->MOS2gamma);
476 	    if (model->MOS2junctionDepth > 0) {
477 	    }
478 	} else {
479 	    gamasd = model->MOS2gamma;
480 	    gammad = model->MOS2gamma;
481 	    EqualDeriv(&d_gamasd,&d_zero);
482 	    EqualDeriv(&d_gammad,&d_zero);
483 	    d_gamasd.value = d_gammad.value = model->MOS2gamma;
484 	    dgddvb = 0.0;
485 	    EqualDeriv(&d_dgddvb,&d_zero);
486 	}
487 	von = vbin+gamasd*sarg1;
488 	MultDeriv(&d_von,&d_gamasd,&d_sarg);
489 	PlusDeriv(&d_von,&d_von,&d_vbin);
490 	/*
491 	vth = von;
492 	EqualDeriv(&d_vth,&d_von);
493 	*/
494 	vdsat = 0.0;
495 	EqualDeriv(&d_vdsat,&d_zero);
496 	if (model->MOS2fastSurfaceStateDensity != 0.0 && OxideCap != 0.0) {
497 	    /* XXX constant per model */
498 	    cfs = CHARGE*model->MOS2fastSurfaceStateDensity*
499 		1e4 /*(cm**2/m**2)*/;
500 	    cdonco = -(gamasd*dsrgdb + dgddvb*sarg1) + factor;
501 	    MultDeriv(&d_dummy,&d_dgddvb,&d_sarg);
502 	    MultDeriv(&d_cdonco,&d_gamasd,&d_dsrgdb);
503 	    PlusDeriv(&d_cdonco,&d_cdonco,&d_dummy);
504 	    TimesDeriv(&d_cdonco,&d_cdonco,-1.0);
505 	    d_cdonco.value += factor;
506 	   xn = 1.0+cfs/OxideCap*here->MOS2m*here->MOS2w*EffectiveLength+cdonco;
507 	   EqualDeriv(&d_xn,&d_cdonco);
508 	   d_xn.value = xn;
509 	    tmp = vt*xn;
510 	    TimesDeriv(&d_tmp,&d_xn,vt);
511 	    von = von+tmp;
512 	    PlusDeriv(&d_von,&d_von,&d_tmp);
513 	    argg = 1.0/tmp;
514 	    InvDeriv(&d_argg,&d_tmp);
515 	    vgst = lvgs-von;
516 	    TimesDeriv(&d_vgst,&d_von,-1.0);
517 	    PlusDeriv(&d_vgst,&d_vgst,&d_p);
518 	    d_vgst.value += lvgs;
519 	} else {
520 	    vgst = lvgs-von;
521 	    TimesDeriv(&d_vgst,&d_von,-1.0);
522 	    PlusDeriv(&d_vgst,&d_vgst,&d_p);
523 	    d_vgst.value += lvgs;
524 
525 	    if (lvgs <= von) {
526 		/*
527 		 *  cutoff region                     */
528 		here->MOS2gds = 0.0; /* look at this later */
529 		goto line1050;
530 	    }
531 	}
532 
533 	/*
534 	 *  compute some more useful quantities             */
535 
536 	sarg3 = sarg1*sarg1*sarg1;
537 	CubeDeriv(&d_sarg3,&d_sarg);
538 	/* XXX constant per model */
539 	sbiarg = sqrt(here->MOS2tBulkPot); /*const*/
540 	gammad = gamasd;
541 	EqualDeriv(&d_gammad,&d_gamasd);
542 	body = barg*barg*barg-sarg3;
543 	TimesDeriv(&d_body,&d_sarg3,-1.0);
544 	CubeDeriv(&d_dummy,&d_barg);
545 	PlusDeriv(&d_body,&d_body,&d_dummy);
546 	if (model->MOS2fastSurfaceStateDensity == 0.0) goto line400;
547 	if (OxideCap == 0.0) goto line410;
548 	/*
549 	 *  evaluate effective mobility and its derivatives             */
550 line400:
551 	if (OxideCap <= 0.0) goto line410;
552 	udenom = vgst;
553 	EqualDeriv(&d_udenom,&d_vgst);
554 	tmp = model->MOS2critField * 100 /* cm/m */ * EPSSIL/
555 	    model->MOS2oxideCapFactor;
556 	if (udenom <= tmp) goto line410;
557 	ufact = exp(model->MOS2critFieldExp*log(tmp/udenom));
558 	/* dummy = tmp/udenom */
559 	InvDeriv(&d_dummy,&d_udenom);
560 	TimesDeriv(&d_dummy,&d_dummy,tmp);
561 	PowDeriv(&d_ufact,&d_dummy,model->MOS2critFieldExp);
562 	ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ *ufact;
563 	TimesDeriv(&d_ueff,&d_ufact,model->MOS2surfaceMobility * 1e-4);
564 	goto line500;
565 line410:
566 	ufact = 0.0;
567 	EqualDeriv(&d_ufact,&d_zero);
568 	ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ ;
569 	EqualDeriv(&d_ueff,&d_zero);
570 	d_ueff.value = ueff;
571 
572 	/*
573 	 *     evaluate saturation voltage and its derivatives according to
574 	 *     grove-frohman equation             */
575 line500:
576 	vgsx = lvgs;
577 	EqualDeriv(&d_vgsx,&d_p); d_vgsx.value = lvgs;
578 	gammad = gamasd/eta; /* eta is a constant */
579 	TimesDeriv(&d_gammad,&d_gamasd,1/eta);
580 	if (model->MOS2fastSurfaceStateDensity != 0 && OxideCap != 0) {
581 	    vgsx = MAX(lvgs,von);
582 	    /* mistake! fixed Dec 8 '89 if (vgsx < von) { } */
583 	 if (lvgs > von) {
584 	     EqualDeriv(&d_vgsx,&d_p);d_vgsx.value = lvgs;
585 	 } else {
586 	    EqualDeriv(&d_vgsx,&d_von);
587 	 }
588 	}
589 
590 	if (gammad > 0) {
591 	    gammd2 = gammad*gammad;
592 	    MultDeriv(&d_gammd2,&d_gammad,&d_gammad);
593 	    argv = (vgsx-vbin)/eta+phiMinVbs;
594 	    TimesDeriv(&d_argv,&d_vbin,-1.0);
595 	    PlusDeriv(&d_argv,&d_vgsx,&d_vgsx);
596 	    TimesDeriv(&d_argv,&d_argv,1/eta);
597 	    PlusDeriv(&d_argv,&d_argv,&d_phiMinVbs);
598 	    if (argv <= 0.0) {
599 		vdsat = 0.0;
600 		EqualDeriv(&d_vdsat,&d_zero);
601 	    } else {
602 		arg1 = sqrt(1.0+4.0*argv/gammd2);
603 		DivDeriv(&d_arg,&d_argv,&d_gammd2);
604 		TimesDeriv(&d_arg,&d_arg,4.0);d_arg.value += 1.0;
605 		SqrtDeriv(&d_arg,&d_arg);
606 #if 0
607 		 dumarg= sqrt(gammd2*gammd2 +4*argv*gammd2);
608 		 TimesDeriv(&d_dumarg,&d_argv,4.0);
609 		 PlusDeriv(&d_dumarg,&d_dumarg,&d_gammd2);
610 		 MultDeriv(&d_dumarg,&d_dumarg,&d_gammd2);
611 		 SqrtDeriv(&d_dumarg,&d_dumarg);
612 
613 		vdsat = (vgsx-vbin)/eta+gammd2*(1.0-arg)/2.0;
614 		/* distortion vdsat=(vgsx-vbin)/eta + (gammd2 - dumarg)/2.0
615 		   = argv - phiMinVbs + (gammd2 - dumarg)/2 */
616 #endif
617 		TimesDeriv(&d_dummy,&d_dumarg,-1.0);
618 		PlusDeriv(&d_dummy,&d_dummy,&d_gammd2);
619 		TimesDeriv(&d_dummy,&d_dummy,0.5);
620 		TimesDeriv(&d_vdsat,&d_phiMinVbs,-1.0);
621 		PlusDeriv(&d_vdsat,&d_vdsat,&d_argv);
622 		PlusDeriv(&d_vdsat,&d_dummy,&d_vdsat);
623 		vdsat = MAX(vdsat,0.0);
624 		if (vdsat < 0.0) {
625 		EqualDeriv(&d_vdsat,&d_zero);
626 	}
627 	    }
628 	} else {
629 	    vdsat = (vgsx-vbin)/eta;
630 	    TimesDeriv(&d_vdsat,&d_vbin,-1.0);
631 	    PlusDeriv(&d_vdsat,&d_vgsx,&d_vdsat);
632 	    TimesDeriv(&d_vdsat,&d_vdsat,1/eta);
633 	    vdsat = MAX(vdsat,0.0);
634 	    if (vdsat < 0.0) {
635 		EqualDeriv(&d_vdsat,&d_zero);
636 	    }
637 	}
638 	if (model->MOS2maxDriftVel > 0) {
639 	    /*
640 	     *     evaluate saturation voltage and its derivatives
641 	     *     according to baum's theory of scattering velocity
642 	     *     saturation
643 	     */
644 	    gammd2 = gammad*gammad;
645 	    MultDeriv(&d_gammd2,&d_gammad,&d_gammad);
646 	    v1 = (vgsx-vbin)/eta+phiMinVbs;
647 	    TimesDeriv(&d_v1,&d_vbin,-1.0);
648 #if 0
649 	    /* mistake ! (fixed Dec 7 '89) thanks to Jean Hsu */
650 	    PlusDeriv(&d_v1,&d_vgsx,&d_vgsx);
651 #endif
652 	    PlusDeriv(&d_v1,&d_v1,&d_vgsx);
653 	    TimesDeriv(&d_v1,&d_v1,1/eta);
654 	    PlusDeriv(&d_v1,&d_v1,&d_phiMinVbs);
655 	    v2 = phiMinVbs;
656 	    EqualDeriv(&d_v2,&d_phiMinVbs);
657 	    xv = model->MOS2maxDriftVel*EffectiveLength/ueff;
658 	    InvDeriv(&d_xv,&d_ueff);
659 	    TimesDeriv(&d_xv,&d_xv,model->MOS2maxDriftVel*EffectiveLength);
660 	    a1 = gammad/0.75;
661 	    TimesDeriv(&d_a1,&d_gammad,4.0/3.0);
662 	    /* dummy1 = a1 */
663 	    b1 = -2.0*(v1+xv);
664 	    PlusDeriv(&d_b1,&d_v1,&d_xv);
665 	    TimesDeriv(&d_b1,&d_b1,-2.0);
666                 /* dummy2 = b1 */
667                 c1 = -2.0*gammad*xv;
668 		MultDeriv(&d_c1,&d_gammad,&d_xv);
669 		TimesDeriv(&d_c1,&d_c1,-2.0);
670                 /* dummy3 = c1 */
671                 d1 = 2.0*v1*(v2+xv)-v2*v2-4.0/3.0*gammad*sarg3;
672 		MultDeriv(&d_d1,&d_gammad,&d_sarg3);
673 		TimesDeriv(&d_d1,&d_d1,4.0/3.0);
674 		MultDeriv(&d_dummy,&d_v2,&d_v2);
675 		PlusDeriv(&d_d1,&d_d1,&d_dummy);
676 		TimesDeriv(&d_d1,&d_d1,-1.0);
677 		PlusDeriv(&d_dummy,&d_v2,&d_xv);
678 		MultDeriv(&d_dummy,&d_dummy,&d_v1);
679 		TimesDeriv(&d_dummy,&d_dummy,2.0);
680 		PlusDeriv(&d_d1,&d_d1,&d_dummy);
681                 a = -b1;
682 		TimesDeriv(&d_a,&d_b1,-1.0);
683                 b = a1*c1-4.0*d1;
684 		TimesDeriv(&d_b,&d_d1,-4.0);
685 		MultDeriv(&d_dummy,&d_a1,&d_c1);
686 		/* mistake! - fixed Dec 8 '89
687 		PlusDeriv(&d_d1,&d_d1,&d_dummy);
688 		*/
689 		PlusDeriv(&d_b,&d_b,&d_dummy);
690                 c = -d1*(a1*a1-4.0*b1)-c1*c1;
691 		TimesDeriv(&d_dummy,&d_b1,-4.0);
692 		MultDeriv(&d_c,&d_a1,&d_a1);
693 		PlusDeriv(&d_dummy,&d_dummy,&d_c);
694 		MultDeriv(&d_c,&d_dummy,&d_d1);
695 		MultDeriv(&d_dummy,&d_c1,&d_c1);
696 		PlusDeriv(&d_c,&d_c,&d_dummy);
697 		TimesDeriv(&d_c,&d_c,-1.0);
698 
699                 r = -a*a/3.0+b;
700 		MultDeriv(&d_arr,&d_a,&d_a);
701 		TimesDeriv(&d_arr,&d_arr,-1.0/3.0);
702 		PlusDeriv(&d_arr,&d_arr,&d_b);
703 
704                 s = 2.0*a*a*a/27.0-a*b/3.0+c;
705 		CubeDeriv(&d_s,&d_a);
706 		TimesDeriv(&d_s,&d_s,2.0/27.0);
707 		PlusDeriv(&d_s,&d_s,&d_c);
708 		MultDeriv(&d_dummy,&d_a,&d_b);
709 		TimesDeriv(&d_dummy,&d_dummy,-1.0/3.0);
710 		PlusDeriv(&d_s,&d_s,&d_dummy);
711 
712                 r3 = r*r*r;
713 		CubeDeriv(&d_r3,&d_arr);
714 
715                 s2 = s*s;
716 		MultDeriv(&d_s2,&d_s,&d_s);
717 
718                 p = s2/4.0+r3/27.0;
719 		TimesDeriv(&d_dummy,&d_r3,1.0/27.0);
720 		TimesDeriv(&d_pee,&d_s2,0.25);
721 		PlusDeriv(&d_pee,&d_pee,&d_dummy);
722                 p0 = fabs(p);
723 		if (p < 0.0)
724 			/* mistake! fixed Dec 8 '89
725 			TimesDeriv(&d_pee,&d_pee, -1.0);
726 			*/
727 			TimesDeriv(&d_p0,&d_pee, -1.0);
728                 p2 = sqrt(p0);
729 		SqrtDeriv(&d_p2,&d_p0);
730                 if (p < 0) {
731                     ro = sqrt(s2/4.0+p0);
732                     ro = log(ro)/3.0;
733                     ro = exp(ro);
734                     /* the above is eqvt. to
735 			ro = (s2/4.0 + p0)^1/6; */
736 		    TimesDeriv(&d_ro,&d_s2,0.25);
737 		    PlusDeriv(&d_ro,&d_ro,&d_p0);
738 		    PowDeriv(&d_ro,&d_ro,1.0/6.0);
739                     fi = atan(-2.0*p2/s);
740 		    DivDeriv(&d_fi,&d_p2,&d_s);
741 		    TimesDeriv(&d_fi,&d_fi,-2.0);
742 		    AtanDeriv(&d_fi,&d_fi);
743                     y3 = 2.0*ro*cos(fi/3.0)-a/3.0;
744 		    TimesDeriv(&d_dummy,&d_fi,1.0/3.0);
745 		    CosDeriv(&d_dummy,&d_dummy);
746 		    MultDeriv(&d_y3,&d_ro,&d_dummy);
747 		    TimesDeriv(&d_y3,&d_y3,2.0);
748 		    /* mistake! fixed Dec 8 '89
749 		    TimesDeriv(&d_dummy,&d_a,-3.0);
750 		    */
751 		    TimesDeriv(&d_dummy,&d_a,-1/3.0);
752 		    PlusDeriv(&d_y3,&d_y3,&d_dummy);
753                 } else {
754                     p3 = (-s/2.0+p2);
755 		    TimesDeriv(&d_p3,&d_s,-0.5);
756 		    PlusDeriv(&d_p3,&d_p3,&d_p2);
757                     p3 = exp(log(fabs(p3))/3.0);
758 		    /* eqvt. to (fabs(p3)) ^ 1/3 */
759 		    if (p3 < 0.0)
760 			TimesDeriv(&d_p3,&d_p3,-1.0);
761 		    PowDeriv(&d_p3,&d_p3,1.0/3.0);
762                     p4 = (-s/2.0-p2);
763 		    TimesDeriv(&d_p4,&d_s,0.5);
764 		    PlusDeriv(&d_p4,&d_p4,&d_p2);
765 		    if (p4 < 0.0)
766 		    TimesDeriv(&d_p4,&d_p4,-1.0); /* this is fabs(p4) */
767                     p4 = exp(log(fabs(p4))/3.0);
768 		    PowDeriv(&d_p4,&d_p4,1.0/3.0);
769 
770                     y3 = p3+p4-a/3.0;
771 		    TimesDeriv(&d_y3,&d_a,-1.0/3.0);
772 		    PlusDeriv(&d_y3,&d_y3,&d_p4);
773 		    PlusDeriv(&d_y3,&d_y3,&d_p3);
774                 }
775                 iknt = 0;
776                 a3 = sqrt(a1*a1/4.0-b1+y3);
777 		MultDeriv(&d_a3,&d_a1,&d_a1);
778 		TimesDeriv(&d_a3,&d_a3,0.25);
779 		PlusDeriv(&d_a3,&d_a3,&d_y3);
780 		TimesDeriv(&d_dummy,&d_b1,-1.0);
781 		PlusDeriv(&d_a3,&d_a3,&d_dummy);
782 		SqrtDeriv(&d_a3,&d_a3);
783 
784                 b3 = sqrt(y3*y3/4.0-d1);
785 		MultDeriv(&d_b3,&d_y3,&d_y3);
786 		TimesDeriv(&d_b3,&d_b3,0.25);
787 		TimesDeriv(&d_dummy,&d_d1,-1.0);
788 		PlusDeriv(&d_b3,&d_b3,&d_dummy);
789 		SqrtDeriv(&d_b3,&d_b3);
790 
791                 for(i = 1;i<=4;i++) {
792                     a4[i-1] = a1/2.0+sig1[i-1]*a3;
793 		    TimesDeriv(&d_a4[i-1],&d_a1,0.5);
794 		    TimesDeriv(&d_dummy,&d_a3,sig1[i-1]);
795 		    PlusDeriv(&d_a4[i-1],&d_a4[i-1],&d_dummy);
796                     b4[i-1] = y3/2.0+sig2[i-1]*b3;
797 		    TimesDeriv(&d_b4[i-1],&d_y3,0.5);
798 		    TimesDeriv(&d_dummy,&d_b3,sig2[i-1]);
799 		    PlusDeriv(&d_b4[i-1],&d_b4[i-1],&d_dummy);
800                     delta4 = a4[i-1]*a4[i-1]/4.0-b4[i-1];
801 		    MultDeriv(&d_delta4,&d_a4[i-1],&d_a4[i-1]);
802 		    TimesDeriv(&d_delta4,&d_delta4,0.25);
803 		    TimesDeriv(&d_dummy,&d_b4[i-1],-1.0);
804 		    PlusDeriv(&d_delta4,&d_delta4,&d_dummy);
805 
806                     if (delta4 < 0) continue;
807                     iknt = iknt+1;
808                     tmp = sqrt(delta4);
809 		    SqrtDeriv(&d_tmp,&d_delta4);
810                     x4[iknt-1] = -a4[i-1]/2.0+tmp;
811 		    TimesDeriv(&d_x4[iknt-1],&d_a4[i-1],-0.5);
812 		    PlusDeriv(&d_x4[iknt-1],&d_x4[iknt-1],&d_tmp);
813                     iknt = iknt+1;
814                     x4[iknt-1] = -a4[i-1]/2.0-tmp;
815 		    TimesDeriv(&d_x4[iknt-1],&d_a4[i-1],-0.5);
816 		    PlusDeriv(&d_x4[iknt-1],&d_x4[iknt-1],&d_tmp);
817                 }
818                 jknt = 0;
819                 for(j = 1;j<=iknt;j++) {
820                     if (x4[j-1] <= 0) continue;
821                     /* XXX implement this sanely */
822                     poly4[j-1] = x4[j-1]*x4[j-1]*x4[j-1]*x4[j-1]+a1*x4[j-1]*
823                         x4[j-1]*x4[j-1];
824 		    CubeDeriv(&d_dummy,&d_x4[j-1]);
825 		    PlusDeriv(&d_poly4[j-1],&d_x4[j-1],&d_a1);
826 		    MultDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_dummy);
827                     poly4[j-1] = poly4[j-1]+b1*x4[j-1]*x4[j-1]+c1*x4[j-1]+d1;
828 		    PlusDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_d1);
829 		    MultDeriv(&d_dummy,&d_b1,&d_x4[j-1]);
830 		    PlusDeriv(&d_dummy,&d_dummy,&d_c1);
831 		    MultDeriv(&d_dummy,&d_dummy,&d_x4[j-1]);
832 		    PlusDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_dummy);
833                     if (fabs(poly4[j-1]) > 1.0e-6) continue;
834                     jknt = jknt+1;
835                     if (jknt <= 1) {
836                         xvalid = x4[j-1];
837 			EqualDeriv(&d_xvalid,&d_x4[j-1]);
838                     }
839                     if (x4[j-1] > xvalid) continue;
840                     xvalid = x4[j-1];
841 		    EqualDeriv(&d_xvalid,&d_x4[j-1]);
842                 }
843                 if (jknt > 0) {
844                     vdsat = xvalid*xvalid-phiMinVbs;
845 		    MultDeriv(&d_vdsat,&d_xvalid,&d_xvalid);
846 		    TimesDeriv(&d_dummy,&d_phiMinVbs,-1.0);
847 		    PlusDeriv(&d_vdsat,&d_vdsat,&d_dummy);
848                 }
849             }
850             /*
851              *  evaluate effective channel length and its derivatives             */
852             if (lvds != 0.0) {
853                 gammad = gamasd;
854 		EqualDeriv(&d_gammad,&d_gamasd);
855                 if ((lvbs-vdsat) <= 0) {
856                     bsarg = sqrt(vdsat+phiMinVbs);
857 		    PlusDeriv(&d_bsarg,&d_vdsat,&d_phiMinVbs);
858 		    SqrtDeriv(&d_bsarg,&d_bsarg);
859 
860                 } else {
861                     bsarg = sphi/(1.0+0.5*(lvbs-vdsat)/here->MOS2tPhi);
862 		    TimesDeriv(&d_bsarg,&d_vdsat,-1.0);
863 		    d_bsarg.value += lvbs; d_bsarg.d1_r += 1.0;
864 		    TimesDeriv(&d_bsarg,&d_bsarg,0.5/here->MOS2tPhi);
865 		    d_bsarg.value += 1.0;
866 		    InvDeriv(&d_bsarg,&d_bsarg);
867 		    TimesDeriv(&d_bsarg,&d_bsarg,sphi);
868 
869                 }
870                 bodys = bsarg*bsarg*bsarg-sarg3;
871 		CubeDeriv(&d_bodys,&d_bsarg);
872 		TimesDeriv(&d_dummy,&d_sarg3,-1.0);
873 		PlusDeriv(&d_bodys,&d_bodys,&d_dummy);
874                 if (model->MOS2maxDriftVel <= 0) {
875                     if (model->MOS2substrateDoping == 0.0) goto line610;
876                     if (xlamda > 0.0) goto line610;
877                     argv = (lvds-vdsat)/4.0;
878 		    TimesDeriv(&d_argv,&d_vdsat,-1.0);
879 		    d_argv.value += lvds; d_argv.d1_r += 1.0;
880 		    TimesDeriv(&d_argv,&d_argv,0.25);
881 
882                     sargv = sqrt(1.0+argv*argv);
883 		    MultDeriv(&d_sargv,&d_argv,&d_argv);
884 		    d_sargv.value += 1.0;
885 		    SqrtDeriv(&d_sargv,&d_sargv);
886                     arg1 = sqrt(argv+sargv);
887 		    PlusDeriv(&d_arg,&d_sargv,&d_argv);
888 		    SqrtDeriv(&d_arg,&d_arg);
889                     xlfact = model->MOS2xd/(EffectiveLength*lvds);
890 		    EqualDeriv(&d_xlfact,&d_r); d_xlfact.value = lvds;
891 		    InvDeriv(&d_xlfact,&d_xlfact);
892 		    TimesDeriv(&d_xlfact,&d_xlfact,model->MOS2xd/EffectiveLength);
893                     xlamda = xlfact*arg1;
894 		    MultDeriv(&d_xlamda,&d_xlfact,&d_arg);
895                 } else {
896                     argv = (vgsx-vbin)/eta-vdsat;
897 		    TimesDeriv(&d_argv,&d_vbin,-1.0);
898 		    PlusDeriv(&d_argv,&d_argv,&d_vgsx);
899 		    TimesDeriv(&d_argv,&d_argv,1/eta);
900 		    TimesDeriv(&d_dummy,&d_vdsat,-1.0);
901 		    PlusDeriv(&d_argv,&d_argv,&d_dummy);
902                     xdv = model->MOS2xd/sqrt(model->MOS2channelCharge); /*const*/
903                     xlv = model->MOS2maxDriftVel*xdv/(2.0*ueff);
904 		    InvDeriv(&d_xlv,&d_ueff);
905 		    TimesDeriv(&d_xlv,&d_xlv,model->MOS2maxDriftVel*xdv*0.5);
906 		    /* retained for historical interest
907                     vqchan = argv-gammad*bsarg;
908 		    MultDeriv(&d_vqchan,&d_gammad,&d_bsarg);
909 		    TimesDeriv(&d_vqchan,&d_vqchan,-1);
910 		    PlusDeriv(&d_vqchan,&d_vqchan,&d_argv);
911 		    */
912                     /* gammad = gamasd
913                     vl = model->MOS2maxDriftVel*EffectiveLength;const*/
914                     if (model->MOS2substrateDoping == 0.0) goto line610;
915                     if (xlamda > 0.0) goto line610;
916                     argv = lvds-vdsat;
917 		    TimesDeriv(&d_argv,&d_vdsat,-1.0);
918 		    d_argv.value += lvds;
919 		    d_argv.d1_r += 1.0;
920 		    if (argv < 0.0)
921 			EqualDeriv(&d_argv,&d_zero);
922                     argv = MAX(argv,0.0);
923                     xls = sqrt(xlv*xlv+argv);
924 		    MultDeriv(&d_xls,&d_xlv,&d_xlv);
925 		    PlusDeriv(&d_xls,&d_xls,&d_argv);
926 		    SqrtDeriv(&d_xls,&d_xls);
927                     /* dummy9 = xlv*xlv + argv */
928                     xlfact = xdv/(EffectiveLength*lvds);
929 		    EqualDeriv(&d_xlfact,&d_r);
930 		    d_xlfact.value += lvds;
931 		    InvDeriv(&d_xlfact,&d_xlfact);
932 		    TimesDeriv(&d_xlfact,&d_xlfact,xdv/EffectiveLength);
933                     xlamda = xlfact*(xls-xlv);
934 		    TimesDeriv(&d_xlamda,&d_xlv,-1.0);
935 		    PlusDeriv(&d_xlamda,&d_xlamda,&d_xls);
936 		    MultDeriv(&d_xlamda,&d_xlamda,&d_xlfact);
937 
938                 }
939             }
940 line610:
941 
942             /*
943              *     limit channel shortening at punch-through             */
944             xwb = model->MOS2xd*sbiarg; /*const*/
945             xld = EffectiveLength-xwb; /*const*/
946             clfact = 1.0-xlamda*lvds;
947 	    EqualDeriv(&d_clfact,&d_r); d_clfact.value = lvds;
948 	    d_clfact.d1_r = -1;
949 	    MultDeriv(&d_clfact,&d_clfact,&d_xlamda);
950 	    d_clfact.value += 1.0;
951             xleff = EffectiveLength*clfact;
952 	    TimesDeriv(&d_xleff,&d_clfact,EffectiveLength);
953             deltal = xlamda*lvds*EffectiveLength;
954 	    EqualDeriv(&d_delta1,&d_r);
955 	    d_delta1.value = EffectiveLength*lvds;
956 	    d_delta1.d1_r = EffectiveLength;
957 	    MultDeriv(&d_delta1,&d_delta1,&d_xlamda);
958 
959 
960             if (model->MOS2substrateDoping == 0.0) xwb = 0.25e-6;
961             if (xleff < xwb) {
962                 xleff = xwb/(1.0+(deltal-xld)/xwb);
963 		EqualDeriv(&d_xleff,&d_delta1);d_xleff.value -= xld;
964 		TimesDeriv(&d_xleff,&d_xleff,1/xwb);d_xleff.value += 1.0;
965 		InvDeriv(&d_xleff,&d_xleff);
966 		TimesDeriv(&d_xleff,&d_xleff,xwb);
967                 clfact = xleff/EffectiveLength;
968 		TimesDeriv(&d_clfact,&d_xleff,1/EffectiveLength);
969 
970  /*               dfact = xleff*xleff/(xwb*xwb); */
971             }
972             /*
973              *  evaluate effective beta (effective kp)
974              */
975             beta1 = Beta*ufact/clfact;
976 	    DivDeriv(&d_beta1,&d_ufact,&d_clfact);
977 	    TimesDeriv(&d_beta1,&d_beta1,Beta);
978             /*
979              *  test for mode of operation and branch appropriately             */
980             gammad = gamasd;
981 	    EqualDeriv(&d_gammad,&d_gamasd);
982             if (lvds <= 1.0e-10) {
983                 if (lvgs <= von) {
984                     if ((model->MOS2fastSurfaceStateDensity == 0.0) ||
985                             (OxideCap == 0.0)) {
986                         here->MOS2gds = 0.0;
987                     d_cdrain.d1_q = 0.0;
988                     d_cdrain.d2_q2 = 0.0;
989                     d_cdrain.d3_q3 = 0.0;
990                         goto line1050;
991                     }
992 
993                     here->MOS2gds = beta1*(von-vbin-gammad*sarg1)*exp(argg*
994                         (lvgs-von));
995 		    MultDeriv(&d_dummy,&d_gammad,&d_sarg);
996 		    PlusDeriv(&d_dummy,&d_dummy,&d_vbin);
997 		    TimesDeriv(&d_dummy,&d_dummy,-1.0);
998 		    PlusDeriv(&d_dummy,&d_dummy,&d_von);
999 		    MultDeriv(&d_mos2gds,&d_beta1,&d_dummy);
1000 		    TimesDeriv(&d_dummy,&d_von,-1.0);
1001 		    PlusDeriv(&d_dummy,&d_dummy,&d_p);
1002 		    d_dummy.value += lvgs;
1003 		    MultDeriv(&d_dummy,&d_dummy,&d_argg);
1004 		    ExpDeriv(&d_dummy,&d_dummy);
1005 		    MultDeriv(&d_mos2gds,&d_mos2gds,&d_dummy);
1006 		    d_cdrain.d1_r = d_mos2gds.value;
1007 		    d_cdrain.d2_r2 = d_mos2gds.d1_r;
1008 		    d_cdrain.d3_r3 = d_mos2gds.d2_r2;
1009                         /* dummy1 = von - vbin - gamasd*sarg */
1010                     goto line1050;
1011                 }
1012 
1013 
1014                 here->MOS2gds = beta1*(lvgs-vbin-gammad*sarg1);
1015 		MultDeriv(&d_mos2gds,&d_gammad,&d_sarg);
1016 		PlusDeriv(&d_mos2gds,&d_mos2gds,&d_vbin);
1017 		TimesDeriv(&d_mos2gds,&d_mos2gds,-1.0);
1018 		MultDeriv(&d_mos2gds,&d_mos2gds,&d_beta1);
1019 		    d_cdrain.d1_r = d_mos2gds.value;
1020 		    d_cdrain.d2_r2 = d_mos2gds.d1_r;
1021 		    d_cdrain.d3_r3 = d_mos2gds.d2_r2;
1022 
1023                 goto line1050;
1024             }
1025 
1026             if (lvgs > von) goto line900;
1027             /*
1028              *  subthreshold region             */
1029             if (vdsat <= 0) {
1030                 here->MOS2gds = 0.0;
1031 		    d_cdrain.d1_r = 0.0;
1032 		    d_cdrain.d2_r2 = 0.0;
1033 		    d_cdrain.d3_r3 = 0.0;
1034                 /* if (lvgs > vth) goto doneval; */
1035                 goto line1050;
1036             }
1037             vdson = MIN(vdsat,lvds);
1038 	    if (vdsat <= lvds) {
1039 		EqualDeriv(&d_vdson,&d_vdsat);
1040 		} else {
1041 		EqualDeriv(&d_vdson,&d_r);
1042 		d_vdson.value = lvds;
1043 		}
1044             if (lvds > vdsat) {
1045                 barg = bsarg;
1046 		EqualDeriv(&d_barg,&d_bsarg);
1047                 body = bodys;
1048 		EqualDeriv(&d_body,&d_bodys);
1049             }
1050             cdson = beta1*((von-vbin-eta*vdson*0.5)*vdson-gammad*body/1.5);
1051 	    MultDeriv(&d_dummy,&d_gammad,&d_body);
1052 	    TimesDeriv(&d_cdson,&d_dummy,-1/1.5);
1053 	    TimesDeriv(&d_dummy,&d_vdson,0.5*eta);
1054 	    PlusDeriv(&d_dummy,&d_dummy,&d_vbin);
1055 	    TimesDeriv(&d_dummy,&d_dummy,-1.0);
1056 	    PlusDeriv(&d_dummy,&d_dummy,&d_von);
1057 	    MultDeriv(&d_dummy,&d_dummy,&d_vdson);
1058 	    PlusDeriv(&d_dummy,&d_dummy,&d_cdson);
1059 	    MultDeriv(&d_cdson,&d_dummy,&d_beta1);
1060             expg = exp(argg*(lvgs-von));
1061 	    TimesDeriv(&d_expg,&d_von,-1.0);
1062 	    d_expg.value += lvgs;
1063 	    d_expg.d1_p += 1.0;
1064 	    MultDeriv(&d_expg,&d_expg,&d_argg);
1065 	    ExpDeriv(&d_expg,&d_expg);
1066 
1067             cdrain = cdson*expg;
1068 	    MultDeriv(&d_cdrain,&d_cdson,&d_expg);
1069 	    /*
1070             gmw = cdrain*argg;
1071             here->MOS2gm = gmw;
1072             tmp = gmw*(lvgs-von)/xn;
1073 	    */
1074             goto doneval;
1075 
1076 line900:
1077             if (lvds <= vdsat) {
1078                 /*
1079                  *  linear region                 */
1080                 cdrain = beta1*((lvgs-vbin-eta*lvds/2.0)*lvds-gammad*body/1.5);
1081 		MultDeriv(&d_dummy,&d_gammad,&d_body);
1082 		TimesDeriv(&d_dummy,&d_dummy,-1/1.5);
1083 		EqualDeriv(&d_cdrain,&d_r);
1084 		d_cdrain.value = eta*lvds*0.5;
1085 		d_cdrain.d1_r = 0.5*eta;
1086 		PlusDeriv(&d_cdrain,&d_cdrain,&d_vbin);
1087 		TimesDeriv(&d_cdrain,&d_cdrain,-1.0);
1088 		d_cdrain.value += lvgs;
1089 		d_cdrain.d1_p += 1.0;
1090 		EqualDeriv(&d_dummy,&d_r);
1091 		d_dummy.value = lvds;
1092 		MultDeriv(&d_cdrain,&d_cdrain,&d_dummy);
1093 		MultDeriv(&d_dummy,&d_gammad,&d_body);
1094 		TimesDeriv(&d_dummy,&d_dummy,-1/1.5);
1095 		PlusDeriv(&d_cdrain,&d_cdrain,&d_dummy);
1096 		MultDeriv(&d_cdrain,&d_cdrain,&d_beta1);
1097             } else {
1098                 /*
1099                  *  saturation region                 */
1100                 cdrain = beta1*((lvgs-vbin-eta*
1101                     vdsat/2.0)*vdsat-gammad*bodys/1.5);
1102 	    TimesDeriv(&d_cdrain,&d_vdsat,0.5*eta);
1103 	    PlusDeriv(&d_cdrain,&d_cdrain,&d_vbin);
1104 	    TimesDeriv(&d_cdrain,&d_cdrain,-1.0);
1105 	    d_cdrain.value += lvgs;
1106 	    d_cdrain.d1_p += 1.0;
1107 	    MultDeriv(&d_cdrain,&d_cdrain,&d_vdsat);
1108 	    MultDeriv(&d_dummy,&d_gammad,&d_bodys);
1109 	    TimesDeriv(&d_dummy,&d_dummy,-1/1.5);
1110 	    PlusDeriv(&d_cdrain,&d_cdrain,&d_dummy);
1111 	    MultDeriv(&d_cdrain,&d_cdrain,&d_beta1);
1112             }
1113             /*
1114              *     compute charges for "on" region             */
1115             goto doneval;
1116             /*
1117              *  finish special cases             */
1118 line1050:
1119             cdrain = 0.0;
1120             here->MOS2gm = 0.0;
1121             here->MOS2gmbs = 0.0;
1122 d_cdrain.value = 0.0;
1123 d_cdrain.d1_p = 0.0;
1124 d_cdrain.d1_q = 0.0;
1125 d_cdrain.d2_p2 = 0.0;
1126 d_cdrain.d2_q2 = 0.0;
1127 d_cdrain.d2_pq = 0.0;
1128 d_cdrain.d2_qr = 0.0;
1129 d_cdrain.d2_pr = 0.0;
1130 d_cdrain.d3_p3 = 0.0;
1131 d_cdrain.d3_q3 = 0.0;
1132 d_cdrain.d3_p2r = 0.0;
1133 d_cdrain.d3_p2q = 0.0;
1134 d_cdrain.d3_q2r = 0.0;
1135 d_cdrain.d3_pq2 = 0.0;
1136 d_cdrain.d3_pr2 = 0.0;
1137 d_cdrain.d3_qr2 = 0.0;
1138 d_cdrain.d3_pqr = 0.0;
1139 }
1140 
1141             /*
1142              *  finished
1143 	     */
1144 
1145 /*================HERE=================*/
1146 doneval:
1147             /*
1148              *  COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
1149              */
1150             /*
1151              * now we do the hard part of the bulk-drain and bulk-source
1152 	     * diode - we evaluate the non-linear capacitance and
1153 	     * charge
1154              * the basic equations are not hard, but the implementation
1155 	     * is somewhat long in an attempt to avoid log/exponential
1156 	     * evaluations
1157 	     */
1158                 /*
1159                  *  charge storage elements                 *
1160                  *.. bulk-drain and bulk-source depletion capacitances
1161 		 */
1162                     if (vbs < here->MOS2tDepCap){
1163                         arg=1-vbs/here->MOS2tBulkPot;
1164                         /*
1165                          * the following block looks somewhat long and messy,
1166                          * but since most users use the default grading
1167                          * coefficients of .5, and sqrt is MUCH faster than an
1168                          * exp(log()) we use this special case code to buy time.
1169                          * (as much as 10% of total job time!)
1170                          */
1171                         if(model->MOS2bulkJctBotGradingCoeff ==
1172                                 model->MOS2bulkJctSideGradingCoeff) {
1173                             if(model->MOS2bulkJctBotGradingCoeff == .5) {
1174                                 sarg = sargsw = 1/sqrt(arg);
1175                             } else {
1176                                 sarg = sargsw =
1177                                         exp(-model->MOS2bulkJctBotGradingCoeff*
1178                                         log(arg));
1179                             }
1180                         } else {
1181                             if(model->MOS2bulkJctBotGradingCoeff == .5) {
1182                                 sarg = 1/sqrt(arg);
1183                             } else {
1184                                 sarg = exp(-model->MOS2bulkJctBotGradingCoeff*
1185                                         log(arg));
1186                             }
1187                             if(model->MOS2bulkJctSideGradingCoeff == .5) {
1188                                 sargsw = 1/sqrt(arg);
1189                             } else {
1190                                 sargsw =exp(-model->MOS2bulkJctSideGradingCoeff*
1191                                         log(arg));
1192                             }
1193                         }
1194 		    lcapbs=here->MOS2Cbs*sarg+
1195                                 here->MOS2Cbssw*sargsw;
1196 		    lcapbs2 = model->MOS2type*0.5/here->MOS2tBulkPot*(
1197 			here->MOS2Cbs*model->MOS2bulkJctBotGradingCoeff*
1198 			sarg/arg + here->MOS2Cbssw*
1199 			model->MOS2bulkJctSideGradingCoeff*sargsw/arg);
1200 		    lcapbs3 = here->MOS2Cbs*sarg*
1201 			model->MOS2bulkJctBotGradingCoeff*
1202 			(model->MOS2bulkJctBotGradingCoeff+1);
1203 		    lcapbs3 += here->MOS2Cbssw*sargsw*
1204 			model->MOS2bulkJctSideGradingCoeff*
1205 			(model->MOS2bulkJctSideGradingCoeff+1);
1206 		    lcapbs3 = lcapbs3/(6*here->MOS2tBulkPot*
1207 			here->MOS2tBulkPot*arg*arg);
1208                     } else {
1209                     /*    *(ckt->CKTstate0 + here->MOS2qbs)= here->MOS2f4s +
1210                                 vbs*(here->MOS2f2s+vbs*(here->MOS2f3s/2));*/
1211                         lcapbs=here->MOS2f2s+here->MOS2f3s*vbs;
1212 			lcapbs2 = 0.5*here->MOS2f3s;
1213 			lcapbs3 = 0;
1214                     }
1215                     if (vbd < here->MOS2tDepCap) {
1216                         arg=1-vbd/here->MOS2tBulkPot;
1217                         /*
1218                          * the following block looks somewhat long and messy,
1219                          * but since most users use the default grading
1220                          * coefficients of .5, and sqrt is MUCH faster than an
1221                          * exp(log()) we use this special case code to buy time.
1222                          * (as much as 10% of total job time!)
1223                          */
1224                         if(model->MOS2bulkJctBotGradingCoeff == .5 &&
1225                                 model->MOS2bulkJctSideGradingCoeff == .5) {
1226                             sarg = sargsw = 1/sqrt(arg);
1227                         } else {
1228                             if(model->MOS2bulkJctBotGradingCoeff == .5) {
1229                                 sarg = 1/sqrt(arg);
1230                             } else {
1231                                 sarg = exp(-model->MOS2bulkJctBotGradingCoeff*
1232                                         log(arg));
1233                             }
1234                             if(model->MOS2bulkJctSideGradingCoeff == .5) {
1235                                 sargsw = 1/sqrt(arg);
1236                             } else {
1237                                 sargsw =exp(-model->MOS2bulkJctSideGradingCoeff*
1238                                         log(arg));
1239                             }
1240                         }
1241 		    lcapbd=here->MOS2Cbd*sarg+
1242                                 here->MOS2Cbdsw*sargsw;
1243 		    lcapbd2 = model->MOS2type*0.5/here->MOS2tBulkPot*(
1244 			here->MOS2Cbd*model->MOS2bulkJctBotGradingCoeff*
1245 			sarg/arg + here->MOS2Cbdsw*
1246 			model->MOS2bulkJctSideGradingCoeff*sargsw/arg);
1247 		    lcapbd3 = here->MOS2Cbd*sarg*
1248 			model->MOS2bulkJctBotGradingCoeff*
1249 			(model->MOS2bulkJctBotGradingCoeff+1);
1250 		    lcapbd3 += here->MOS2Cbdsw*sargsw*
1251 			model->MOS2bulkJctSideGradingCoeff*
1252 			(model->MOS2bulkJctSideGradingCoeff+1);
1253 		    lcapbd3 = lcapbd3/(6*here->MOS2tBulkPot*
1254 			here->MOS2tBulkPot*arg*arg);
1255                     } else {
1256                         lcapbd=here->MOS2f2d + vbd * here->MOS2f3d;
1257 			lcapbd2=0.5*here->MOS2f3d;
1258 			lcapbd3=0;
1259                     }
1260             /*
1261              *     meyer's capacitor model             */
1262 	/*
1263 	 * the meyer capacitance equations are in DEVqmeyer
1264 	 * these expressions are derived from those equations.
1265 	 * these expressions are incorrect; they assume just one
1266 	 * controlling variable for each charge storage element
1267 	 * while actually there are several;  the MOS2 small
1268 	 * signal ac linear model is also wrong because it
1269 	 * ignores controlled capacitive elements. these can be
1270 	 * corrected (as can the linear ss ac model) if the
1271 	 * expressions for the charge are available
1272 	 */
1273 
1274 
1275 {
1276 
1277 
1278     double phi;
1279     double cox;
1280     double vddif;
1281     double vddif1;
1282     double vddif2;
1283     /* von, vgst and vdsat have already been adjusted for
1284         possible source-drain interchange */
1285 
1286 
1287 
1288     phi = here->MOS2tPhi;
1289     cox = OxideCap;
1290     if (vgst <= -phi) {
1291     lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
1292     } else if (vgst <= -phi/2) {
1293     lcapgb2= -cox/(4*phi);
1294     lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
1295     } else if (vgst <= 0) {
1296     lcapgb2= -cox/(4*phi);
1297     lcapgb3=lcapgs3=lcapgd2=lcapgd3=0;
1298     lcapgs2 = cox/(3*phi);
1299     } else  {			/* the MOS2modes are around because
1300 					vds has not been adjusted */
1301         if (vdsat <= here->MOS2mode*vds) {
1302 	lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
1303         } else {
1304             vddif = 2.0*vdsat-here->MOS2mode*vds;
1305             vddif1 = vdsat-here->MOS2mode*vds/*-1.0e-12*/;
1306             vddif2 = vddif*vddif;
1307 	    lcapgd2 = -vdsat*here->MOS2mode*vds*cox/(3*vddif*vddif2);
1308 	    lcapgd3 = - here->MOS2mode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2);
1309 	    lcapgs2 = -vddif1*here->MOS2mode*vds*cox/(3*vddif*vddif2);
1310 	    lcapgs3 = - here->MOS2mode*vds*cox*(vddif - 6*vddif1)/(9*vddif2*vddif2);
1311 	    lcapgb2=lcapgb3=0;
1312         }
1313     }
1314     }
1315 
1316 		/* the b-s and b-d diodes need no processing ...  */
1317 	here->capbs2 = lcapbs2;
1318 	here->capbs3 = lcapbs3;
1319 	here->capbd2 = lcapbd2;
1320 	here->capbd3 = lcapbd3;
1321 	here->gbs2 = lgbs2;
1322 	here->gbs3 = lgbs3;
1323 	here->gbd2 = lgbd2;
1324 	here->gbd3 = lgbd3;
1325 	here->capgb2 = model->MOS2type*lcapgb2;
1326 	here->capgb3 = lcapgb3;
1327                 /*
1328                  *   process to get Taylor coefficients, taking into		 * account type and mode.
1329                  */
1330 gm2 = d_cdrain.d2_p2;
1331 gb2 = d_cdrain.d2_q2;
1332 gds2 = d_cdrain.d2_r2;
1333 gmb = d_cdrain.d2_pq;
1334 gbds = d_cdrain.d2_qr;
1335 gmds = d_cdrain.d2_pr;
1336 gm3 = d_cdrain.d3_p3;
1337 gb3 = d_cdrain.d3_q3;
1338 gds3 = d_cdrain.d3_r3;
1339 gm2ds = d_cdrain.d3_p2r;
1340 gm2b = d_cdrain.d3_p2q;
1341 gb2ds = d_cdrain.d3_q2r;
1342 gmb2 = d_cdrain.d3_pq2;
1343 gmds2 = d_cdrain.d3_pr2;
1344 gbds2 = d_cdrain.d3_qr2;
1345 gmbds = d_cdrain.d3_pqr;
1346 
1347 	if (here->MOS2mode == 1)
1348 		{
1349 		/* normal mode - no source-drain interchange */
1350 
1351  here->cdr_x2 = gm2;
1352  here->cdr_y2 = gb2;
1353  here->cdr_z2 = gds2;
1354  here->cdr_xy = gmb;
1355  here->cdr_yz = gbds;
1356  here->cdr_xz = gmds;
1357  here->cdr_x3 = gm3;
1358  here->cdr_y3 = gb3;
1359  here->cdr_z3 = gds3;
1360  here->cdr_x2z = gm2ds;
1361  here->cdr_x2y = gm2b;
1362  here->cdr_y2z = gb2ds;
1363  here->cdr_xy2 = gmb2;
1364  here->cdr_xz2 = gmds2;
1365  here->cdr_yz2 = gbds2;
1366  here->cdr_xyz = gmbds;
1367 
1368 		/* the gate caps have been divided and made into			Taylor coeffs., but not adjusted for type */
1369 
1370 	here->capgs2 = model->MOS2type*lcapgs2;
1371 	here->capgs3 = lcapgs3;
1372 	here->capgd2 = model->MOS2type*lcapgd2;
1373 	here->capgd3 = lcapgd3;
1374 } else {
1375 		/*
1376 		 * inverse mode - source and drain interchanged		 */
1377 here->cdr_x2 = -gm2;
1378 here->cdr_y2 = -gb2;
1379 here->cdr_z2 = -(gm2 + gb2 + gds2 + 2*(gmb + gmds + gbds));
1380 here->cdr_xy = -gmb;
1381 here->cdr_yz = gmb + gb2 + gbds;
1382 here->cdr_xz = gm2 + gmb + gmds;
1383 here->cdr_x3 = -gm3;
1384 here->cdr_y3 = -gb3;
1385 here->cdr_z3 = gm3 + gb3 + gds3 +
1386 	3*(gm2b + gm2ds + gmb2 + gb2ds + gmds2 + gbds2) + 6*gmbds ;
1387 here->cdr_x2z = gm3 + gm2b + gm2ds;
1388 here->cdr_x2y = -gm2b;
1389 here->cdr_y2z = gmb2 + gb3 + gb2ds;
1390 here->cdr_xy2 = -gmb2;
1391 here->cdr_xz2 = -(gm3 + 2*(gm2b + gm2ds + gmbds) +
1392 					gmb2 + gmds2);
1393 here->cdr_yz2 = -(gb3 + 2*(gmb2 + gb2ds + gmbds) +
1394 					gm2b + gbds2);
1395 here->cdr_xyz = gm2b + gmb2 + gmbds;
1396 
1397           here->capgs2 = model->MOS2type*lcapgd2;
1398 	  here->capgs3 = lcapgd3;
1399 
1400 	  here->capgd2 = model->MOS2type*lcapgs2;
1401 	  here->capgd3 = lcapgs3;
1402 
1403 }
1404 
1405 /* now to adjust for type and multiply by factors to convert to Taylor coeffs. */
1406 
1407 here->cdr_x2 = 0.5*model->MOS2type*here->cdr_x2;
1408 here->cdr_y2 = 0.5*model->MOS2type*here->cdr_y2;
1409 here->cdr_z2 = 0.5*model->MOS2type*here->cdr_z2;
1410 here->cdr_xy = model->MOS2type*here->cdr_xy;
1411 here->cdr_yz = model->MOS2type*here->cdr_yz;
1412 here->cdr_xz = model->MOS2type*here->cdr_xz;
1413 here->cdr_x3 = here->cdr_x3/6.;
1414 here->cdr_y3 = here->cdr_y3/6.;
1415 here->cdr_z3 = here->cdr_z3/6.;
1416 here->cdr_x2z = 0.5*here->cdr_x2z;
1417 here->cdr_x2y = 0.5*here->cdr_x2y;
1418 here->cdr_y2z = 0.5*here->cdr_y2z;
1419 here->cdr_xy2 = 0.5*here->cdr_xy2;
1420 here->cdr_xz2 = 0.5*here->cdr_xz2;
1421 here->cdr_yz2 = 0.5*here->cdr_yz2;
1422 
1423 
1424 		}
1425         }
1426     return(OK);
1427     }
1428