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