You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
3.6 KiB
166 lines
3.6 KiB
/**********
|
|
Copyright 1991 Regents of the University of California. All rights reserved.
|
|
Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
|
|
Author: 1991 David A. Gates, U. C. Berkeley CAD Group
|
|
**********/
|
|
|
|
#include "ngspice/ngspice.h"
|
|
#include "ngspice/numglobs.h"
|
|
#include "ngspice/numenum.h"
|
|
#include "ngspice/onemesh.h"
|
|
#include "ngspice/onedev.h"
|
|
#include "ngspice/profile.h"
|
|
#include "ngspice/macros.h"
|
|
#include "onedext.h"
|
|
#include "oneddefs.h"
|
|
#include "ngspice/cidersupt.h"
|
|
|
|
/* functions in this file are used to calculate the conc */
|
|
|
|
double
|
|
ONEdopingValue(DOPprofile *pProfile, DOPtable *pTable, double x)
|
|
{
|
|
double argX, argP, value=0.0;
|
|
|
|
|
|
/* Find the appropriate lookup table if necessary */
|
|
if (pProfile->type == LOOKUP) {
|
|
while (pTable != NULL) {
|
|
if (pTable->impId == pProfile->IMPID) {
|
|
/* Found it */
|
|
break;
|
|
} else {
|
|
pTable = pTable->next;
|
|
}
|
|
}
|
|
if (pTable == NULL) {
|
|
fprintf(stderr, "Error: unknown impurity profile %d\n",
|
|
((int)pProfile->IMPID));
|
|
exit(1);
|
|
}
|
|
}
|
|
/* Find distances */
|
|
if (pProfile->X_LOW > x) {
|
|
argX = pProfile->X_LOW - x;
|
|
} else if (x > pProfile->X_HIGH) {
|
|
argX = x - pProfile->X_HIGH;
|
|
} else {
|
|
argX = 0.0;
|
|
}
|
|
|
|
argP = argX;
|
|
|
|
/* Transform to coordinates of profile peak */
|
|
argP -= pProfile->LOCATION;
|
|
argP /= pProfile->CHAR_LENGTH;
|
|
|
|
switch (pProfile->type) {
|
|
case UNIF:
|
|
if (argP > 0.0) {
|
|
value = 0.0;
|
|
} else {
|
|
value = pProfile->CONC;
|
|
}
|
|
break;
|
|
case LIN:
|
|
argP = ABS(argP);
|
|
if (argP > 1.0) {
|
|
value = 0.0;
|
|
} else {
|
|
value = pProfile->CONC * (1.0 - argP);
|
|
}
|
|
break;
|
|
case GAUSS:
|
|
argP *= argP;
|
|
if (argP > 80.0) {
|
|
value = 0.0;
|
|
} else {
|
|
value = pProfile->PEAK_CONC * exp(-argP);
|
|
}
|
|
case EXP:
|
|
argP = ABS(argP);
|
|
if (argP > 80.0) {
|
|
value = 0.0;
|
|
} else {
|
|
value = pProfile->PEAK_CONC * exp(-argP);
|
|
}
|
|
break;
|
|
case ERRFC:
|
|
argP = ABS(argP);
|
|
if (argP > 10.0) {
|
|
value = 0.0;
|
|
} else {
|
|
value = pProfile->PEAK_CONC * erfc(-argP);
|
|
}
|
|
break;
|
|
case LOOKUP:
|
|
argP = ABS(argP);
|
|
value = lookup(pTable->dopData, argP);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return (value);
|
|
}
|
|
|
|
|
|
void
|
|
ONEsetDoping(ONEdevice *pDevice, DOPprofile *pProfile, DOPtable *pTable)
|
|
{
|
|
ONEnode *pNode;
|
|
ONEelem *pElem;
|
|
DOPprofile *pP;
|
|
double conc;
|
|
int index, eIndex;
|
|
BOOLEAN dopeMe;
|
|
|
|
|
|
/* Clear doping info for all nodes. */
|
|
for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) {
|
|
pElem = pDevice->elemArray[eIndex];
|
|
for (index = 0; index <= 1; index++) {
|
|
if (pElem->evalNodes[index]) {
|
|
pNode = pElem->pNodes[index];
|
|
pNode->na = 0.0;
|
|
pNode->nd = 0.0;
|
|
pNode->netConc = 0.0;
|
|
pNode->totalConc = 0.0;
|
|
}
|
|
}
|
|
}
|
|
/* Now compute the contribution to the total doping from each profile. */
|
|
for (pP = pProfile; pP != NULL; pP = pP->next) {
|
|
for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) {
|
|
pElem = pDevice->elemArray[eIndex];
|
|
if (pElem->elemType == SEMICON) {
|
|
if (pP->numDomains > 0) {
|
|
dopeMe = FALSE;
|
|
for (index = 0; index < pP->numDomains; index++) {
|
|
if (pElem->domain == pP->domains[index]) {
|
|
dopeMe = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
} else { /* domains not given, so dope all */
|
|
dopeMe = TRUE;
|
|
}
|
|
if (dopeMe) {
|
|
for (index = 0; index <= 1; index++) {
|
|
if (pElem->evalNodes[index]) {
|
|
pNode = pElem->pNodes[index];
|
|
conc = ONEdopingValue(pP, pTable, pNode->x);
|
|
pNode->netConc += conc;
|
|
if (conc < 0.0) {
|
|
pNode->totalConc -= conc;
|
|
pNode->na -= conc;
|
|
} else {
|
|
pNode->totalConc += conc;
|
|
pNode->nd += conc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|