287 lines
8.5 KiB
C
287 lines
8.5 KiB
C
/**********
|
|
Copyright 1991 Regents of the University of California. All rights reserved.
|
|
Author: 1991 David A. Gates, U. C. Berkeley CAD Group
|
|
Modified: 2001 Paolo Nenzi
|
|
**********/
|
|
|
|
#include "ngspice/ngspice.h"
|
|
#include "ngspice/numcards.h"
|
|
#include "ngspice/numgen.h"
|
|
#include "ngspice/dopdefs.h"
|
|
#include "ngspice/devdefs.h"
|
|
#include "ngspice/sperror.h"
|
|
#include "ngspice/suffix.h"
|
|
|
|
#define UM_TO_CM 1.0e-4
|
|
|
|
extern int DOPnewCard(GENcard**,GENmodel*);
|
|
extern int DOPparam(int,IFvalue*,GENcard*);
|
|
|
|
|
|
IFparm DOPpTable[] = {
|
|
IP("domains", DOP_DOMAIN, IF_INTVEC, "Domain(s) to dope"),
|
|
IP("uniform", DOP_UNIF, IF_FLAG, "Uniform doping"),
|
|
IP("linear", DOP_LINEAR, IF_FLAG, "Linear graded doping"),
|
|
IP("gaussian",DOP_GAUSS, IF_FLAG, "Gaussian doping"),
|
|
IP("gdiff", DOP_GAUSS, IF_FLAG, "Gaussian diffusion"),
|
|
IP("gimp", DOP_GAUSS, IF_FLAG, "Gaussian implantation"),
|
|
IP("erfc", DOP_ERFC, IF_FLAG, "Error-function doping"),
|
|
IP("errfc", DOP_ERFC, IF_FLAG, "Error-function doping"),
|
|
IP("exponential",DOP_EXP, IF_FLAG, "Exponential doping"),
|
|
IP("suprem3", DOP_SUPREM3, IF_FLAG, "Suprem3 doping"),
|
|
IP("ascii", DOP_ASCII, IF_FLAG, "Ascii-input doping"),
|
|
IP("infile", DOP_INFILE, IF_STRING, "Input-file name"),
|
|
IP("lat.rotate",DOP_ROTATE_LAT,IF_FLAG, "Rotate principal profile"),
|
|
IP("lat.unif",DOP_UNIF_LAT, IF_FLAG, "Uniform lateral falloff"),
|
|
IP("lat.linf",DOP_LINEAR_LAT, IF_FLAG, "Linear lateral falloff"),
|
|
IP("lat.gauss",DOP_GAUSS_LAT, IF_FLAG, "Gaussian lateral falloff"),
|
|
IP("lat.erfc",DOP_ERFC_LAT, IF_FLAG, "Erfc lateral falloff"),
|
|
IP("lat.exp", DOP_EXP_LAT, IF_FLAG, "Exponential lateral falloff"),
|
|
IP("boron", DOP_BORON, IF_FLAG, "Boron impurities"),
|
|
IP("phosphorus",DOP_PHOSP, IF_FLAG, "Phosphorus impurities"),
|
|
IP("arsenic", DOP_ARSEN, IF_FLAG, "Arsenic impurities"),
|
|
IP("antimony",DOP_ANTIM, IF_FLAG, "Antimony impurities"),
|
|
IP("p.type", DOP_P_TYPE, IF_FLAG, "P-type impurities"),
|
|
IP("acceptor",DOP_P_TYPE, IF_FLAG, "Acceptor impurities"),
|
|
IP("n.type", DOP_N_TYPE, IF_FLAG, "N-type impurities"),
|
|
IP("donor", DOP_N_TYPE, IF_FLAG, "Donor impurities"),
|
|
IP("x.axis", DOP_X_AXIS, IF_FLAG, "X principal axis"),
|
|
IP("y.axis", DOP_Y_AXIS, IF_FLAG, "Y principal axis"),
|
|
IP("x.low", DOP_X_LOW, IF_REAL, "Low X edge"),
|
|
IP("x.high", DOP_X_HIGH, IF_REAL, "High X edge"),
|
|
IP("y.low", DOP_Y_LOW, IF_REAL, "Low Y edge"),
|
|
IP("y.high", DOP_Y_HIGH, IF_REAL, "High Y edge"),
|
|
IP("conc", DOP_CONC, IF_REAL, "Concentration"),
|
|
IP("peak.conc",DOP_CONC, IF_REAL, "Peak concentration"),
|
|
IP("location",DOP_LOCATION, IF_REAL, "Peak location"),
|
|
IP("range", DOP_LOCATION, IF_REAL, "Peak location"),
|
|
IP("char.length",DOP_CHAR_LEN,IF_REAL, "Characteristic length"),
|
|
IP("ratio.lat",DOP_RATIO_LAT, IF_REAL, "Lateral ratio")
|
|
};
|
|
|
|
IFcardInfo DOPinfo = {
|
|
"doping",
|
|
"Add dopant to domains of a device",
|
|
NUMELEMS(DOPpTable),
|
|
DOPpTable,
|
|
|
|
DOPnewCard,
|
|
DOPparam,
|
|
NULL
|
|
};
|
|
|
|
int
|
|
DOPnewCard(GENcard **inCard, GENmodel *inModel)
|
|
{
|
|
DOPcard *tmpCard, *newCard;
|
|
GENnumModel *model = (GENnumModel *)inModel;
|
|
|
|
newCard = TMALLOC(DOPcard, 1);
|
|
if (!newCard) {
|
|
*inCard = NULL;
|
|
return(E_NOMEM);
|
|
}
|
|
newCard->DOPnextCard = NULL;
|
|
*inCard = (GENcard *) newCard;
|
|
|
|
tmpCard = model->GENdopings;
|
|
if (!tmpCard) { /* First in list */
|
|
model->GENdopings = newCard;
|
|
} else {
|
|
/* Go to end of list */
|
|
while (tmpCard->DOPnextCard) tmpCard = tmpCard->DOPnextCard;
|
|
/* And add new card */
|
|
tmpCard->DOPnextCard = newCard;
|
|
}
|
|
return(OK);
|
|
}
|
|
|
|
|
|
int
|
|
DOPparam(int param, IFvalue *value, GENcard *inCard)
|
|
{
|
|
int i;
|
|
DOPcard *card = (DOPcard *)inCard;
|
|
|
|
switch (param) {
|
|
case DOP_DOMAIN:
|
|
if ( !card->DOPdomainsGiven ) {
|
|
card->DOPnumDomains = value->v.numValue;
|
|
card->DOPdomains = TMALLOC(int, value->v.numValue);
|
|
for ( i=0; i < card->DOPnumDomains; i++ ) {
|
|
card->DOPdomains[i] = value->v.vec.iVec[i];
|
|
}
|
|
card->DOPdomainsGiven = TRUE;
|
|
} /* else: do nothing, can only define domains once */
|
|
break;
|
|
case DOP_ROTATE_LAT:
|
|
card->DOProtateLat = TRUE;
|
|
card->DOProtateLatGiven = TRUE;
|
|
break;
|
|
case DOP_UNIF:
|
|
if ( !card->DOPprofileTypeGiven ) {
|
|
card->DOPprofileType = DOP_UNIF;
|
|
card->DOPprofileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_UNIF_LAT:
|
|
if ( !card->DOPlatProfileTypeGiven ) {
|
|
card->DOPlatProfileType = DOP_UNIF;
|
|
card->DOPlatProfileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_LINEAR:
|
|
if ( !card->DOPprofileTypeGiven ) {
|
|
card->DOPprofileType = DOP_LINEAR;
|
|
card->DOPprofileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_LINEAR_LAT:
|
|
if ( !card->DOPlatProfileTypeGiven ) {
|
|
card->DOPlatProfileType = DOP_LINEAR_LAT;
|
|
card->DOPlatProfileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_GAUSS:
|
|
if ( !card->DOPprofileTypeGiven ) {
|
|
card->DOPprofileType = DOP_GAUSS;
|
|
card->DOPprofileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_GAUSS_LAT:
|
|
if ( !card->DOPlatProfileTypeGiven ) {
|
|
card->DOPlatProfileType = DOP_GAUSS;
|
|
card->DOPlatProfileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_ERFC:
|
|
if ( !card->DOPprofileTypeGiven ) {
|
|
card->DOPprofileType = DOP_ERFC;
|
|
card->DOPprofileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_ERFC_LAT:
|
|
if ( !card->DOPlatProfileTypeGiven ) {
|
|
card->DOPlatProfileType = DOP_ERFC;
|
|
card->DOPlatProfileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_EXP:
|
|
if ( !card->DOPprofileTypeGiven ) {
|
|
card->DOPprofileType = DOP_EXP;
|
|
card->DOPprofileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_EXP_LAT:
|
|
if ( !card->DOPlatProfileTypeGiven ) {
|
|
card->DOPlatProfileType = DOP_EXP;
|
|
card->DOPlatProfileTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_SUPREM3:
|
|
if ( !card->DOPprofileTypeGiven ) {
|
|
card->DOPprofileType = DOP_SUPREM3;
|
|
card->DOPprofileTypeGiven = TRUE;
|
|
} else if ( card->DOPprofileType == DOP_ASCII ) {
|
|
card->DOPprofileType = DOP_SUPASCII;
|
|
}
|
|
break;
|
|
case DOP_ASCII:
|
|
if ( !card->DOPprofileTypeGiven ) {
|
|
card->DOPprofileType = DOP_ASCII;
|
|
card->DOPprofileTypeGiven = TRUE;
|
|
} else if ( card->DOPprofileType == DOP_SUPREM3 ) {
|
|
card->DOPprofileType = DOP_SUPASCII;
|
|
}
|
|
break;
|
|
case DOP_BORON:
|
|
if ( !card->DOPimpurityTypeGiven ) {
|
|
card->DOPimpurityType = DOP_BORON;
|
|
card->DOPimpurityTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_PHOSP:
|
|
if ( !card->DOPimpurityTypeGiven ) {
|
|
card->DOPimpurityType = DOP_PHOSP;
|
|
card->DOPimpurityTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_ARSEN:
|
|
if ( !card->DOPimpurityTypeGiven ) {
|
|
card->DOPimpurityType = DOP_ARSEN;
|
|
card->DOPimpurityTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_ANTIM:
|
|
if ( !card->DOPimpurityTypeGiven ) {
|
|
card->DOPimpurityType = DOP_ANTIM;
|
|
card->DOPimpurityTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_P_TYPE:
|
|
if ( !card->DOPimpurityTypeGiven ) {
|
|
card->DOPimpurityType = DOP_P_TYPE;
|
|
card->DOPimpurityTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_N_TYPE:
|
|
if ( !card->DOPimpurityTypeGiven ) {
|
|
card->DOPimpurityType = DOP_N_TYPE;
|
|
card->DOPimpurityTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_X_AXIS:
|
|
if ( !card->DOPaxisTypeGiven ) {
|
|
card->DOPaxisType = DOP_X_AXIS;
|
|
card->DOPaxisTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_Y_AXIS:
|
|
if ( !card->DOPaxisTypeGiven ) {
|
|
card->DOPaxisType = DOP_Y_AXIS;
|
|
card->DOPaxisTypeGiven = TRUE;
|
|
}
|
|
break;
|
|
case DOP_INFILE:
|
|
card->DOPinFile = value->sValue;
|
|
card->DOPinFileGiven = TRUE;
|
|
break;
|
|
case DOP_X_LOW:
|
|
card->DOPxLow = value->rValue * UM_TO_CM;
|
|
card->DOPxLowGiven = TRUE;
|
|
break;
|
|
case DOP_X_HIGH:
|
|
card->DOPxHigh = value->rValue * UM_TO_CM;
|
|
card->DOPxHighGiven = TRUE;
|
|
break;
|
|
case DOP_Y_LOW:
|
|
card->DOPyLow = value->rValue * UM_TO_CM;
|
|
card->DOPyLowGiven = TRUE;
|
|
break;
|
|
case DOP_Y_HIGH:
|
|
card->DOPyHigh = value->rValue * UM_TO_CM;
|
|
card->DOPyHighGiven = TRUE;
|
|
break;
|
|
case DOP_CONC:
|
|
card->DOPconc = fabs(value->rValue);
|
|
card->DOPconcGiven = TRUE;
|
|
break;
|
|
case DOP_LOCATION:
|
|
card->DOPlocation = value->rValue * UM_TO_CM;
|
|
card->DOPlocationGiven = TRUE;
|
|
break;
|
|
case DOP_CHAR_LEN:
|
|
card->DOPcharLen = value->rValue * UM_TO_CM;
|
|
card->DOPcharLenGiven = TRUE;
|
|
break;
|
|
case DOP_RATIO_LAT:
|
|
card->DOPratioLat = value->rValue;
|
|
card->DOPratioLatGiven = TRUE;
|
|
break;
|
|
default:
|
|
return(E_BADPARM);
|
|
break;
|
|
}
|
|
return(OK);
|
|
}
|