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 /* Functions to compute terminal conductances & currents. */ 7 8 #include "ngspice/ngspice.h" 9 #include "ngspice/numglobs.h" 10 #include "ngspice/numenum.h" 11 #include "ngspice/twomesh.h" 12 #include "ngspice/twodev.h" 13 #include "ngspice/bool.h" 14 #include "ngspice/spmatrix.h" 15 #include "twoddefs.h" 16 #include "twodext.h" 17 18 19 void NUMD2conductance(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * gd)20 NUMD2conductance(TWOdevice *pDevice, BOOLEAN tranAnalysis, 21 double *intCoeff, double *gd) 22 { 23 TWOcontact *pContact = pDevice->pFirstContact; 24 double *incVpn; 25 BOOLEAN deltaVContact = FALSE; 26 27 /* 28 * store the new rhs for computing the incremental quantities 29 * with the second to last node. solve the system of equations 30 */ 31 incVpn = pDevice->dcDeltaSolution; 32 storeNewRhs( pDevice, pDevice->pLastContact ); 33 spSolve( pDevice->matrix, pDevice->rhs, incVpn, NULL, NULL); 34 35 incVpn = pDevice->dcDeltaSolution; 36 *gd = contactConductance( pDevice, pContact, deltaVContact, incVpn, 37 tranAnalysis, intCoeff ); 38 *gd *= - GNorm * pDevice->width * LNorm; 39 } 40 41 void NBJT2conductance(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * dIeDVce,double * dIcDVce,double * dIeDVbe,double * dIcDVbe)42 NBJT2conductance(TWOdevice *pDevice, BOOLEAN tranAnalysis, 43 double *intCoeff, double *dIeDVce, double *dIcDVce, 44 double *dIeDVbe, double *dIcDVbe) 45 { 46 TWOcontact *pEmitContact = pDevice->pLastContact; 47 TWOcontact *pColContact = pDevice->pFirstContact; 48 TWOcontact *pBaseContact = pDevice->pFirstContact->next; 49 double width = pDevice->width; 50 double *incVce, *incVbe; 51 52 /* 53 * store the new rhs for computing the incremental quantities 54 * incVce (dcDeltaSolution) and incVbe (copiedSolution) are used to 55 * store the incremental quantities associated with Vce and Vbe 56 */ 57 58 incVce = pDevice->dcDeltaSolution; 59 incVbe = pDevice->copiedSolution; 60 storeNewRhs( pDevice, pColContact ); 61 spSolve( pDevice->matrix, pDevice->rhs, incVce, NULL, NULL); 62 storeNewRhs( pDevice, pBaseContact ); 63 spSolve( pDevice->matrix, pDevice->rhs, incVbe, NULL, NULL); 64 65 *dIeDVce = contactConductance( pDevice, pEmitContact, FALSE, incVce, 66 tranAnalysis, intCoeff ); 67 *dIeDVbe = contactConductance( pDevice, pEmitContact, FALSE, incVbe, 68 tranAnalysis, intCoeff ); 69 70 *dIcDVce = contactConductance( pDevice, pColContact, TRUE, incVce, 71 tranAnalysis, intCoeff ); 72 *dIcDVbe = contactConductance( pDevice, pColContact, FALSE, incVbe, 73 tranAnalysis, intCoeff ); 74 *dIeDVce *= GNorm * width * LNorm; 75 *dIcDVce *= GNorm * width * LNorm; 76 *dIeDVbe *= GNorm * width * LNorm; 77 *dIcDVbe *= GNorm * width * LNorm; 78 } 79 80 void NUMOSconductance(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,struct mosConductances * dIdV)81 NUMOSconductance(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff, 82 struct mosConductances *dIdV) 83 { 84 TWOcontact *pDContact = pDevice->pFirstContact; 85 TWOcontact *pGContact = pDevice->pFirstContact->next; 86 TWOcontact *pSContact = pDevice->pFirstContact->next->next; 87 double width = pDevice->width; 88 double *incVdb, *incVsb, *incVgb; 89 90 /* 91 * store the new rhs for computing the incremental quantities 92 * incVdb (dcDeltaSolution) 93 */ 94 95 incVdb = pDevice->dcDeltaSolution; 96 incVsb = pDevice->copiedSolution; 97 incVgb = pDevice->rhsImag; 98 storeNewRhs( pDevice, pDContact ); 99 spSolve( pDevice->matrix, pDevice->rhs, incVdb, NULL, NULL); 100 storeNewRhs( pDevice, pSContact ); 101 spSolve( pDevice->matrix, pDevice->rhs, incVsb, NULL, NULL); 102 storeNewRhs( pDevice, pGContact ); 103 spSolve( pDevice->matrix, pDevice->rhs, incVgb, NULL, NULL); 104 105 dIdV->dIdDVdb = contactConductance( pDevice, pDContact, TRUE, 106 incVdb, tranAnalysis, intCoeff ); 107 dIdV->dIsDVdb = contactConductance( pDevice, pSContact, FALSE, 108 incVdb, tranAnalysis, intCoeff ); 109 dIdV->dIgDVdb = GateTypeConductance( pDevice, pGContact, FALSE, 110 incVdb, tranAnalysis, intCoeff ); 111 dIdV->dIdDVsb = contactConductance( pDevice, pDContact, FALSE, 112 incVsb, tranAnalysis, intCoeff ); 113 dIdV->dIsDVsb = contactConductance( pDevice, pSContact, TRUE, 114 incVsb, tranAnalysis, intCoeff ); 115 dIdV->dIgDVsb = GateTypeConductance( pDevice, pGContact, FALSE, 116 incVsb, tranAnalysis, intCoeff ); 117 dIdV->dIdDVgb = contactConductance( pDevice, pDContact, FALSE, 118 incVgb, tranAnalysis, intCoeff ); 119 dIdV->dIsDVgb = contactConductance( pDevice, pSContact, FALSE, 120 incVgb, tranAnalysis, intCoeff ); 121 dIdV->dIgDVgb = GateTypeConductance( pDevice, pGContact, TRUE, 122 incVgb, tranAnalysis, intCoeff ); 123 124 dIdV->dIdDVdb *= GNorm * width * LNorm; 125 dIdV->dIdDVsb *= GNorm * width * LNorm; 126 dIdV->dIdDVgb *= GNorm * width * LNorm; 127 dIdV->dIsDVdb *= GNorm * width * LNorm; 128 dIdV->dIsDVsb *= GNorm * width * LNorm; 129 dIdV->dIsDVgb *= GNorm * width * LNorm; 130 dIdV->dIgDVdb *= GNorm * width * LNorm; 131 dIdV->dIgDVsb *= GNorm * width * LNorm; 132 dIdV->dIgDVgb *= GNorm * width * LNorm; 133 134 } 135 136 double contactCurrent(TWOdevice * pDevice,TWOcontact * pContact)137 contactCurrent(TWOdevice *pDevice, TWOcontact *pContact) 138 { 139 /* computes the current through the contact given in pContact */ 140 int index, i, numContactNodes; 141 TWOnode *pNode; 142 TWOelem *pElem; 143 TWOedge *pHEdge, *pVEdge; 144 double dx, dy; 145 double jTotal = 0.0; 146 147 numContactNodes = pContact->numNodes; 148 for ( index = 0; index < numContactNodes; index++ ) { 149 pNode = pContact->pNodes[ index ]; 150 for ( i = 0; i <= 3; i++ ) { 151 pElem = pNode->pElems[ i ]; 152 if ( pElem != NULL ) { 153 dx = 0.5 * pElem->dx; 154 dy = 0.5 * pElem->dy; 155 switch ( i ) { 156 case 0: 157 /* Bottom Right node */ 158 pHEdge = pElem->pBotEdge; 159 pVEdge = pElem->pRightEdge; 160 jTotal += pElem->epsRel * ( -dy * pHEdge->jd - dx * pVEdge->jd ); 161 if ( pElem->elemType == SEMICON ) { 162 jTotal += -dy * (pHEdge->jn + pHEdge->jp) 163 -dx * (pVEdge->jn + pVEdge->jp); 164 } 165 break; 166 case 1: 167 /* Bottom Left node */ 168 pHEdge = pElem->pBotEdge; 169 pVEdge = pElem->pLeftEdge; 170 jTotal += pElem->epsRel * ( dy * pHEdge->jd - dx * pVEdge->jd ); 171 if ( pElem->elemType == SEMICON ) { 172 jTotal += dy * (pHEdge->jn + pHEdge->jp) 173 -dx * (pVEdge->jn + pVEdge->jp); 174 } 175 break; 176 case 2: 177 /* Top Left node */ 178 pHEdge = pElem->pTopEdge; 179 pVEdge = pElem->pLeftEdge; 180 jTotal += pElem->epsRel * ( dy * pHEdge->jd + dx * pVEdge->jd ); 181 if ( pElem->elemType == SEMICON ) { 182 jTotal += dy * (pHEdge->jn + pHEdge->jp) 183 + dx * (pVEdge->jn + pVEdge->jp); 184 } 185 break; 186 case 3: 187 /* Top Right Node */ 188 pHEdge = pElem->pTopEdge; 189 pVEdge = pElem->pRightEdge; 190 jTotal += pElem->epsRel * ( -dy * pHEdge->jd + dx * pVEdge->jd ); 191 if ( pElem->elemType == SEMICON ) { 192 jTotal += -dy * (pHEdge->jn + pHEdge->jp) 193 + dx * (pVEdge->jn + pVEdge->jp); 194 } 195 break; 196 } 197 } 198 } 199 } 200 201 return( jTotal * pDevice->width * LNorm * JNorm ); 202 } 203 204 double oxideCurrent(TWOdevice * pDevice,TWOcontact * pContact,BOOLEAN tranAnalysis)205 oxideCurrent(TWOdevice *pDevice, TWOcontact *pContact, 206 BOOLEAN tranAnalysis) 207 { 208 /* computes the current through the contact given in pContact */ 209 int index, i, numContactNodes; 210 TWOnode *pNode; 211 TWOelem *pElem; 212 TWOedge *pHEdge, *pVEdge; 213 double dx, dy; 214 double jTotal = 0.0; 215 216 if ( !tranAnalysis ) { 217 return( jTotal ); 218 } 219 220 numContactNodes = pContact->numNodes; 221 for ( index = 0; index < numContactNodes; index++ ) { 222 pNode = pContact->pNodes[ index ]; 223 for ( i = 0; i <= 3; i++ ) { 224 pElem = pNode->pElems[ i ]; 225 if ( pElem != NULL ) { 226 dx = 0.5 * pElem->dx; 227 dy = 0.5 * pElem->dy; 228 switch ( i ) { 229 case 0: 230 /* Bottom Right node */ 231 pHEdge = pElem->pBotEdge; 232 pVEdge = pElem->pRightEdge; 233 jTotal += pElem->epsRel * ( -dy * pHEdge->jd - dx * pVEdge->jd ); 234 break; 235 case 1: 236 /* Bottom Left node */ 237 pHEdge = pElem->pBotEdge; 238 pVEdge = pElem->pLeftEdge; 239 jTotal += pElem->epsRel * ( dy * pHEdge->jd - dx * pVEdge->jd ); 240 break; 241 case 2: 242 /* Top Left node */ 243 pHEdge = pElem->pTopEdge; 244 pVEdge = pElem->pLeftEdge; 245 jTotal += pElem->epsRel * ( dy * pHEdge->jd + dx * pVEdge->jd ); 246 break; 247 case 3: 248 /* Top Right Node */ 249 pHEdge = pElem->pTopEdge; 250 pVEdge = pElem->pRightEdge; 251 jTotal += pElem->epsRel * ( -dy * pHEdge->jd + dx * pVEdge->jd ); 252 break; 253 } 254 } 255 } 256 } 257 258 return( jTotal * pDevice->width * LNorm * JNorm ); 259 } 260 261 262 double contactConductance(TWOdevice * pDevice,TWOcontact * pContact,BOOLEAN delVContact,double * dxDv,BOOLEAN tranAnalysis,double * intCoeff)263 contactConductance(TWOdevice *pDevice, TWOcontact *pContact, 264 BOOLEAN delVContact, double *dxDv, 265 BOOLEAN tranAnalysis, double *intCoeff) 266 { 267 /* computes the conductance of the contact given in pContact */ 268 int index, i, numContactNodes; 269 TWOnode *pNode, *pHNode = NULL, *pVNode = NULL; 270 TWOelem *pElem; 271 TWOedge *pHEdge = NULL, *pVEdge = NULL; 272 double dPsiDv, dnDv, dpDv; 273 double gTotal = 0.0; 274 int nInc, pInc; 275 276 NG_IGNORE(pDevice); 277 278 /* for one carrier the rest of this code relies on appropriate 279 current derivative term to be zero */ 280 if ( !OneCarrier ) { 281 nInc = 1; 282 pInc = 2; 283 } else { 284 nInc = 1; 285 pInc = 1; 286 } 287 288 numContactNodes = pContact->numNodes; 289 for ( index = 0; index < numContactNodes; index++ ) { 290 pNode = pContact->pNodes[ index ]; 291 for ( i = 0; i <= 3; i++ ) { 292 pElem = pNode->pElems[ i ]; 293 if ( pElem != NULL ) { 294 switch ( i ) { 295 case 0: 296 /* the TL element */ 297 pHNode = pElem->pBLNode; 298 pVNode = pElem->pTRNode; 299 pHEdge = pElem->pBotEdge; 300 pVEdge = pElem->pRightEdge; 301 if ( pElem->elemType == SEMICON ) { 302 /* compute the derivatives with n,p */ 303 if ( pHNode->nodeType != CONTACT ) { 304 dnDv = dxDv[ pHNode->nEqn ]; 305 dpDv = dxDv[ pHNode->pEqn ]; 306 gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDn * dnDv 307 + pHEdge->dJpDp * dpDv); 308 } 309 if ( pVNode->nodeType != CONTACT ) { 310 dnDv = dxDv[ pVNode->nEqn ]; 311 dpDv = dxDv[ pVNode->pEqn ]; 312 gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDn * dnDv 313 + pVEdge->dJpDp * dpDv); 314 } 315 } 316 break; 317 case 1: 318 /* the TR element */ 319 pHNode = pElem->pBRNode; 320 pVNode = pElem->pTLNode; 321 pHEdge = pElem->pBotEdge; 322 pVEdge = pElem->pLeftEdge; 323 if ( pElem->elemType == SEMICON ) { 324 /* compute the derivatives with n,p */ 325 if ( pHNode->nodeType != CONTACT ) { 326 dnDv = dxDv[ pHNode->nEqn ]; 327 dpDv = dxDv[ pHNode->pEqn ]; 328 gTotal += 0.5 * pElem->dy * (pHEdge->dJnDnP1 * dnDv 329 + pHEdge->dJpDpP1 * dpDv); 330 } 331 if ( pVNode->nodeType != CONTACT ) { 332 dnDv = dxDv[ pVNode->nEqn ]; 333 dpDv = dxDv[ pVNode->pEqn ]; 334 gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDn * dnDv 335 + pVEdge->dJpDp * dpDv); 336 } 337 } 338 break; 339 case 2: 340 /* the BR element*/ 341 pHNode = pElem->pTRNode; 342 pVNode = pElem->pBLNode; 343 pHEdge = pElem->pTopEdge; 344 pVEdge = pElem->pLeftEdge; 345 if ( pElem->elemType == SEMICON ) { 346 /* compute the derivatives with n,p */ 347 if ( pHNode->nodeType != CONTACT ) { 348 dnDv = dxDv[ pHNode->nEqn ]; 349 dpDv = dxDv[ pHNode->pEqn ]; 350 gTotal += 0.5 * pElem->dy * (pHEdge->dJnDnP1 * dnDv 351 + pHEdge->dJpDpP1 * dpDv); 352 } 353 if ( pVNode->nodeType != CONTACT ) { 354 dnDv = dxDv[ pVNode->nEqn ]; 355 dpDv = dxDv[ pVNode->pEqn ]; 356 gTotal += 0.5 * pElem->dx * (pVEdge->dJnDnP1 * dnDv 357 + pVEdge->dJpDpP1 * dpDv); 358 } 359 } 360 break; 361 case 3: 362 /* the BL element */ 363 pHNode = pElem->pTLNode; 364 pVNode = pElem->pBRNode; 365 pHEdge = pElem->pTopEdge; 366 pVEdge = pElem->pRightEdge; 367 if ( pElem->elemType == SEMICON ) { 368 /* compute the derivatives with n,p */ 369 if ( pHNode->nodeType != CONTACT ) { 370 dnDv = dxDv[ pHNode->nEqn ]; 371 dpDv = dxDv[ pHNode->pEqn ]; 372 gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDn * dnDv 373 + pHEdge->dJpDp * dpDv); 374 } 375 if ( pVNode->nodeType != CONTACT ) { 376 dnDv = dxDv[ pVNode->nEqn ]; 377 dpDv = dxDv[ pVNode->pEqn ]; 378 gTotal += 0.5 * pElem->dx * (pVEdge->dJnDnP1 * dnDv 379 + pVEdge->dJpDpP1 * dpDv); 380 } 381 } 382 break; 383 } 384 if ( pElem->elemType == SEMICON ) { 385 if ( pHNode->nodeType != CONTACT ) { 386 dPsiDv = dxDv[ pHNode->psiEqn ]; 387 gTotal += 0.5 * pElem->dy * dPsiDv * (pHEdge->dJnDpsiP1 + pHEdge->dJpDpsiP1 ); 388 if ( delVContact ) { 389 gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDpsiP1 + pHEdge->dJpDpsiP1 ); 390 } 391 } 392 if ( pVNode->nodeType != CONTACT ) { 393 dPsiDv = dxDv[ pVNode->psiEqn ]; 394 gTotal += 0.5 * pElem->dx * dPsiDv * (pVEdge->dJnDpsiP1 + pVEdge->dJpDpsiP1 ); 395 if ( delVContact ) { 396 gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDpsiP1 + pVEdge->dJpDpsiP1 ); 397 } 398 } 399 } 400 if ( tranAnalysis ) { 401 /* add the displacement current terms */ 402 if ( pHNode->nodeType != CONTACT ) { 403 dPsiDv = dxDv[ pHNode->psiEqn ]; 404 gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx * dPsiDv; 405 if ( delVContact ) { 406 gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx; 407 } 408 } 409 if ( pVNode->nodeType != CONTACT ) { 410 dPsiDv = dxDv[ pVNode->psiEqn ]; 411 gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy * dPsiDv; 412 if ( delVContact ) { 413 gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy; 414 } 415 } 416 } 417 } 418 } 419 } 420 421 return( gTotal ); 422 } 423 424 425 double oxideConductance(TWOdevice * pDevice,TWOcontact * pContact,BOOLEAN delVContact,double * dxDv,BOOLEAN tranAnalysis,double * intCoeff)426 oxideConductance(TWOdevice *pDevice, TWOcontact *pContact, 427 BOOLEAN delVContact, double *dxDv, 428 BOOLEAN tranAnalysis, double *intCoeff) 429 { 430 /* computes the conductance of the contact given in pContact */ 431 int index, i, numContactNodes; 432 TWOnode *pNode, *pHNode = NULL, *pVNode = NULL; 433 TWOelem *pElem; 434 double dPsiDv; 435 double gTotal = 0.0; 436 437 NG_IGNORE(pDevice); 438 439 if ( !tranAnalysis ) { 440 return( gTotal ); 441 } 442 443 numContactNodes = pContact->numNodes; 444 for ( index = 0; index < numContactNodes; index++ ) { 445 pNode = pContact->pNodes[ index ]; 446 for ( i = 0; i <= 3; i++ ) { 447 pElem = pNode->pElems[ i ]; 448 if ( pElem != NULL ) { 449 switch ( i ) { 450 case 0: 451 /* the TL element */ 452 pHNode = pElem->pBLNode; 453 pVNode = pElem->pTRNode; 454 break; 455 case 1: 456 /* the TR element */ 457 pHNode = pElem->pBRNode; 458 pVNode = pElem->pTLNode; 459 break; 460 case 2: 461 /* the BR element*/ 462 pHNode = pElem->pTRNode; 463 pVNode = pElem->pBLNode; 464 break; 465 case 3: 466 /* the BL element */ 467 pHNode = pElem->pTLNode; 468 pVNode = pElem->pBRNode; 469 break; 470 } 471 /* add the displacement current terms */ 472 if ( pHNode->nodeType != CONTACT ) { 473 dPsiDv = dxDv[ pHNode->psiEqn ]; 474 gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx * dPsiDv; 475 if ( delVContact ) { 476 gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx; 477 } 478 } 479 if ( pVNode->nodeType != CONTACT ) { 480 dPsiDv = dxDv[ pVNode->psiEqn ]; 481 gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy * dPsiDv; 482 if ( delVContact ) { 483 gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy; 484 } 485 } 486 } 487 } 488 } 489 490 return( gTotal ); 491 } 492 493 /* these functions are used for solving the complete system of 494 * equations directly using LU decomposition 1/22/88 495 */ 496 497 void NUMD2current(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * id)498 NUMD2current(TWOdevice *pDevice, BOOLEAN tranAnalysis, 499 double *intCoeff, double *id) 500 { 501 TWOcontact *pPContact = pDevice->pFirstContact; 502 /* TWOcontact *pNContact = pDevice->pLastContact; */ 503 double ip, ipPrime, *solution; 504 /* double in;*/ 505 BOOLEAN deltaVContact = FALSE; 506 507 solution = pDevice->dcDeltaSolution; 508 ip = contactCurrent( pDevice, pPContact ); 509 /* 510 in = contactCurrent( pDevice, pNContact ); 511 fprintf(stdout, "DIO current: ( %11.4e error )\n", ip+in ); 512 fprintf(stdout, " Ip = %11.4e In = %11.4e\n", ip, in ); 513 */ 514 515 /* 516 * for the additional contribution to id will make use of 517 * contactConductance. This function will be called 518 * with the dcDeltaSolution vector instead of the incremental quantities 519 */ 520 ipPrime = contactConductance( pDevice, pPContact, deltaVContact, 521 solution, tranAnalysis, intCoeff ); 522 523 ipPrime *= JNorm * pDevice->width * LNorm; 524 ip += ipPrime; 525 *id = ip; 526 } 527 528 void NBJT2current(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * ie,double * ic)529 NBJT2current(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff, 530 double *ie, double *ic) 531 { 532 TWOcontact *pEmitContact = pDevice->pLastContact; 533 TWOcontact *pColContact = pDevice->pFirstContact; 534 /* TWOcontact *pBaseContact = pDevice->pFirstContact->next; */ 535 double *solution, iePrime, icPrime; 536 /* double ib; */ 537 538 solution = pDevice->dcDeltaSolution; 539 540 *ie = contactCurrent( pDevice, pEmitContact ); 541 *ic = contactCurrent( pDevice, pColContact ); 542 /* 543 ib = contactCurrent( pDevice, pBaseContact ); 544 fprintf(stdout, "BJT current: ( %11.4e error )\n", *ic+ib+*ie ); 545 fprintf(stdout, " Ic = %11.4e Ib = %11.4e\n", *ic, ib ); 546 fprintf(stdout, " Ie = %11.4e\n", *ie ); 547 */ 548 549 iePrime = contactConductance( pDevice, pEmitContact, FALSE, solution, 550 tranAnalysis, intCoeff ); 551 552 icPrime = contactConductance( pDevice, pColContact, FALSE, solution, 553 tranAnalysis, intCoeff ); 554 555 iePrime *= JNorm * pDevice->width * LNorm; 556 icPrime *= JNorm * pDevice->width * LNorm; 557 558 *ie += iePrime; 559 *ic += icPrime; 560 } 561 562 void NUMOScurrent(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * id,double * is,double * ig)563 NUMOScurrent(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff, 564 double *id, double *is, double *ig) 565 { 566 TWOcontact *pDContact = pDevice->pFirstContact; 567 TWOcontact *pGContact = pDevice->pFirstContact->next; 568 TWOcontact *pSContact = pDevice->pFirstContact->next->next; 569 /* TWOcontact *pBContact = pDevice->pLastContact; */ 570 double *solution, idPrime, isPrime, igPrime; 571 /* double ib; */ 572 573 solution = pDevice->dcDeltaSolution; 574 575 *id = contactCurrent( pDevice, pDContact ); 576 577 /* 578 * This is a terrible hack 579 */ 580 581 #ifdef NORMAL_GATE 582 *ig = GateTypeCurrent( pDevice, pGContact, tranAnalysis ); 583 #else 584 *ig = GateTypeCurrent( pDevice, pGContact); 585 #endif 586 587 *is = contactCurrent( pDevice, pSContact ); 588 /* 589 ib = contactCurrent( pDevice, pBContact ); 590 fprintf(stdout, "MOS current: ( %11.4e error )\n", *id+*ig+*is+ib ); 591 fprintf(stdout, " Id = %11.4e Is = %11.4e\n", *id, *is ); 592 fprintf(stdout, " Ig = %11.4e Ib = %11.4e\n", *ig, ib ); 593 */ 594 595 idPrime = contactConductance( pDevice, pDContact, FALSE, 596 solution, tranAnalysis, intCoeff ); 597 598 isPrime = contactConductance( pDevice, pSContact, FALSE, 599 solution, tranAnalysis, intCoeff ); 600 601 igPrime = GateTypeConductance( pDevice, pGContact, FALSE, 602 solution, tranAnalysis, intCoeff ); 603 604 idPrime *= JNorm * pDevice->width * LNorm; 605 isPrime *= JNorm * pDevice->width * LNorm; 606 igPrime *= JNorm * pDevice->width * LNorm; 607 608 *id += idPrime; 609 *is += isPrime; 610 *ig += igPrime; 611 } 612