1 /**********
2 Copyright 1991 Regents of the University of California. All rights reserved.
3 Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
4 **********/
5
6 #include "ngspice/ngspice.h"
7 #include "ngspice/cktdefs.h"
8 #include "ngspice/smpdefs.h"
9 #include "nbjtdefs.h"
10 #include "ngspice/numconst.h"
11 #include "ngspice/numenum.h"
12 #include "ngspice/sperror.h"
13 #include "../../../ciderlib/oned/onedext.h"
14 #include "ngspice/cidersupt.h"
15 #include "ngspice/ciderinp.h"
16 #include "ngspice/suffix.h"
17 #include "ngspice/meshext.h"
18
19 #define TSCALLOC(var, size, type)\
20 if (size && (var =(type *)calloc(1, (unsigned)(size)*sizeof(type))) == NULL) {\
21 return(E_NOMEM);\
22 }
23
24 int
NBJTsetup(SMPmatrix * matrix,GENmodel * inModel,CKTcircuit * ckt,int * states)25 NBJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
26 /*
27 * load the diode structure with those pointers needed later for fast matrix
28 * loading
29 */
30 {
31 register NBJTmodel *model = (NBJTmodel *) inModel;
32 register NBJTinstance *inst;
33 METHcard *methods;
34 MODLcard *models;
35 OPTNcard *options;
36 OUTPcard *outputs;
37 int error;
38 int xMeshSize;
39 ONEdevice *pDevice;
40 ONEcoord *xCoordList = NULL;
41 ONEdomain *domainList = NULL;
42 DOPprofile *profileList = NULL;
43 DOPtable *dopTableList = NULL;
44 ONEmaterial *pM, *pMaterial = NULL, *materialList = NULL;
45 double startTime;
46
47
48 /* loop through all the diode models */
49 for (; model != NULL; model = NBJTnextModel(model)) {
50 if (!model->NBJTpInfo) {
51 TSCALLOC(model->NBJTpInfo, 1, ONEtranInfo);
52 }
53 methods = model->NBJTmethods;
54 if (!methods) {
55 TSCALLOC(methods, 1, METHcard);
56 model->NBJTmethods = methods;
57 }
58 models = model->NBJTmodels;
59 if (!models) {
60 TSCALLOC(models, 1, MODLcard);
61 model->NBJTmodels = models;
62 }
63 options = model->NBJToptions;
64 if (!options) {
65 TSCALLOC(options, 1, OPTNcard);
66 model->NBJToptions = options;
67 }
68 outputs = model->NBJToutputs;
69 if (!outputs) {
70 TSCALLOC(outputs, 1, OUTPcard);
71 model->NBJToutputs = outputs;
72 }
73 if (!methods->METHvoltPredGiven) {
74 methods->METHvoltPred = FALSE;
75 }
76 if (!methods->METHmobDerivGiven) {
77 methods->METHmobDeriv = TRUE;
78 }
79 if (!methods->METHoneCarrierGiven) {
80 methods->METHoneCarrier = FALSE;
81 }
82 if (!methods->METHacAnalysisMethodGiven) {
83 methods->METHacAnalysisMethod = SOR;
84 }
85 if (!methods->METHdabstolGiven) {
86 methods->METHdabstol = DABSTOL1D;
87 }
88 if (!methods->METHdreltolGiven) {
89 methods->METHdreltol = ckt->CKTreltol;
90 }
91 if (!methods->METHitLimGiven) {
92 methods->METHitLim = 20;
93 }
94 if (!methods->METHomegaGiven || methods->METHomega <= 0.0) {
95 methods->METHomega = 2.0 * M_PI /* radians/sec */ ;
96 }
97 if (!options->OPTNdefaGiven || options->OPTNdefa <= 0.0) {
98 options->OPTNdefa = 1.0e4 /* cm^2 */ ;
99 }
100 if (!options->OPTNbaseLengthGiven) {
101 options->OPTNbaseLength = 0.0;
102 }
103 if (!options->OPTNbaseAreaGiven) {
104 options->OPTNbaseArea = 1.0;
105 }
106 if (!options->OPTNdeviceTypeGiven) {
107 options->OPTNdeviceType = OPTN_BIPOLAR;
108 }
109 if (!options->OPTNicFileGiven) {
110 options->OPTNicFile = NULL;
111 options->OPTNunique = FALSE; /* Can't form a unique name. */
112 }
113 if (!options->OPTNuniqueGiven) {
114 options->OPTNunique = FALSE;
115 }
116
117 /* Set up the rest of the card lists */
118 if ((error = MODLsetup(model->NBJTmodels)) != 0)
119 return (error);
120 BandGapNarrowing = models->MODLbandGapNarrowing;
121 ConcDepLifetime = models->MODLconcDepLifetime;
122 TempDepMobility = models->MODLtempDepMobility;
123 ConcDepMobility = models->MODLconcDepMobility;
124
125 if ((error = OUTPsetup(model->NBJToutputs)) != 0)
126 return (error);
127 if ((error = MATLsetup(model->NBJTmaterials, &materialList)) != 0)
128 return (error);
129 if ((error = MOBsetup(model->NBJTmobility, materialList)) != 0)
130 return (error);
131 if ((error = MESHsetup('x', model->NBJTxMeshes, &xCoordList, &xMeshSize)) != 0)
132 return (error);
133 if ((error = DOMNsetup(model->NBJTdomains, &domainList,
134 xCoordList, NULL, materialList)) != 0)
135 return (error);
136 if ((error = BDRYsetup(model->NBJTboundaries,
137 xCoordList, NULL, domainList)) != 0)
138 return (error);
139 if ((error = CONTsetup(model->NBJTcontacts, NULL)) != 0)
140 return (error);
141 if ((error = DOPsetup(model->NBJTdopings, &profileList,
142 &dopTableList, xCoordList, NULL)) != 0)
143 return (error);
144 model->NBJTmatlInfo = materialList;
145 model->NBJTprofiles = profileList;
146 model->NBJTdopTables = dopTableList;
147
148 /* loop through all the instances of the model */
149 for (inst = NBJTinstances(model); inst != NULL;
150 inst = NBJTnextInstance(inst)) {
151
152 startTime = SPfrontEnd->IFseconds();
153
154 if (!inst->NBJTprintGiven) {
155 inst->NBJTprint = 0;
156 } else if (inst->NBJTprint <= 0) {
157 inst->NBJTprint = 1;
158 }
159 if (!inst->NBJTicFileGiven) {
160 if (options->OPTNunique) {
161 inst->NBJTicFile = tprintf("%s.%s", options->OPTNicFile, inst->NBJTname);
162 } else if (options->OPTNicFile != NULL) {
163 inst->NBJTicFile = tprintf("%s", options->OPTNicFile);
164 } else {
165 inst->NBJTicFile = NULL;
166 }
167 }
168 inst->NBJTstate = *states;
169 *states += NBJTnumStates;
170
171 if (!inst->NBJTpDevice) {
172 /* Assign the mesh info to each instance. */
173 TSCALLOC(pDevice, 1, ONEdevice);
174 TSCALLOC(pDevice->pStats, 1, ONEstats);
175 pDevice->name = inst->NBJTname;
176 pDevice->solverType = SLV_NONE;
177 pDevice->numNodes = xMeshSize;
178 pDevice->abstol = methods->METHdabstol;
179 pDevice->reltol = methods->METHdreltol;
180 pDevice->rhsImag = NULL;
181 TSCALLOC(pDevice->elemArray, pDevice->numNodes, ONEelem *);
182
183 /* Create a copy of material data that can change with temperature. */
184 pDevice->pMaterials = NULL;
185 for (pM = materialList; pM != NULL; pM = pM->next) {
186 if (pDevice->pMaterials == NULL) {
187 TSCALLOC(pMaterial, 1, ONEmaterial);
188 pDevice->pMaterials = pMaterial;
189 } else {
190 TSCALLOC(pMaterial->next, 1, ONEmaterial);
191 pMaterial = pMaterial->next;
192 }
193 /* Copy everything, then fix the incorrect pointer. */
194 memcpy(pMaterial, pM, sizeof(ONEmaterial));
195 pMaterial->next = NULL;
196 }
197
198 /* generate the mesh structure for the device */
199 ONEbuildMesh(pDevice, xCoordList, domainList, pDevice->pMaterials);
200
201 if (options->OPTNbaseDepthGiven) {
202 /* The base contact depth has been specified in the input. */
203 pDevice->baseIndex = MESHlocate(xCoordList, options->OPTNbaseDepth);
204 } else {
205 pDevice->baseIndex = -1; /* Invalid index acts as a flag */
206 }
207 /* store the device info in the instance */
208 inst->NBJTpDevice = pDevice;
209 }
210 /* Now update the state pointers. */
211 ONEgetStatePointers(inst->NBJTpDevice, states);
212
213 /* Wipe out statistics from previous runs (if any). */
214 memset(inst->NBJTpDevice->pStats, 0, sizeof(ONEstats));
215
216 inst->NBJTpDevice->pStats->totalTime[STAT_SETUP] +=
217 SPfrontEnd->IFseconds() - startTime;
218
219 /* macro to make elements with built in test for out of memory */
220 #define TSTALLOC(ptr,first,second) \
221 do { if ((inst->ptr = SMPmakeElt(matrix, inst->first, inst->second)) == NULL){\
222 return(E_NOMEM);\
223 } } while(0)
224
225 TSTALLOC(NBJTcolColPtr, NBJTcolNode, NBJTcolNode);
226 TSTALLOC(NBJTbaseBasePtr, NBJTbaseNode, NBJTbaseNode);
227 TSTALLOC(NBJTemitEmitPtr, NBJTemitNode, NBJTemitNode);
228 TSTALLOC(NBJTcolBasePtr, NBJTcolNode, NBJTbaseNode);
229 TSTALLOC(NBJTcolEmitPtr, NBJTcolNode, NBJTemitNode);
230 TSTALLOC(NBJTbaseColPtr, NBJTbaseNode, NBJTcolNode);
231 TSTALLOC(NBJTbaseEmitPtr, NBJTbaseNode, NBJTemitNode);
232 TSTALLOC(NBJTemitColPtr, NBJTemitNode, NBJTcolNode);
233 TSTALLOC(NBJTemitBasePtr, NBJTemitNode, NBJTbaseNode);
234 }
235 /* Clean up lists */
236 killCoordInfo(xCoordList);
237 killDomainInfo(domainList);
238 }
239 return (OK);
240 }
241