1 /**********
2 Copyright 1991 Regents of the University of California. All rights reserved.
3 Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
4 Author: 1991 David A. Gates, U. C. Berkeley CAD Group
5 **********/
6
7 /**********
8 Two-Dimensional Numerical Device Setup Routines
9 **********/
10
11 #include "ngspice/ngspice.h"
12 #include "ngspice/numglobs.h"
13 #include "ngspice/numconst.h"
14 #include "ngspice/numenum.h"
15 #include "ngspice/twomesh.h"
16 #include "ngspice/twodev.h"
17 #include "ngspice/carddefs.h" /* XXX Not really modular if we need this. */
18 #include "twoddefs.h"
19 #include "twodext.h"
20 #include "ngspice/cidersupt.h"
21
22
23 /* compute node parameters */
TWOsetup(TWOdevice * pDevice)24 void TWOsetup(TWOdevice *pDevice)
25 {
26 double temp1, deltaEg, avgConc, totalConc, absNetConc;
27 double ncv0, dBand, dNie, psiBand[4];
28 double *xScale = pDevice->xScale;
29 double *yScale = pDevice->yScale;
30 int index, eIndex;
31 int numContactNodes;
32 TWOnode *pNode;
33 TWOelem *pElem;
34 TWOedge *pEdge;
35 TWOcontact *pC;
36 TWOmaterial *info;
37
38 for ( eIndex = 1; eIndex <= pDevice->numElems; eIndex++ ) {
39 pElem = pDevice->elements[ eIndex ];
40 info = pElem->matlInfo;
41
42 pElem->dx = xScale[ pElem->pTRNode->nodeI ]-xScale[ pElem->pTLNode->nodeI ];
43 pElem->dy = yScale[ pElem->pBLNode->nodeJ ]-yScale[ pElem->pTLNode->nodeJ ];
44 pElem->epsRel = info->eps;
45
46 if ( pElem->elemType == INSULATOR ) {
47 for ( index = 0; index <= 3; index++ ) {
48 if ( pElem->evalNodes[ index ] ) {
49 pNode = pElem->pNodes[ index ];
50 if (pNode->nodeType == CONTACT) {
51 pNode->eaff = PHI_METAL;
52 pNode->eg = 0.0;
53 } else {
54 pNode->eaff = info->affin;
55 pNode->eg = info->eg0;
56 }
57 }
58 }
59 } else if ( pElem->elemType == SEMICON ) {
60 ncv0 = sqrt( info->nc0 ) * sqrt( info->nv0 );
61 for ( index = 0; index <= 3; index++ ) {
62 if ( pElem->evalNodes[ index ] ) {
63 pNode = pElem->pNodes[ index ];
64
65 /* Narrowing of Energy-Band Gap */
66 if (BandGapNarrowing) {
67 absNetConc = ABS( pNode->netConc );
68 if ( pNode->netConc > 0.0 ) {
69 temp1 = log( absNetConc / info->nrefBGN[ELEC] );
70 deltaEg = - info->dEgDn[ELEC] * (temp1 + sqrt(temp1*temp1 + 0.5));
71 pNode->eg = info->eg0 + deltaEg;
72 } else if ( pNode->netConc < 0.0 ) {
73 temp1 = log( absNetConc / info->nrefBGN[HOLE] );
74 deltaEg = - info->dEgDn[HOLE] * (temp1 + sqrt(temp1*temp1 + 0.5));
75 pNode->eg = info->eg0 + deltaEg;
76 } else {
77 pNode->eg = info->eg0;
78 }
79 } else {
80 pNode->eg = info->eg0;
81 }
82 pNode->nie = ncv0 * exp ( -0.5 * pNode->eg / Vt );
83 pNode->eaff = info->affin;
84 /* Save band structure parameter. */
85 psiBand[ index ] = - info->refPsi;
86
87 /* Ionized-Impurity-Scattering Reduction of Carrier Lifetime */
88 if (ConcDepLifetime) {
89 totalConc = pNode->totalConc;
90 temp1 = 1.0 / ( 1.0 + totalConc / info->nrefSRH[ELEC] );
91 pNode->tn = info->tau0[ELEC] * temp1;
92 temp1 = 1.0 / ( 1.0 + totalConc / info->nrefSRH[HOLE] );
93 pNode->tp = info->tau0[HOLE] * temp1;
94 } else {
95 pNode->tn = info->tau0[ELEC];
96 pNode->tp = info->tau0[HOLE];
97 }
98 }
99 }
100
101 for ( index = 0; index <= 3; index++ ) {
102 if ( pElem->evalEdges[ index ] ) {
103 pEdge = pElem->pEdges[ index ];
104
105 /* Fixed Interface Charge */
106 pEdge->qf = 0.0;
107
108 /* Variable Band Built-In Potential */
109 if ( index <= 1 ) {
110 dBand = psiBand[index+1] - psiBand[index];
111 dNie = log( pElem->pNodes[index+1]->nie /
112 pElem->pNodes[index]->nie );
113 pEdge->dCBand = dBand + dNie;
114 pEdge->dVBand = - dBand + dNie;
115 } else {
116 dBand = psiBand[index] - psiBand[(index+1)%4];
117 dNie = log( pElem->pNodes[index]->nie /
118 pElem->pNodes[(index+1)%4]->nie );
119 pEdge->dCBand = dBand + dNie;
120 pEdge->dVBand = - dBand + dNie;
121 }
122 }
123 }
124
125 /* Evaluate conc.-dep. mobility. */
126 /* Average conc of all four nodes. */
127 avgConc = 0.25*(pElem->pTLNode->totalConc + pElem->pTRNode->totalConc +
128 pElem->pBRNode->totalConc + pElem->pBLNode->totalConc);
129 MOBconcDep( info, avgConc, &pElem->mun0, &pElem->mup0 );
130 }
131 }
132
133 for ( pC = pDevice->pFirstContact; pC != NULL; pC = pC->next ) {
134 numContactNodes = pC->numNodes;
135 for ( index = 0; index < numContactNodes; index++ ) {
136 pNode = pC->pNodes[ index ];
137 pNode->eaff = pC->workf; /* Affinity aka work function */
138 }
139 }
140 }
141
142 /* Transfer BC info from card to nodes and edges. */
143 static void
TWOcopyBCinfo(TWOdevice * pDevice,TWOelem * pElem,BDRYcard * card,int index)144 TWOcopyBCinfo(TWOdevice *pDevice, TWOelem *pElem, BDRYcard *card, int index )
145 {
146 TWOnode *pNode;
147 TWOelem *pNElem;
148 TWOedge *pEdge;
149 TWOmaterial *info;
150 TWOchannel *newChannel;
151 int eIndex, nIndex;
152 int direction = index%2;
153 double length, area, width, layerWidth;
154 double dop, na = 0.0, nd = 0.0;
155
156 /* First add fixed charge. */
157 pEdge = pElem->pEdges[index];
158 pEdge->qf += card->BDRYqf;
159
160 /* Now add surface recombination. */
161 if ( direction == 0 ) { /* Horizontal Edge */
162 length = 0.5 * pElem->dx;
163 } else {
164 length = 0.5 * pElem->dy;
165 }
166 for (nIndex = 0; nIndex <= 1; nIndex++) {
167 pNode = pElem->pNodes[ (index+nIndex)%4 ];
168 /* Compute semiconductor area around this node. */
169 area = 0.0;
170 for (eIndex = 0; eIndex <= 3; eIndex++) {
171 pNElem = pNode->pElems[eIndex];
172 if (pNElem != NULL && pElem->elemType == SEMICON) {
173 area += 0.25 * pElem->dx * pElem->dy;
174 }
175 }
176 if (card->BDRYsnGiven) {
177 pNode->tn = pNode->tn /
178 (1.0 + ((card->BDRYsn * TNorm)*length*pNode->tn) / area);
179 }
180 if (card->BDRYspGiven) {
181 pNode->tp = pNode->tp /
182 (1.0 + ((card->BDRYsp * TNorm)*length*pNode->tp) / area);
183 }
184 /* Compute doping just in case we need it later. */
185 na += 0.5 * pNode->na;
186 nd += 0.5 * pNode->nd;
187 }
188
189 /* Finally do surface layer. */
190 pNElem = pElem->pElems[index];
191 if (card->BDRYlayerGiven && SurfaceMobility && pElem->elemType == SEMICON
192 && pElem->channel == 0 && pNElem && pNElem->elemType == INSULATOR
193 && pElem->pNodes[index]->nodeType != CONTACT &&
194 pElem->pNodes[(index+1)%4]->nodeType != CONTACT ) {
195 /* Find the layer width. */
196 layerWidth = card->BDRYlayer;
197 if (card->BDRYlayer <= 0.0) { /* Need to compute extrinsic Debye length */
198 info = pElem->matlInfo;
199 dop = MAX(MAX(na,nd),info->ni0);
200 layerWidth = sqrt((Vt * info->eps) / (CHARGE * dop));
201 }
202
203 /* Add a channel to the list of channels. */
204 XCALLOC( newChannel, TWOchannel, 1);
205 newChannel->pSeed = pElem;
206 newChannel->pNElem = pNElem;
207 newChannel->type = index;
208 if (pDevice->pChannel != NULL) {
209 newChannel->id = pDevice->pChannel->id + 1;
210 newChannel->next = pDevice->pChannel;
211 } else {
212 newChannel->id = 1;
213 newChannel->next = NULL;
214 }
215 pDevice->pChannel = newChannel;
216
217 /* Now add elements to channel until we're more than layerWidth away
218 * from the interface. If we encounter a missing element or an
219 * element that's already part of a different channel, quit.
220 * The seed element is at the surface.
221 */
222 width = 0.0;
223 eIndex = (index+2)%4;
224 pElem->surface = TRUE;
225 while (width < layerWidth && pElem && pElem->channel == 0) {
226 pElem->channel = newChannel->id;
227 pElem->direction = direction;
228 /*
229 * Surface mobility is normally concentration-independent in
230 * the default model. Overwrite concentration-dependent value
231 * calculated earlier unless matching of low-field surface
232 * and bulk mobilities is requested.
233 */
234 if (!MatchingMobility) {
235 pElem->mun0 = pElem->matlInfo->mus[ELEC];
236 pElem->mup0 = pElem->matlInfo->mus[HOLE];
237 }
238 if ( direction == 0 ) {
239 width += pElem->dy;
240 } else {
241 width += pElem->dx;
242 }
243 pElem = pElem->pElems[ eIndex ];
244 }
245 }
246 }
247
248 /* Compute boundary condition parameters. */
TWOsetBCparams(TWOdevice * pDevice,BDRYcard * cardList)249 void TWOsetBCparams(TWOdevice *pDevice, BDRYcard *cardList)
250 {
251 int index, xIndex, yIndex; /* Need to access in X/Y order. */
252 TWOelem *pElem, *pNElem;
253 BDRYcard *card;
254
255 for ( card = cardList; card != NULL; card = card->BDRYnextCard ) {
256 for (xIndex = card->BDRYixLow; xIndex < card->BDRYixHigh; xIndex++) {
257 for (yIndex = card->BDRYiyLow; yIndex < card->BDRYiyHigh; yIndex++) {
258 pElem = pDevice->elemArray[ xIndex ][ yIndex ];
259 if (pElem != NULL) {
260 if (pElem->domain == card->BDRYdomain) {
261 for (index = 0; index <= 3; index++) {
262 if (pElem->evalEdges[index]) {
263 pNElem = pElem->pElems[index];
264 if (card->BDRYneighborGiven) {
265 if (pNElem && pNElem->domain == card->BDRYneighbor) {
266 /* Found an interface edge. */
267 TWOcopyBCinfo( pDevice, pElem, card, index );
268 }
269 } else {
270 if (!pNElem || pNElem->domain != pElem->domain) {
271 /* Found a boundary edge. */
272 TWOcopyBCinfo( pDevice, pElem, card, index );
273 }
274 }
275 }
276 }
277 }
278 }
279 }
280 }
281 }
282 }
283
TWOnormalize(TWOdevice * pDevice)284 void TWOnormalize(TWOdevice *pDevice)
285 {
286 int index, eIndex;
287 TWOelem *pElem;
288 TWOnode *pNode;
289 TWOedge *pEdge;
290
291 for ( eIndex = 1; eIndex <= pDevice->numElems; eIndex++ ) {
292 pElem = pDevice->elements[ eIndex ];
293
294 pElem->dx /= LNorm;
295 pElem->dy /= LNorm;
296 pElem->epsRel /= EpsNorm;
297 for ( index = 0; index <= 3; index++ ) {
298 if ( pElem->evalNodes[ index ] ) {
299 pNode = pElem->pNodes[ index ];
300 pNode->netConc /= NNorm;
301 pNode->nd /= NNorm;
302 pNode->na /= NNorm;
303 pNode->nie /= NNorm;
304 pNode->eg /= VNorm;
305 pNode->eaff /= VNorm;
306 }
307 if ( pElem->evalEdges[ index ] ) {
308 pEdge = pElem->pEdges[ index ];
309 pEdge->qf /= NNorm*LNorm;
310 }
311 }
312 }
313 }
314