1 /**********
2 Copyright 1991 Regents of the University of California. All rights reserved.
3 Author: 1991 David A. Gates, U. C. Berkeley CAD Group
4 Modifed: 2001 Paolo Nenzi
5 **********/
6
7 #include "ngspice/carddefs.h"
8 #include "ngspice/cidersupt.h"
9 #include "ngspice/cktdefs.h"
10 #include "ngspice/ciderinp.h"
11 #include "ngspice/cpextern.h"
12 #include "ngspice/dopdefs.h"
13 #include "ngspice/meshext.h"
14 #include "ngspice/ngspice.h"
15 #include "ngspice/numenum.h"
16 #include "ngspice/profile.h"
17 #include "ngspice/gendev.h"
18 #include "ngspice/sperror.h"
19 #include "ngspice/suffix.h"
20
21
22 /*
23 * Name: DOPcheck
24 * Purpose: checks a list of DOPcards for input errors
25 * Formals: cardList: the list to check
26 * Returns: OK/E_PRIVATE
27 * Users: numerical device setup routines
28 * Calls: error message handler
29 */
30 int
DOPcheck(DOPcard * cardList,MESHcoord * xMeshList,MESHcoord * yMeshList)31 DOPcheck(DOPcard *cardList, MESHcoord *xMeshList, MESHcoord *yMeshList)
32 {
33 DOPcard *card;
34 int cardNum = 0;
35 int error = OK;
36
37 for ( card = cardList; card != NULL; card = card->DOPnextCard ) {
38 cardNum++;
39 if (!card->DOPdomainsGiven) {
40 card->DOPnumDomains = 0;
41 card->DOPdomains = NULL;
42 }
43 if (!card->DOPprofileTypeGiven) {
44 SPfrontEnd->IFerrorf( ERR_WARNING, "doping card %d does not specify profile type", cardNum );
45 error = E_PRIVATE;
46 } else switch (card->DOPprofileType) {
47 case DOP_UNIF:
48 if (!card->DOPconcGiven) {
49 SPfrontEnd->IFerrorf( ERR_WARNING, "doping card %d needs conc of uniform distribution", cardNum );
50 error = E_PRIVATE;
51 }
52 break;
53 case DOP_LINEAR:
54 if (!card->DOPconcGiven) {
55 SPfrontEnd->IFerrorf( ERR_WARNING, "doping card %d needs peak conc of linear distribution", cardNum );
56 error = E_PRIVATE;
57 }
58 break;
59 case DOP_GAUSS:
60 if (!card->DOPconcGiven) {
61 SPfrontEnd->IFerrorf( ERR_WARNING, "doping card %d needs peak conc of gaussian distribution", cardNum );
62 error = E_PRIVATE;
63 }
64 break;
65 case DOP_ERFC:
66 if (!card->DOPconcGiven) {
67 SPfrontEnd->IFerrorf( ERR_WARNING, "doping card %d needs peak conc of error-function distribution", cardNum );
68 error = E_PRIVATE;
69 }
70 break;
71 case DOP_EXP:
72 if (!card->DOPconcGiven) {
73 SPfrontEnd->IFerrorf( ERR_WARNING, "doping card %d needs peak conc of exponential distribution", cardNum );
74 error = E_PRIVATE;
75 }
76 break;
77 case DOP_SUPREM3:
78 case DOP_SUPASCII:
79 if (!card->DOPinFileGiven) {
80 SPfrontEnd->IFerrorf( ERR_WARNING, "doping card %d needs input-file name of suprem3 data", cardNum );
81 error = E_PRIVATE;
82 }
83 break;
84 case DOP_ASCII:
85 if (!card->DOPinFileGiven) {
86 SPfrontEnd->IFerrorf( ERR_WARNING, "doping card %d needs input-file name of ascii data", cardNum );
87 error = E_PRIVATE;
88 }
89 break;
90 default:
91 SPfrontEnd->IFerrorf( ERR_FATAL, "doping card %d has unrecognized profile type", cardNum );
92 error = E_NOTFOUND;
93 break;
94 }
95 if (!card->DOProtateLatGiven) {
96 card->DOProtateLat = FALSE;
97 }
98 if (!card->DOPlatProfileTypeGiven || card->DOProtateLat) {
99 card->DOPlatProfileType = card->DOPprofileType;
100 }
101 if (!card->DOPratioLatGiven) {
102 card->DOPratioLat = 1.0;
103 }
104 if (!card->DOPcharLenGiven) {
105 card->DOPcharLen = 1.0e-4; /* 1um in centimeters */
106 }
107 if (!card->DOPlocationGiven) {
108 card->DOPlocation = 0.0;
109 }
110 if (!card->DOPimpurityTypeGiven) {
111 card->DOPimpurityType = IMP_N_TYPE;
112 } else switch (card->DOPimpurityType) {
113 case DOP_BORON:
114 card->DOPimpurityType = IMP_BORON;
115 break;
116 case DOP_PHOSP:
117 card->DOPimpurityType = IMP_PHOSPHORUS;
118 break;
119 case DOP_ARSEN:
120 card->DOPimpurityType = IMP_ARSENIC;
121 break;
122 case DOP_ANTIM:
123 card->DOPimpurityType = IMP_ANTIMONY;
124 break;
125 case DOP_N_TYPE:
126 card->DOPimpurityType = IMP_N_TYPE;
127 break;
128 case DOP_P_TYPE:
129 card->DOPimpurityType = IMP_P_TYPE;
130 break;
131 default:
132 break;
133 }
134
135 if (!card->DOPaxisTypeGiven) {
136 if ( xMeshList && yMeshList ) { /* both lists are non-empty */
137 card->DOPaxisType = DOP_Y_AXIS;
138 } else if ( xMeshList ) { /* x-mesh list is non-empty */
139 card->DOPaxisType = DOP_X_AXIS;
140 } else if ( yMeshList ) { /* y-mesh list is non-empty */
141 card->DOPaxisType = DOP_Y_AXIS;
142 }
143 }
144
145 /* Return now if anything has failed */
146 if (error) return(error);
147 }
148 return(OK);
149 }
150
151
152
153 /*
154 * Name: DOPsetup
155 * Purpose: convert a list of DOPcard's to DOPprofile's
156 * Formals: cardList: list of cards to setup
157 * profileList: returns the list of DOPprofile's
158 * xMeshList: list of coordinates in the x mesh
159 * yMeshList: list of coordinates in the y mesh
160 * Returns: OK/E_PRIVATE
161 * Users: numerical devices
162 * Calls: DOPcheck
163 */
164 int
DOPsetup(DOPcard * cardList,DOPprofile ** profileList,DOPtable ** tableList,MESHcoord * xMeshList,MESHcoord * yMeshList)165 DOPsetup(DOPcard *cardList, DOPprofile **profileList, DOPtable **tableList,
166 MESHcoord *xMeshList, MESHcoord *yMeshList)
167 {
168 DOPcard *card;
169 DOPprofile *newProfile = NULL, *endProfile;
170 int impurityId = 0;
171 double xMin, xMax, yMin, yMax;
172 double sign;
173 int error, xProfUnif, yProfUnif;
174
175 /* Initialize list of profiles */
176 *profileList = endProfile = NULL;
177
178 /* Check the card list */
179 if ((error = DOPcheck( cardList, xMeshList, yMeshList )) != 0) return( error );
180
181 /* Find the limits on locations */
182 MESHlBounds( xMeshList, &xMin, &xMax );
183 MESHlBounds( yMeshList, &yMin, &yMax );
184
185 for ( card = cardList; card != NULL; card = card->DOPnextCard ) {
186
187 if (*profileList == NULL) {
188 RALLOC( newProfile, DOPprofile, 1 );
189 *profileList = newProfile;
190 }
191 else {
192 RALLOC( newProfile->next, DOPprofile, 1 );
193 newProfile = newProfile->next;
194 }
195 newProfile->next = NULL;
196
197 newProfile->numDomains = card->DOPnumDomains;
198 if ( newProfile->numDomains > 0 ) {
199 int i;
200 RALLOC( newProfile->domains, int, newProfile->numDomains );
201 for ( i=0; i < newProfile->numDomains; i++ ) {
202 newProfile->domains[i] = card->DOPdomains[i];
203 }
204 }
205 else {
206 newProfile->domains = NULL;
207 }
208
209 if ( card->DOPimpurityType == IMP_P_TYPE ) {
210 sign = -1.0;
211 }
212 else {
213 sign = 1.0;
214 }
215 switch( card->DOPprofileType ) {
216 case DOP_UNIF:
217 newProfile->type = UNIF;
218 newProfile->CONC = sign * card->DOPconc;
219 break;
220 case DOP_LINEAR:
221 newProfile->type = LIN;
222 newProfile->CONC = sign * card->DOPconc;
223 break;
224 case DOP_GAUSS:
225 newProfile->type = GAUSS;
226 newProfile->CONC = sign * card->DOPconc;
227 break;
228 case DOP_ERFC:
229 newProfile->type = ERRFC;
230 newProfile->CONC = sign * card->DOPconc;
231 break;
232 case DOP_EXP:
233 newProfile->type = EXP;
234 newProfile->CONC = sign * card->DOPconc;
235 break;
236 case DOP_SUPREM3:
237 newProfile->type = LOOKUP;
238 if (readSupremData( card->DOPinFile, 0, card->DOPimpurityType,
239 tableList) != 0) {
240 (void) fprintf(cp_err, "Doping setup failed.\n");
241 return -1;
242 }
243 newProfile->IMPID = ++impurityId;
244 break;
245 case DOP_SUPASCII:
246 newProfile->type = LOOKUP;
247 if (readSupremData( card->DOPinFile, 1, card->DOPimpurityType,
248 tableList) != 0) {
249 (void) fprintf(cp_err, "Doping setup failed.\n");
250 return -1;
251 }
252 newProfile->IMPID = ++impurityId;
253 break;
254 case DOP_ASCII:
255 newProfile->type = LOOKUP;
256 if (readAsciiData(card->DOPinFile, card->DOPimpurityType,
257 tableList) != 0) {
258 (void) fprintf(cp_err, "Doping setup failed.\n");
259 return -1;
260 }
261 newProfile->IMPID = ++impurityId;
262 break;
263 default:
264 break;
265 }
266 switch( card->DOPlatProfileType ) {
267 case DOP_UNIF:
268 newProfile->latType = UNIF;
269 break;
270 case DOP_LINEAR:
271 newProfile->latType = LIN;
272 break;
273 case DOP_GAUSS:
274 newProfile->latType = GAUSS;
275 break;
276 case DOP_ERFC:
277 newProfile->latType = ERRFC;
278 break;
279 case DOP_EXP:
280 newProfile->latType = EXP;
281 break;
282 case DOP_SUPREM3:
283 case DOP_SUPASCII:
284 newProfile->latType = LOOKUP;
285 break;
286 case DOP_ASCII:
287 newProfile->latType = LOOKUP;
288 break;
289 default:
290 break;
291 }
292 newProfile->rotate = card->DOProtateLat;
293 newProfile->LOCATION = card->DOPlocation;
294 newProfile->CHAR_LENGTH = card->DOPcharLen;
295 newProfile->LAT_RATIO = card->DOPratioLat;
296
297 xProfUnif = yProfUnif = FALSE;
298 if (card->DOPaxisType == DOP_X_AXIS) {
299 newProfile->DIRECTION = X;
300 if (newProfile->type == UNIF) xProfUnif = TRUE;
301 if (newProfile->latType == UNIF) yProfUnif = TRUE;
302 }
303 else {
304 newProfile->DIRECTION = Y;
305 if (newProfile->type == UNIF) yProfUnif = TRUE;
306 if (newProfile->latType == UNIF) xProfUnif = TRUE;
307 }
308
309 /* Fill in x coordinates. Use defaults if necessary */
310 if (card->DOPxLowGiven && card->DOPxHighGiven) {
311 newProfile->X_LOW = card->DOPxLow;
312 newProfile->X_HIGH = card->DOPxHigh;
313 }
314 else if (card->DOPxLowGiven) {
315 newProfile->X_LOW = card->DOPxLow;
316 if (xProfUnif) {
317 newProfile->X_HIGH = xMax;
318 }
319 else {
320 newProfile->X_HIGH = newProfile->X_LOW;
321 }
322 }
323 else if (card->DOPxHighGiven) {
324 newProfile->X_HIGH = card->DOPxHigh;
325 if (xProfUnif) {
326 newProfile->X_LOW = xMin;
327 }
328 else {
329 newProfile->X_LOW = newProfile->X_HIGH;
330 }
331 }
332 else {
333 if (xProfUnif) {
334 newProfile->X_LOW = xMin;
335 newProfile->X_HIGH = xMax;
336 }
337 else {
338 newProfile->X_LOW = 0.5 * (xMin + xMax);
339 newProfile->X_HIGH = 0.5 * (xMin + xMax);
340 }
341 }
342
343 /* Fill in y coordinates. Use defaults if necessary */
344 if (card->DOPyLowGiven && card->DOPyHighGiven) {
345 newProfile->Y_LOW = card->DOPyLow;
346 newProfile->Y_HIGH = card->DOPyHigh;
347 }
348 else if (card->DOPyLowGiven) {
349 newProfile->Y_LOW = card->DOPyLow;
350 if (yProfUnif) {
351 newProfile->Y_HIGH = yMax;
352 }
353 else {
354 newProfile->Y_HIGH = newProfile->Y_LOW;
355 }
356 }
357 else if (card->DOPyHighGiven) {
358 newProfile->Y_HIGH = card->DOPyHigh;
359 if (xProfUnif) {
360 newProfile->Y_LOW = yMin;
361 }
362 else {
363 newProfile->Y_LOW = newProfile->Y_HIGH;
364 }
365 }
366 else {
367 if (yProfUnif) {
368 newProfile->Y_LOW = yMin;
369 newProfile->Y_HIGH = yMax;
370 }
371 else {
372 newProfile->Y_LOW = 0.5 * (yMin + yMax);
373 newProfile->Y_HIGH = 0.5 * (yMin + yMax);
374 }
375 }
376 }
377 return( OK );
378 }
379