1 /***************************************************************************
2 JSPICE3 adaptation of Spice3f2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California.  All rights reserved.
4 Authors: 1985 Thomas L. Quarles
5          1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 #include "spice.h"
9 #include <stdio.h>
10 #include "diodefs.h"
11 #include "const.h"
12 #include "util.h"
13 #include "sperror.h"
14 #include "niext.h"
15 
16 
17 #ifdef __STDC__
18 static int  dio_bypass(CKTcircuit*,DIOmodel*,DIOinstance*);
19 static int  dio_limiting(CKTcircuit*,DIOmodel*,DIOinstance*);
20 static int  dio_pnjlim(double*,double,double,double);
21 static void dio_iv(CKTcircuit*,DIOmodel*,DIOinstance*);
22 static void dio_cap(CKTcircuit*,DIOmodel*,DIOinstance*);
23 static void dio_load(CKTcircuit*,DIOmodel*,DIOinstance*);
24 #else
25 static int  dio_bypass();
26 static int  dio_limiting();
27 static void dio_iv();
28 static void dio_cap();
29 static void dio_load();
30 #endif
31 
32 
33 int
DIOload(inModel,ckt)34 DIOload(inModel,ckt)
35 
36 /* actually load the current stamp into the
37  * sparse matrix previously provided
38  */
39 GENmodel *inModel;
40 CKTcircuit *ckt;
41 {
42     DIOmodel *model = (DIOmodel*)inModel;
43     DIOinstance *here;
44     double ceq;
45     double geq;
46     int error;
47 
48     if (ckt->CKTmode & MODEINITFLOAT) {
49 
50         /* loop through all the diode models */
51         for ( ; model != NULL; model = model->DIOnextModel) {
52 
53             /* loop through all the instances of the model */
54             for (here = model->DIOinstances; here != NULL;
55                     here = here->DIOnextInstance) {
56 
57                 here->DIOvd = *(ckt->CKTrhsOld + here->DIOposPrimeNode) -
58                         *(ckt->CKTrhsOld + here->DIOnegNode);
59 
60                 /*
61                  *   bypass if solution has not changed
62                  */
63                 if (ckt->CKTbypass && dio_bypass(ckt,model,here))
64                     continue;
65 
66                 (void)dio_limiting(ckt,model,here);
67 
68                 dio_iv(ckt,model,here);
69 
70                 if (ckt->CKTmode & MODETRAN) {
71                     dio_cap(ckt,model,here);
72                     /*
73                      *   transient analysis
74                      */
75                     NI_INTEG(ckt,geq,ceq,here->DIOcap,here->DIOcapCharge);
76                     here->DIOgd += geq;
77                     here->DIOcd += *(ckt->CKTstate0 + here->DIOcapCurrent);
78                 }
79                 dio_load(ckt,model,here);
80             }
81         }
82         return (OK);
83     }
84 
85     if (ckt->CKTmode & MODEINITPRED) {
86         double xf1;
87         double xf2;
88 
89         xf2 = -ckt->CKTdelta/ckt->CKTdeltaOld[1];
90         xf1 = 1 - xf2;
91 
92         /* loop through all the diode models */
93         for ( ; model != NULL; model = model->DIOnextModel) {
94 
95             /* loop through all the instances of the model */
96             for (here = model->DIOinstances; here != NULL;
97                     here = here->DIOnextInstance) {
98 
99                 here->DIOvd = xf1* *(ckt->CKTstate1 + here->DIOvoltage)
100                         + xf2* *(ckt->CKTstate2 + here->DIOvoltage);
101 
102                 *(ckt->CKTstate0 + here->DIOvoltage) =
103                     *(ckt->CKTstate1 + here->DIOvoltage);
104 
105                 (void)dio_limiting(ckt,model,here);
106                 dio_iv(ckt,model,here);
107                 if (ckt->CKTmode & MODETRAN) {
108                     dio_cap(ckt,model,here);
109                     NI_INTEG(ckt,geq,ceq,here->DIOcap,here->DIOcapCharge);
110                     here->DIOgd += geq;
111                     here->DIOcd += *(ckt->CKTstate0 + here->DIOcapCurrent);
112                 }
113                 dio_load(ckt,model,here);
114             }
115         }
116         return (OK);
117     }
118 
119     if (ckt->CKTmode & MODEINITFIX) {
120 
121         /* loop through all the diode models */
122         for ( ; model != NULL; model = model->DIOnextModel) {
123 
124             /* loop through all the instances of the model */
125             for (here = model->DIOinstances; here != NULL;
126                     here = here->DIOnextInstance) {
127 
128                 if (here->DIOoff)
129                     here->DIOvd = 0;
130                 else {
131                     here->DIOvd = *(ckt->CKTrhsOld + here->DIOposPrimeNode) -
132                         *(ckt->CKTrhsOld + here->DIOnegNode);
133 
134                     if (dio_limiting(ckt,model,here))
135                         ckt->CKTnoncon++;
136                 }
137                 dio_iv(ckt,model,here);
138                 dio_load(ckt,model,here);
139             }
140         }
141         return (OK);
142     }
143 
144     if (ckt->CKTmode & MODEINITTRAN) {
145 
146         /* loop through all the diode models */
147         for ( ; model != NULL; model = model->DIOnextModel) {
148 
149             /* loop through all the instances of the model */
150             for (here = model->DIOinstances; here != NULL;
151                     here = here->DIOnextInstance) {
152 
153                 here->DIOvd = *(ckt->CKTstate1 + here->DIOvoltage);
154 
155                 dio_iv(ckt,model,here);
156                 dio_cap(ckt,model,here);
157                 *(ckt->CKTstate1 + here->DIOcapCharge) =
158                     *(ckt->CKTstate0 + here->DIOcapCharge);
159                 NI_INTEG(ckt,geq,ceq,here->DIOcap,here->DIOcapCharge);
160                 here->DIOgd += geq;
161                 here->DIOcd += *(ckt->CKTstate0 + here->DIOcapCurrent);
162                 dio_load(ckt,model,here);
163             }
164         }
165         return (OK);
166     }
167 
168     if (ckt->CKTmode & MODEINITSMSIG) {
169 
170         /* loop through all the diode models */
171         for ( ; model != NULL; model = model->DIOnextModel) {
172 
173             /* loop through all the instances of the model */
174             for (here = model->DIOinstances; here != NULL;
175                     here = here->DIOnextInstance) {
176 
177                 here->DIOvd = *(ckt->CKTstate0 + here->DIOvoltage);
178                 dio_iv(ckt,model,here);
179                 dio_cap(ckt,model,here);
180             }
181         }
182         return (OK);
183     }
184 
185     if ((ckt->CKTmode & MODEINITJCT) &&
186             (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) {
187 
188         /* loop through all the diode models */
189         for ( ; model != NULL; model = model->DIOnextModel) {
190 
191             /* loop through all the instances of the model */
192             for (here = model->DIOinstances; here != NULL;
193                     here = here->DIOnextInstance) {
194 
195                 *(ckt->CKTstate0 + here->DIOvoltage) = here->DIOinitCond;
196             }
197         }
198         return (OK);
199     }
200 
201     if (ckt->CKTmode & MODEINITJCT) {
202 
203         /* loop through all the diode models */
204         for ( ; model != NULL; model = model->DIOnextModel) {
205 
206             /* loop through all the instances of the model */
207             for (here = model->DIOinstances; here != NULL;
208                     here = here->DIOnextInstance) {
209 
210                 if (here->DIOoff)
211                     here->DIOvd = 0;
212                 else
213                     here->DIOvd = here->DIOtVcrit;
214                 dio_iv(ckt,model,here);
215                 dio_load(ckt,model,here);
216             }
217         }
218     }
219     return (OK);
220 }
221 
222 
223 static int
dio_bypass(ckt,model,here)224 dio_bypass(ckt,model,here)
225 
226 CKTcircuit *ckt;
227 DIOmodel *model;
228 DIOinstance *here;
229 {
230     double delvd, cdhat, tol, A1, A2;
231 
232     delvd = here->DIOvd - *(ckt->CKTstate0 + here->DIOvoltage);
233 
234     A1  = FABS(here->DIOvd);
235     A2  = FABS(*(ckt->CKTstate0 + here->DIOvoltage));
236     tol = ckt->CKTvoltTol + ckt->CKTreltol*MAX(A1,A2);
237 
238     if (FABS(delvd) < tol) {
239         cdhat = here->DIOcd + here->DIOgd*delvd;
240         A1 = FABS(cdhat);
241         A2 = FABS(here->DIOcd);
242         tol = ckt->CKTabstol + ckt->CKTreltol*MAX(A1,A2);
243         A1 = cdhat - here->DIOcd;
244         if (FABS(A1) < tol) {
245             here->DIOvd = *(ckt->CKTstate0 + here->DIOvoltage);
246             dio_load(ckt,model,here);
247             return (1);
248         }
249     }
250     return (0);
251 }
252 
253 
254 static int
dio_limiting(ckt,model,here)255 dio_limiting(ckt,model,here)
256 
257 CKTcircuit *ckt;
258 DIOmodel *model;
259 DIOinstance *here;
260 {
261     double temp;
262     int rt;
263 
264     if (model->DIObreakdownVoltageGiven) {
265         temp = 10*here->DIOvte - here->DIOtBrkdwnV;
266         if (here->DIOvd < MIN(0,temp)) {
267 
268             temp = -(here->DIOvd + here->DIOtBrkdwnV);
269             rt = dio_pnjlim(&temp,
270                 -(*(ckt->CKTstate0 + here->DIOvoltage) + here->DIOtBrkdwnV),
271                 here->DIOvte,here->DIOtVcrit);
272             here->DIOvd = -(temp + here->DIOtBrkdwnV);
273             return (rt);
274         }
275     }
276     return (dio_pnjlim(&here->DIOvd,*(ckt->CKTstate0 + here->DIOvoltage),
277                 here->DIOvte,here->DIOtVcrit));
278 
279 }
280 
281 
282 static int
dio_pnjlim(vnew,vold,vt,vcrit)283 dio_pnjlim(vnew,vold,vt,vcrit)
284 
285 /*
286  * limit the per-iteration change of PN junction voltages
287  */
288 double *vnew;
289 double vold;
290 double vt;
291 double vcrit;
292 {
293     double arg;
294     double vn;
295 
296     vn = *vnew;
297     if ((vn > vcrit) && (FABS(vn - vold) > (vt + vt))) {
298         if (vold > 0) {
299             arg = 1 + (vn - vold)/vt;
300             if (arg > 0) {
301                 *vnew = vold + vt*log(arg);
302             }
303             else {
304                 *vnew = vcrit;
305             }
306         }
307         else {
308             *vnew = vt*log(vn/vt);
309         }
310         return (1);
311     }
312     return (0);
313 }
314 
315 
316 static void
dio_iv(ckt,model,here)317 dio_iv(ckt,model,here)
318 
319 /*
320  *   compute dc current and derivitives
321  */
322 CKTcircuit *ckt;
323 DIOmodel *model;
324 DIOinstance *here;
325 {
326     double arg;
327     double vte;
328     double vd;
329     double csat;
330 
331     vte  = here->DIOvte;
332     csat = here->DIOtSatCur;
333     vd   = here->DIOvd;
334 
335     if (vd >= -3*vte) {
336         arg = exp(vd/vte);
337         here->DIOcd = csat*(arg-1) + ckt->CKTgmin*vd;
338         here->DIOgd = csat*arg/vte + ckt->CKTgmin;
339     }
340     else if ((!(here->DIOtBrkdwnV)) || vd >= -here->DIOtBrkdwnV) {
341         arg = 3*vte/(vd*CONSTe);
342         arg = arg * arg * arg;
343         here->DIOcd = -csat*(1+arg) + ckt->CKTgmin*vd;
344         here->DIOgd = csat*3*arg/vd + ckt->CKTgmin;
345     }
346     else {
347         arg = exp(-(here->DIOtBrkdwnV + vd)/vte);
348         here->DIOcd = -csat*arg + ckt->CKTgmin*vd;
349         here->DIOgd = csat*arg/vte + ckt->CKTgmin;
350     }
351 }
352 
353 
354 static void
dio_cap(ckt,model,here)355 dio_cap(ckt,model,here)
356 
357 /*
358  *   charge storage elements
359  */
360 CKTcircuit *ckt;
361 DIOmodel *model;
362 DIOinstance *here;
363 {
364     double czero;
365     double czof2;
366     double arg;
367     double sarg;
368     double vd;
369 
370     vd = here->DIOvd;
371     czero = here->DIOtJctCap*here->DIOarea;
372 
373     if (vd < here->DIOtDepCap) {
374         arg = 1 - vd/model->DIOjunctionPot;
375 
376         if (model->DIOgradingCoeff == .5)
377             sarg = 1/sqrt(arg);
378         else
379             sarg = exp(-model->DIOgradingCoeff*log(arg));
380 
381         *(ckt->CKTstate0 + here->DIOcapCharge) =
382                 model->DIOtransitTime*here->DIOcd +
383                 model->DIOjunctionPot*czero*(1 - arg*sarg)/
384                     (1 - model->DIOgradingCoeff);
385         here->DIOcap =
386                 model->DIOtransitTime*here->DIOgd + czero*sarg;
387     }
388     else {
389         czof2 = czero/model->DIOf2;
390         *(ckt->CKTstate0 + here->DIOcapCharge) =
391                 model->DIOtransitTime*here->DIOcd + czero*here->DIOtF1 +
392                 czof2*(model->DIOf3*(vd - here->DIOtDepCap) +
393                 (model->DIOgradingCoeff/
394                     (model->DIOjunctionPot + model->DIOjunctionPot))*
395                         (vd*vd - here->DIOtDepCap*here->DIOtDepCap));
396         here->DIOcap =
397                 model->DIOtransitTime*here->DIOgd +
398                 czof2*(model->DIOf3 +
399                     model->DIOgradingCoeff*vd/model->DIOjunctionPot);
400     }
401 }
402 
403 
404 static void
dio_load(ckt,model,here)405 dio_load(ckt,model,here)
406 
407 /*
408  *   load matrix, rhs, and state
409  */
410 CKTcircuit *ckt;
411 DIOmodel *model;
412 DIOinstance *here;
413 {
414     double gspr;
415     double cdeq;
416     double gd;
417 
418     gd = here->DIOgd;
419 
420     *(ckt->CKTstate0 + here->DIOvoltage) = here->DIOvd;
421 
422     gspr = model->DIOconductance*here->DIOarea;
423     cdeq = here->DIOcd - gd*here->DIOvd;
424 
425     *(ckt->CKTrhs + here->DIOnegNode)      += cdeq;
426     *(ckt->CKTrhs + here->DIOposPrimeNode) -= cdeq;
427 
428     *(here->DIOposPosPtr)           += gspr;
429     *(here->DIOnegNegPtr)           += gd;
430     *(here->DIOposPrimePosPrimePtr) += gd + gspr;
431     *(here->DIOposPosPrimePtr)      -= gspr;
432     *(here->DIOnegPosPrimePtr)      -= gd;
433     *(here->DIOposPrimePosPtr)      -= gspr;
434     *(here->DIOposPrimeNegPtr)      -= gd;
435 }
436